• Stars
    star
    113
  • Rank 310,115 (Top 7 %)
  • Language
    Ruby
  • License
    MIT License
  • Created about 8 years ago
  • Updated 3 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Travis CI build config processing

This is a replacement for, and rewrite of travis-yaml.

Travis CI build config processing

This library is used for parsing, normalizing, and validating Travis CI build configuration (.travis.yml).

It serves these main functions:

  • Defining and producing a specification for our build configuration format in the form of JSON Schema.
  • Merging actual build configuration parts (such as .travis.yml)
  • Applying the spec to a merged build configuration in order to normalize and validate it.
  • Expanding a build config to job matrix configs.
  • Generating reference documentation from the spec.

The specification (schema) produced by the library is being used for both normalizing and validating build configs, and for generating reference documentation. I.e. these two parts of the code base are clients to the schema.

Applying the specification to a build configuration produces structured messages on the levels info, warn, and error. Such messages include a message code (e.g. unknown_key, deprecated_key etc.) and arguments (e.g. the given key, value) so they can be translated to human readable messages by clients. These can be used in the UI, and links to the documentation, suggesting fixes.

For example:

yaml = 'rvm: 2.3'
config = Travis::Yml.load(yaml)

config.serialize
# {
#   language: 'ruby',
#   os: ['linux'],
#   rvm: ['2.3']
# }

config.msgs
# [
#   [:info, :language, :default, key: :language, default: 'ruby'],
#   [:info, :language, :default, key: :os, default: 'linux'],
# ]

config.msgs.map { |msg| Travis::Yml.msg(msg) }
# [
#   '[info] on root: missing :language, using the default: "ruby"',
#   '[info] on root: missing :os, using the default: "linux"',
# ]

YAML

The library uses a custom YAML parser based on Psych, using its safe YAML parsing features.

Diverging from the YAML specification this library does not:

  • convert the strings yes or on to the boolean true, or the strings no or off to the boolean false
  • convert YAML integers or floats to Ruby integers or floats
  • convert symbol keys to symbols

For the following reasons:

  • Deployment config uses the key on. This being converted to true as a hash key does not make sense for us.
  • Version numbers like 1.10 used to be truncated to 1.1 by the YAML parser, causing confusion, and requiring users to specify these as strings ("1.10") instead.
  • Keys need to be strings so they can carry additional meta information (such as the source name of the build config, and the line number for messages).

The parser uses the classes Key, Map, and Seq for representing Ruby strings that are hash keys, hashes, and arrays, in order to be able to carry additional meta information. This is then used while merging config parts, and normalizing and validating the resulting config.

Integers and floats are not converted by the YAML parser, but they are casted later by the build config normalization, so they can be casted only if the respective node wants an integer or float.

Types

Borrowing from YAML's terminology the library uses:

  • map for hashes (key value mappings)
  • seq for arrays (sequence)

It also uses the following scalar types:

  • str for strings
  • num for numbers
  • bool for booleans
  • secure for secure strings

Scalars can be enums, as defined by JSON Schema, i.e. they can have a number of known and allowed values. Examples for keys that hold enums are: language, os, dist etc.

A map can be strict or not strict. Maps are strict by default. A strict map disallows keys that are not known.

A secure resembles our build config format for encrypted key/value pairs. Secures also can be strict or not strict, and they are strict by default. A not strict secure would accept a plain string without producing a warning (e.g. on keys like username or email).

Build config specification

The spec is included to the repository as schema.json.

The spec is defined in Schema::Def, and can be produced by:

Travis::Yml.schema

Classes in Schema::Def use classes in Schema::Type to build a tree of nodes that define allowed keys, types, and various options in a readable and succinct way (using a DSL for describing the schema).

Nodes on this tree that match certain well-known patterns are then transformed according to these patterns using classes in Schema::Type::Form. E.g. a sequence of strings always also accepts a single string, which will then automatically be wrapped into a sequence during the config normalization process. Therefore the JSON Schema needs to accept both forms.

