travis-yaml 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +1 -0
- data/.rspec +3 -0
- data/.travis.yml +14 -0
- data/Gemfile +9 -0
- data/Gemfile.lock +73 -0
- data/LICENSE +22 -0
- data/README.md +232 -0
- data/Rakefile +3 -0
- data/SPEC.md +1018 -0
- data/bench/parser_bench.rb +54 -0
- data/config.ru +2 -0
- data/lib/travis/yaml.rb +43 -0
- data/lib/travis/yaml/matrix.rb +65 -0
- data/lib/travis/yaml/nodes.rb +40 -0
- data/lib/travis/yaml/nodes/branches.rb +12 -0
- data/lib/travis/yaml/nodes/bundler_args.rb +6 -0
- data/lib/travis/yaml/nodes/cache.rb +29 -0
- data/lib/travis/yaml/nodes/compiler.rb +7 -0
- data/lib/travis/yaml/nodes/compiler_entry.rb +9 -0
- data/lib/travis/yaml/nodes/deploy.rb +7 -0
- data/lib/travis/yaml/nodes/deploy_conditions.rb +12 -0
- data/lib/travis/yaml/nodes/deploy_entry.rb +10 -0
- data/lib/travis/yaml/nodes/env.rb +36 -0
- data/lib/travis/yaml/nodes/fixed_value.rb +60 -0
- data/lib/travis/yaml/nodes/git.rb +9 -0
- data/lib/travis/yaml/nodes/jdk.rb +11 -0
- data/lib/travis/yaml/nodes/language.rb +18 -0
- data/lib/travis/yaml/nodes/language_specific.rb +45 -0
- data/lib/travis/yaml/nodes/mapping.rb +204 -0
- data/lib/travis/yaml/nodes/matrix.rb +36 -0
- data/lib/travis/yaml/nodes/node.rb +102 -0
- data/lib/travis/yaml/nodes/notifications.rb +77 -0
- data/lib/travis/yaml/nodes/open_mapping.rb +18 -0
- data/lib/travis/yaml/nodes/os.rb +21 -0
- data/lib/travis/yaml/nodes/os_entry.rb +19 -0
- data/lib/travis/yaml/nodes/root.rb +44 -0
- data/lib/travis/yaml/nodes/ruby.rb +11 -0
- data/lib/travis/yaml/nodes/scalar.rb +97 -0
- data/lib/travis/yaml/nodes/sequence.rb +84 -0
- data/lib/travis/yaml/nodes/stage.rb +6 -0
- data/lib/travis/yaml/nodes/version.rb +6 -0
- data/lib/travis/yaml/nodes/version_list.rb +7 -0
- data/lib/travis/yaml/nodes/virtual_env.rb +7 -0
- data/lib/travis/yaml/parser.rb +31 -0
- data/lib/travis/yaml/parser/dummy.rb +13 -0
- data/lib/travis/yaml/parser/psych.rb +217 -0
- data/lib/travis/yaml/parser/ruby.rb +77 -0
- data/lib/travis/yaml/secure_string.rb +12 -0
- data/lib/travis/yaml/version.rb +5 -0
- data/play/lint.rb +8 -0
- data/play/spec.rb +183 -0
- data/play/weblint.rb +296 -0
- data/spec/nodes/.rb +0 -0
- data/spec/nodes/branches_spec.rb +45 -0
- data/spec/nodes/bundler_args_spec.rb +9 -0
- data/spec/nodes/cache_spec.rb +55 -0
- data/spec/nodes/compiler_spec.rb +14 -0
- data/spec/nodes/deploy_spec.rb +83 -0
- data/spec/nodes/git_spec.rb +55 -0
- data/spec/nodes/jdk_spec.rb +41 -0
- data/spec/nodes/language_spec.rb +79 -0
- data/spec/nodes/notifications_spec.rb +45 -0
- data/spec/nodes/os_spec.rb +28 -0
- data/spec/nodes/ruby_spec.rb +69 -0
- data/spec/nodes/stage_spec.rb +34 -0
- data/spec/nodes/virtual_env_spec.rb +9 -0
- data/spec/parser/dummy_spec.rb +7 -0
- data/spec/parser/ruby_spec.rb +41 -0
- data/spec/support.rb +3 -0
- data/spec/support/coverage.rb +11 -0
- data/spec/support/environment.rb +1 -0
- data/spec/yaml_spec.rb +26 -0
- data/travis-yaml.gemspec +24 -0
- metadata +207 -0
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'bundler/setup'
|
2
|
+
require 'benchmark'
|
3
|
+
require 'psych'
|
4
|
+
require 'safe_yaml/load'
|
5
|
+
require 'travis/yaml'
|
6
|
+
|
7
|
+
parsers = [Psych, SafeYAML, Travis::Yaml]
|
8
|
+
content = <<-YAML
|
9
|
+
# from rails/rails
|
10
|
+
script: 'ci/travis.rb'
|
11
|
+
before_install:
|
12
|
+
- travis_retry gem install bundler
|
13
|
+
- "rvm current | grep 'jruby' && export AR_JDBC=true || echo"
|
14
|
+
rvm:
|
15
|
+
- 1.9.3
|
16
|
+
- 2.0.0
|
17
|
+
- 2.1.1
|
18
|
+
- rbx-2
|
19
|
+
- jruby
|
20
|
+
env:
|
21
|
+
- "GEM=railties"
|
22
|
+
- "GEM=ap,am,amo,as,av"
|
23
|
+
- "GEM=ar:mysql"
|
24
|
+
- "GEM=ar:mysql2"
|
25
|
+
- "GEM=ar:sqlite3"
|
26
|
+
- "GEM=ar:postgresql"
|
27
|
+
matrix:
|
28
|
+
allow_failures:
|
29
|
+
- rvm: rbx-2
|
30
|
+
- rvm: jruby
|
31
|
+
fast_finish: true
|
32
|
+
notifications:
|
33
|
+
email: false
|
34
|
+
irc:
|
35
|
+
on_success: change
|
36
|
+
on_failure: always
|
37
|
+
channels:
|
38
|
+
- "irc.freenode.org#rails-contrib"
|
39
|
+
campfire:
|
40
|
+
on_success: change
|
41
|
+
on_failure: always
|
42
|
+
bundler_args: --path vendor/bundle --without test
|
43
|
+
services:
|
44
|
+
- memcached
|
45
|
+
YAML
|
46
|
+
|
47
|
+
GC.disable
|
48
|
+
Benchmark.bmbm do |x|
|
49
|
+
parsers.each do |parser|
|
50
|
+
x.report(parser.inspect) do
|
51
|
+
500.times { parser.load(content) }
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
data/config.ru
ADDED
data/lib/travis/yaml.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
module Travis
|
2
|
+
module Yaml
|
3
|
+
Error ||= Class.new(StandardError)
|
4
|
+
ParseError ||= Class.new(Error)
|
5
|
+
|
6
|
+
require 'travis/yaml/secure_string'
|
7
|
+
require 'travis/yaml/nodes'
|
8
|
+
require 'travis/yaml/matrix'
|
9
|
+
require 'travis/yaml/parser'
|
10
|
+
|
11
|
+
extend self
|
12
|
+
|
13
|
+
def parse(value)
|
14
|
+
Parser.parse(value)
|
15
|
+
end
|
16
|
+
|
17
|
+
alias_method :load, :parse
|
18
|
+
|
19
|
+
def parse!(value, file_name = '.travis.yml')
|
20
|
+
result = parse(value)
|
21
|
+
result.nested_warnings.each do |key, message|
|
22
|
+
warn key.empty? ? "#{file_name}: #{message}" :
|
23
|
+
"#{file_name}: #{key.join(?.)} section - #{message}"
|
24
|
+
end
|
25
|
+
result
|
26
|
+
end
|
27
|
+
|
28
|
+
def new
|
29
|
+
root = Nodes::Root.new
|
30
|
+
yield root if block_given?
|
31
|
+
root.deep_verify
|
32
|
+
root
|
33
|
+
end
|
34
|
+
|
35
|
+
def matrix(value)
|
36
|
+
Matrix.new parse(value)
|
37
|
+
end
|
38
|
+
|
39
|
+
def matrix!(value, file_name = '.travis.yml')
|
40
|
+
Matrix.new parse!(value, file_name)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'delegate'
|
2
|
+
|
3
|
+
module Travis::Yaml
|
4
|
+
class Matrix < DelegateClass(Array)
|
5
|
+
EXPAND_KEYS = [
|
6
|
+
:compiler, :gemfile, :ghc, :go, :jdk, :lein, :node_js, :otp_release,
|
7
|
+
:perl, :php, :python, :ruby, :scala, :xcode_scheme, :xcode_sdk, :os
|
8
|
+
]
|
9
|
+
|
10
|
+
KEYS = EXPAND_KEYS + [:env]
|
11
|
+
|
12
|
+
class Entry < DelegateClass(Nodes::Root)
|
13
|
+
attr_reader :env, :matrix_attributes
|
14
|
+
|
15
|
+
def initialize(root, matrix_attributes)
|
16
|
+
super(root)
|
17
|
+
|
18
|
+
@matrix_attributes = matrix_attributes
|
19
|
+
@env = Nodes::Env.new(self)
|
20
|
+
inherited_env = root.env.global if root.env
|
21
|
+
@env.global = [matrix_attributes[:env], *inherited_env].compact
|
22
|
+
end
|
23
|
+
|
24
|
+
EXPAND_KEYS.each do |key|
|
25
|
+
define_method(key) { @matrix_attributes.fetch(key, super()) }
|
26
|
+
end
|
27
|
+
|
28
|
+
def inspect
|
29
|
+
"#<#{self.class}: #{matrix_attributes}>"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
attr_reader :root
|
34
|
+
|
35
|
+
def initialize(root)
|
36
|
+
@root = root
|
37
|
+
super(entries)
|
38
|
+
end
|
39
|
+
|
40
|
+
def axes
|
41
|
+
@axes ||= KEYS.select do |key|
|
42
|
+
next true if values_for(key) and values_for(key).size > 1
|
43
|
+
root.matrix.include.any? { |i| i[key] } if root.matrix and root.matrix.include
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def entries
|
48
|
+
@entries ||= begin
|
49
|
+
first, *rest = axes.map { |k| values_for(k) || [nil] }
|
50
|
+
entries = Array(first).product(*rest).map { |list| Hash[axes.zip(list)] }
|
51
|
+
if m = root.matrix
|
52
|
+
entries.delete_if { |e| m.exclude.any? { |p| p.all? { |k,v| e[k.to_sym] == v } } } if m.exclude
|
53
|
+
m.include.each { |i| entries << Hash[axes.map { |k| [k, i[k]] }] } if m.include
|
54
|
+
end
|
55
|
+
entries.map! { |attributes| Entry.new(root, attributes) }
|
56
|
+
entries.any? ? entries : [root]
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def values_for(key)
|
61
|
+
return root[key] unless key == :env
|
62
|
+
root.env.matrix if root.env
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Travis::Yaml
|
2
|
+
module Nodes
|
3
|
+
def self.[](key)
|
4
|
+
return key if key.respond_to? :new
|
5
|
+
name = constants.detect { |c| c.downcase == key }
|
6
|
+
raise ArgumentError, "unknown node type %p" % key unless name
|
7
|
+
const_get(name)
|
8
|
+
end
|
9
|
+
|
10
|
+
require 'travis/yaml/nodes/node'
|
11
|
+
require 'travis/yaml/nodes/scalar'
|
12
|
+
require 'travis/yaml/nodes/fixed_value'
|
13
|
+
require 'travis/yaml/nodes/sequence'
|
14
|
+
require 'travis/yaml/nodes/mapping'
|
15
|
+
require 'travis/yaml/nodes/open_mapping'
|
16
|
+
require 'travis/yaml/nodes/language_specific'
|
17
|
+
require 'travis/yaml/nodes/version'
|
18
|
+
require 'travis/yaml/nodes/version_list'
|
19
|
+
require 'travis/yaml/nodes/git'
|
20
|
+
require 'travis/yaml/nodes/bundler_args'
|
21
|
+
require 'travis/yaml/nodes/stage'
|
22
|
+
require 'travis/yaml/nodes/deploy_conditions'
|
23
|
+
require 'travis/yaml/nodes/deploy_entry'
|
24
|
+
require 'travis/yaml/nodes/deploy'
|
25
|
+
require 'travis/yaml/nodes/language'
|
26
|
+
require 'travis/yaml/nodes/compiler_entry'
|
27
|
+
require 'travis/yaml/nodes/compiler'
|
28
|
+
require 'travis/yaml/nodes/os_entry'
|
29
|
+
require 'travis/yaml/nodes/os'
|
30
|
+
require 'travis/yaml/nodes/virtual_env'
|
31
|
+
require 'travis/yaml/nodes/ruby'
|
32
|
+
require 'travis/yaml/nodes/jdk'
|
33
|
+
require 'travis/yaml/nodes/env'
|
34
|
+
require 'travis/yaml/nodes/matrix'
|
35
|
+
require 'travis/yaml/nodes/notifications'
|
36
|
+
require 'travis/yaml/nodes/branches'
|
37
|
+
require 'travis/yaml/nodes/cache'
|
38
|
+
require 'travis/yaml/nodes/root'
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Travis::Yaml
|
2
|
+
module Nodes
|
3
|
+
class Cache < Mapping
|
4
|
+
map :apt, :bundler, to: Scalar[:bool]
|
5
|
+
map :directories, to: Sequence
|
6
|
+
|
7
|
+
def visit_scalar(visitor, type, value, implicit = true)
|
8
|
+
case type
|
9
|
+
when :bool
|
10
|
+
visit_key_value(visitor, :bundler, value)
|
11
|
+
visit_key_value(visitor, :apt, value)
|
12
|
+
when :str
|
13
|
+
key = visitor.generate_key(self, value)
|
14
|
+
self[key] = true
|
15
|
+
else
|
16
|
+
super
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def visit_sequence(visitor, value)
|
21
|
+
visitor.apply_sequence(self, value)
|
22
|
+
end
|
23
|
+
|
24
|
+
def visit_child(visitor, value)
|
25
|
+
visit_scalar(visitor, :str, value)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Travis::Yaml
|
2
|
+
module Nodes
|
3
|
+
class DeployConditions < Mapping
|
4
|
+
include LanguageSpecific
|
5
|
+
map :jdk, :node, :perl, :php, :python, :ruby, :scala, :node, to: Version
|
6
|
+
map :rvm, to: :ruby
|
7
|
+
map :repo, :branch, :condition, to: Scalar[:str]
|
8
|
+
map :all_branches, :tags, to: Scalar[:bool]
|
9
|
+
prefix_scalar :branch
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'shellwords'
|
2
|
+
|
3
|
+
module Travis::Yaml
|
4
|
+
module Nodes
|
5
|
+
class Env < Mapping
|
6
|
+
class Variables < Scalar
|
7
|
+
cast :str, :secure
|
8
|
+
|
9
|
+
def visit_mapping(visitor, value)
|
10
|
+
self.value = ""
|
11
|
+
visitor.apply_mapping(self, value)
|
12
|
+
end
|
13
|
+
|
14
|
+
def visit_mapping(visitor, key, value)
|
15
|
+
key = visitor.generate_key(self, key)
|
16
|
+
node = Scalar.new
|
17
|
+
visitor.accept(node, value)
|
18
|
+
|
19
|
+
if node.errors?
|
20
|
+
warning "dropping %p: %s", key, value.errors.join(', ')
|
21
|
+
else
|
22
|
+
self.value << " " unless self.value.empty?
|
23
|
+
self.value << "#{key}=#{Shellwords.escape(value.value)}"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class List < Sequence
|
29
|
+
type Variables
|
30
|
+
end
|
31
|
+
|
32
|
+
map :global, :matrix, to: List
|
33
|
+
auto_prefix :matrix
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Travis::Yaml
|
2
|
+
module Nodes
|
3
|
+
class FixedValue < Scalar
|
4
|
+
def self.[](*values)
|
5
|
+
Class.new(self) { value(*values) }
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.default(value = nil)
|
9
|
+
value &&= value.to_s
|
10
|
+
super(value)
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.ignore_case?
|
14
|
+
@ignore_case ||= false
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.ignore_case
|
18
|
+
@ignore_case = true
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.valid_values
|
22
|
+
@valid_values ||= superclass.respond_to?(:valid_values) ? superclass.valid_values.dup : []
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.aliases
|
26
|
+
@aliases ||= superclass.respond_to?(:aliases) ? superclass.aliases.dup : {}
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.map_value(value)
|
30
|
+
value = value.to_s
|
31
|
+
if ignore_case?
|
32
|
+
all_values = valid_values + aliases.keys
|
33
|
+
value = all_values.detect { |supported| supported.downcase == value.downcase }
|
34
|
+
end
|
35
|
+
value &&= aliases.fetch(value, value)
|
36
|
+
value if valid_values.include? value
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.value(*list)
|
40
|
+
list.each do |value|
|
41
|
+
if value.respond_to? :each_pair
|
42
|
+
value.each_pair { |aka, proper| aliases[aka.to_s] = proper.to_s }
|
43
|
+
else
|
44
|
+
valid_values << value.to_s
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def value=(value)
|
50
|
+
if mapped = self.class.map_value(value)
|
51
|
+
super(mapped)
|
52
|
+
elsif self.value
|
53
|
+
warning "illegal value %p, defaulting to %p", value, self.value
|
54
|
+
elsif value
|
55
|
+
error "illegal value %p", value
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module Travis::Yaml
|
2
|
+
module Nodes
|
3
|
+
class JDK < VersionList
|
4
|
+
def verify_language(language)
|
5
|
+
return unless language == 'ruby'
|
6
|
+
return if @parent.ruby and @parent.ruby.jruby?
|
7
|
+
error 'specified "jdk", but "ruby" does not include "jruby"'
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Travis::Yaml
|
2
|
+
module Nodes
|
3
|
+
class Language < FixedValue
|
4
|
+
ignore_case
|
5
|
+
default :ruby
|
6
|
+
|
7
|
+
value :c, :cpp, :clojure, :erlang, :go, :groovy, :haskell, :java, :node_js,
|
8
|
+
:"objective-c", :ruby, :python, :perl, :php, :scala, :android
|
9
|
+
value jvm: :java, javascript: :node_js, node: :node_js, nodejs: :node_js, golang: :go,
|
10
|
+
objective_c: :"objective-c", obj_c: :"objective-c", objc: :"objective-c"
|
11
|
+
value "c++" => :cpp, "node.js" => :node_js, "obj-c" => :"objective-c"
|
12
|
+
|
13
|
+
def default_os
|
14
|
+
value == "objective-c" ? :osx : OSEntry.default
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|