travis-yaml 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|