The resulting tree is then serialized by classes in Schema::Json to a large Hash which serves as a specification in the form of a JSON Schema.

A good starting point for exploring the schema definition is the root node.

Examples for various nodes on this specification can be found in the tests, e.g. for the git, heroku, or os nodes.

Most nodes can be sufficiently specified by mapping known keys (e.g. language) to types (str, bool, map, seq etc.) with certain options, such as:

  • values: known values on a scalar type
  • default: default value
  • required: the node has to have a value
  • edge: the node represents an experimental feature
  • only: the node is valid only if the given value matches the current language or os
  • except: the node is valid only if the given value does not match the current language or os
  • expand: the node represents a matrix key for matrix expansion

In order to keep the JSON payload reasonably small the library uses JSON Schema's mechanism for defining and referencing shared sub schemas. All nodes that have a registered definition class are exported as such a defined sub schema, and then referenced on the respective nodes that use them.

TBD: mention JSON Schema limitations, and how travis-yml interprets particular types (all, any) in a specific way that is not defined by JSON Schema.

Loading the spec

Before the tree representing the schema can be applied to an actual build configuration it will be turned into another object oriented representation optimized for this purpose, so non-parametrized methods can be memoized for better performance.

The method Travis::Yml.expand returns this object oriented tree, using classes in Doc::Schema.

Applying the spec to a build config

This representation of the schema can be applied to a build configuration by:

# given a YAML string
Travis::Yml.load(yaml)

# given a Ruby hash
Travis::Yml.apply(config)

Both methods also accept an optional options hash. Please see here for a list of known options.

When the schema is applied to a build configuration three things happen:

  • The config is turned into an object oriented representation as well by the way of calling Doc::Value.build. This method uses classes in Doc::Value in order to build a tree of nodes that maps to the given build config hash.

  • The config structure is normalized by the way of calling Doc::Change.apply. This method applies various strategies in order to attempt to fix potential problems with the given structure, such as typos, misplaced keys, wrong section types. In some cases it will store messages on the resulting tree. Change strategies are determined based on the type of the given node. Some strategies can be required by the schema for certain sections that need very specific normalizations, such as cache, env_vars, enable.

  • The resulting config is validated by the way of calling Doc::Validate.apply. This method applies various validations, and sets default values. It also stores (most of the) messages on the resulting tree. Sections also can require specific validations. The only section specific validation currently is template (which validates used var names in notification templates).

Examples of type specific change strategies:

  • downcase: downcase a string if required by the spec
  • keys: add required keys, and attempt to fix an unknown key by removing special chars and finding typos (uses a dictionary, as well levenshtein and similar simple strategies)
  • prefix: turn the given value into a hash with a prefix key (e.g. turning env: ["FOO=bar"] into env: { matrix: ["FOO=foo"] })
  • pick: pick the first value of a given sequence for a scalar node
  • value: de-alias fixed node values, and try fixing typos in unknown values
  • wrap: wrap the given node into a sequence if required by the spec (e.g. os needs to result in an array)

Section specific change strategies:

  • env_vars: normalize env vars according to our build config format, parse env vars in order to validate them
  • enable: normalize enabled and disabled values, set enabled if missing (used by, for example, notifications)
  • inherit: inherit certain keys from the parent node if present (used by, for example, notifications)

Examples of the validations:

  • alert: add an alert level message if a node that expects a secure string accepts a plain string
  • default: use a default value as required by the spec if the node does not have a value
  • empty: warn about an empty section
  • format: unset the value and if the given value does not conform with the format as required by the spec
  • invalid_type: unset the value if the given value's type is not compatible with the spec's node type
  • required: add an error level message if the given map is missing a required key
  • template: drop the value if the given template string uses unknown variables
  • unknown_keys: add an error level message for an unknown key
  • unknown_value: add an error level message for an unknown value

Env vars given as strings will be parsed into hashes using the library sh_vars. Conditions will be parsed using the library travis-conditions.

Summary

There are three sets of classes that are used to build trees:

  • Travis::Yml::Spec builds the static, unexpanded Ruby hash that can be served as JSON.
  • Travis::Yml::Doc::Spec is used to build an object oriented tree of nodes from the expanded spec.
  • Travis::Yml::Doc::Value is used to build an object oriented tree of nodes that represent the given build config.

Only the last one, Doc::Value, is re-used at runtime, i.e. only for the given build configs we build new trees. The Doc::Spec representation is kept in memory, is static, and remains unchanged.

For each build config we then apply all relevant changes (Doc::Change) and all relevant validations (Doc::Validate) to each node.

Expanding a build matrix

A given build configuration can be expanded to job matrix configurations by:

Travis::Yml.matrix(config)

E.g. a build config like:

{
  language: 'ruby',
  ruby: ['2.2', '2.3'],
  env: ['FOO=foo', 'BAR=bar']
}

will be expanded to:

[
  { language: 'ruby', ruby: '2.2', env: { FOO: 'foo' } },
  { language: 'ruby', ruby: '2.2', env: { BAR: 'bar' } },
  { language: 'ruby', ruby: '2.3', env: { FOO: 'foo' } },
  { language: 'ruby', ruby: '2.3', env: { BAR: 'bar' } },
]

Web API

This gem also contains a web API for parsing and expanding a build config, which is used by travis-gatekeeper when processing a build request.

To start the server:

$ bundle exec rackup

The API contains three endpoints:

Home

$ curl -X GET /v1 | jq .
{
  "version": "v1"
}

Parse

The body of the request should be raw YAML. The response contains parsing messages and the validated and normalised config.

$ curl -X POST --data-binary @travis.yml /v1/parse | jq .
{
  "version": "v1",
  "messages": [
    {
      "level": "info",
      "key": "language",
      "code": "default",
      "args": {
        "key": "language",
        "default": "ruby"
      }
    }
  ],
  "full_messages": [
    "[info] on language: missing :language, defaulting to: ruby"
  ],
  "config": {
    "language": "ruby",
    "os": [
      "linux"
    ],
    "dist": "trusty",
    "sudo": false
  }
}

Expand

The body of the request should be the JSON config found in the response from /v1/parse. The response will contain the expanded matrix of jobs.

$ curl -X POST --data-binary @config.json /v1/expand | jq .
{
  "version": "v1",
  "matrix": [
    {
      "os": "linux",
      "language": "ruby",
      "dist": "trusty",
      "sudo": false
    }
  ]
}

More Repositories

1

travis-ci

Free continuous integration platform for GitHub projects.
8,353
star
2

travis.rb

Travis CI Client (CLI and Ruby library)
Ruby
1,583
star
3

dpl

Dpl (dee-pee-ell) is a deploy tool made for continuous deployment.
Ruby
1,284
star
4

gimme

Install go, yay!
Shell
690
star
5

travis-cookbooks

Chef cookbook monolithic repo 📖 💣
HTML
663
star
6

travis-build

.travis.yml => build.sh converter
Ruby
653
star
7

travis-web

The Ember web client for Travis CI
JavaScript
611
star
8

docs-travis-ci-com

The Travis CI Documentation
SCSS
570
star
9

travis-api

The Travis CI API
Ruby
295
star
10

worker

Worker runs your Travis CI jobs
Go
274
star
11

travis-core

[DEPRECATED] Models and classes shared by Travis CI api, hub and gatekeeper
Ruby
239
star
12

travis-yaml

parses, normalizes, validates and serializes your .travis.yml
Ruby
170
star
13

travis-ci.github.com

[DEPRECATED] The Travis CI blog & documentation website
CSS
154
star
14

travis-worker

[DEPRECATED] This project is deprecated in favor of travis-ci/worker
Ruby
141
star
15

terraform-config

Terraform bits and bytes
HCL
123
star
16

travis-lint

[DEPRECATED] Use travis-ci/travis-yml instead
Ruby
113
star
17

apt-package-safelist

Safelist of apt packages approved for build environments with restricted sudo
Shell
108
star
18

packer-templates

Templates for Packer!
Ruby
102
star
19

travis-watcher-macosx

[DEPRECATED] A Travis CI client for Mac OS X.
Objective-C
95
star
20

artifacts

Travis CI Artifacts Uploader
Go
87
star
21

travis-boxes

[DEPRECATED] Travis Boxes makes provisioning and configuring Virtual Box machines simple and easy.
Ruby
78
star
22

apt-source-safelist

Safelist of apt sources approved for build environments with restricted sudo
Ruby
78
star
23

gh

Layered GitHub API client
Ruby
68
star
24

travis-hub

Job State Central Command
Ruby
67
star
25

beta-features

The perfect place to leave feedback and comments on newly released Beta Features.
58
star
26

pudding

[DEPRECATED] It's a thing for managing instances!
Go
58
star
27

travis-logs

Processes log updates from the job runner (worker), and streams them to the web client, aggregates them, and archives to S3.
Ruby
56
star
28

travis-crowd

[DEPRECATED] Travis' love campaign (replaced by https://github.com/travis-ci/travis-love-campaign)
Ruby
49
star
29

osx-image-bootstrap

DEPRECATED Bootstrap scripts for Travis CI OS X VMs
Shell
47
star
30

build-stages-demo

Demos for Travis CI build stages
Ruby
46
star
31

travis-listener

Receives and queues service hook notifications from GitHub for processing.
Ruby
44
star
32

travis-rubies

my rubies, let me show you them
Shell
43
star
33

casher

CH CHING
Ruby
42
star
34

moustached-hubot

Moustached ChatOps for your hubot.
CoffeeScript
42
star
35

kubernetes-config

Travis services running on Kubernetes!
Shell
38
star
36

travis-tasks

The Sidekiq based Travis background job processor.
Ruby
37
star
37

php-src-builder

Builds php/php-src with php-build and uploads artifacts to S3
Roff
31
star
38

travis-support

Support classes and extensions used in travis-ci
Ruby
30
star
39

travis-scheduler

Queues jobs to be run by the various workers
Ruby
28
star
40

travis-cli-gh

[DEPRECATED] Travis CLI plugin to interact with GitHub API
Ruby
24
star
41

travis-sso

Implements Travis CI Single Sign-On as a Rack middleware.
Ruby
22
star
42

travis-artifacts

[DEPRECATED] Upload artifacts after running your tests to S3 (Unmaintained. See https://github.com/travis-ci/artifacts)
Ruby
21
star
43

docker-sinatra

[DEMO] Sample project for running a sinatra application on Docker from within a Travis build
Ruby
21
star
44

sso

SSO in go, implemented as an HTTP proxy.
Go
21
star
45

travis-assets

[DEPRECATED] We are using a CDN now
JavaScript
21
star
46

travis-conditions

Boolean language for conditional builds, stages, jobs
Ruby
20
star
47

actions

The best of GitHub Actions!
JavaScript
19
star
48

travis-foundation

Travis Foundation website.
HTML
19
star
49

gcloud-cleanup

Clean That Cloud! ☁️ 🛀
Go
19
star
50

travis-ruby-client

Ruby client library for Travis CI API
Ruby
19
star
51

packer-templates-mac

Templates for building images for macOS for Travis with Packer!
Shell
17
star
52

travis-chat

[DEMO] example app demoing travis-sso usage
Ruby
15
star
53

jupiter-brain

Jupiter Brain manages servers
Go
14
star
54

cpython-builder

Clones and builds CPython
Shell
13
star
55

travis.js

[DEPRECATED]
CoffeeScript
12
star
56

travis-deploy

[DEPRECATED] Travis Deploy tool
Ruby
11
star
57

collectd-vsphere

vSphere metrics plugin for collectd
Go
11
star
58

travis-web-log

CoffeeScript
10
star
59

system-info

💁 Gathers and reports system information specific to the travis build environment.
Ruby
10
star
60

worker-operator

A Kubernetes operator for deploying worker
Go
10
star
61

enterprise-installation

Travis CI Enterprise Installation Instructions
10
star
62

job-board

have a job? need a job? no jobs? all the jobs!
Ruby
9
star
63

cloud-brain

It talks to the clouds
Go
9
star
64

travis-weblint

travis-lint meets teh Internet
Ruby
9
star
65

travis-images

[DEPRECATED] Used to created and manage Travis VMs IN THE CLOUD
Ruby
9
star
66

apt-whitelist-checker

Automation of https://github.com/travis-ci/apt-package-whitelist approval process
Shell
9
star
67

cyclist

AWS ASG lifecycle thing 🎉 🚴
Go
8
star
68

2fabot

Slack bot that sends reminders to people to enable two-factor authentication.
Go
8
star
69

travis-extension-chrome

[DEPRECATED] Chrome extension that displays build status in the toolbar
8
star
70

travis-cli-pr

[DEPRECATED] This plugin has been deprecated, please use the travis settings command and the GitHub plugin instead. https://github.com/travis-ci/travis-cli-gh
Ruby
8
star
71

unlimited-jce-policy-jdk7

It's JCE Unlimited Strength Jurisdiction Policy Files 7 in a gem!
Ruby
7
star
72

prompt_warn_env

Warn if sensitive env vars are present
Shell
7
star
73

travis-erlang-builder

📫
Shell
6
star
74

travis-become

Ruby
6
star
75

travis-config

How does one configure 💃
Ruby
6
star
76

travis-migrations

Skeleton app to allow migrations to be run for our infrastructures
Ruby
6
star
77

travis-nightly-builder

API + rake tasks to build "nightly" or on-demand stuff
JavaScript
6
star
78

encrypted-column

Go implementation of encrypted database column bits
Go
6
star
79

travis-cli-settings

[DEPRECATED] No longer in use.
Ruby
5
star
80

travis-styleguide

[DEPRECATED] ✨
CSS
5
star
81

hubot-pudding

Script for interacting with a pudding server
CoffeeScript
5
star
82

travis-redirect

Ruby
5
star
83

veewee-definitions

[DEPRECATED] Veewee definitions we use to build our base boxes
Shell
5
star
84

container-example

[DEMO] An example showing how to use Travis CIs container-based infrastructure
Protocol Buffer
5
star
85

webhook-signature-verifier

A small Sinatra app to verify the webhook payload signature
Ruby
4
star
86

travis-images-specs

[DEPRECATED] tests for Travis build images
Ruby
4
star
87

travis-sidekiqs

Async, baby!
Ruby
4
star
88

cat-party

[DEMO] CodeDeploy Demo
HTML
4
star
89

tfw

The Tiny Floating Whale of infrastructure at Travis CI ✨ 🐳
Shell
4
star
90

travis-caching

[DEPRECATED] A simple caching service with pluggable backends
Ruby
4
star
91

travis_migrate_to_apps

Migrate your GitHub organizations to use the Travis CI GitHub App integration
Ruby
4
star
92

macbot

Slack bot for managing vSphere and other Travis Mac infrastructure things
Go
4
star
93

build-email

[DEPRECATED] The up-to-date HTML for build emails is generated from this template: https://github.com/travis-ci/travis-tasks/blob/master/lib/travis/addons/email/mailer/views/build/finished_email.html.erb
4
star
94

openshift-travis-quickstart

[DEMO] A sample Rack application showing Travis CI and OpenShift integration
Ruby
4
star
95

travis-api-v3

Pulling out our V3 codebase to be a stand alone application.
Ruby
3
star
96

travis-packer-build

📦 🚧
Ruby
3
star
97

travis-logsearch

Pipeline to dump job execution logs into elasticsearch!
Ruby
3
star
98

apt-gpg-keys

List of keys installed by travis-build at run time
3
star
99

build-env-linux

[WIP] New and improved Travis build environments for Linux
3
star
100

travis-encrypt

Encryption support
Ruby
3
star