travis-yaml 0.1.0 → 0.2.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.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +3 -8
  3. data/Gemfile +3 -6
  4. data/Gemfile.lock +20 -50
  5. data/README.md +97 -2
  6. data/SPEC.md +116 -33
  7. data/lib/travis/yaml.rb +6 -3
  8. data/lib/travis/yaml/matrix.rb +12 -17
  9. data/lib/travis/yaml/nodes.rb +4 -0
  10. data/lib/travis/yaml/nodes/addons.rb +44 -0
  11. data/lib/travis/yaml/nodes/android.rb +7 -0
  12. data/lib/travis/yaml/nodes/cache.rb +5 -3
  13. data/lib/travis/yaml/nodes/deploy_conditions.rb +2 -1
  14. data/lib/travis/yaml/nodes/deploy_entry.rb +46 -0
  15. data/lib/travis/yaml/nodes/dist.rb +6 -0
  16. data/lib/travis/yaml/nodes/env.rb +1 -1
  17. data/lib/travis/yaml/nodes/group.rb +6 -0
  18. data/lib/travis/yaml/nodes/language.rb +3 -2
  19. data/lib/travis/yaml/nodes/language_specific.rb +2 -2
  20. data/lib/travis/yaml/nodes/mapping.rb +39 -10
  21. data/lib/travis/yaml/nodes/node.rb +58 -1
  22. data/lib/travis/yaml/nodes/notifications.rb +10 -6
  23. data/lib/travis/yaml/nodes/open_mapping.rb +1 -1
  24. data/lib/travis/yaml/nodes/os.rb +1 -1
  25. data/lib/travis/yaml/nodes/os_entry.rb +7 -5
  26. data/lib/travis/yaml/nodes/root.rb +28 -4
  27. data/lib/travis/yaml/nodes/scalar.rb +16 -1
  28. data/lib/travis/yaml/nodes/sequence.rb +38 -0
  29. data/lib/travis/yaml/nodes/version.rb +13 -0
  30. data/lib/travis/yaml/nodes/version_list.rb +4 -0
  31. data/lib/travis/yaml/parser/psych.rb +11 -5
  32. data/lib/travis/yaml/secure_string.rb +35 -2
  33. data/lib/travis/yaml/serializer.rb +17 -0
  34. data/lib/travis/yaml/serializer/generic.rb +114 -0
  35. data/lib/travis/yaml/serializer/json.rb +72 -0
  36. data/lib/travis/yaml/serializer/legacy.rb +32 -0
  37. data/lib/travis/yaml/serializer/ruby.rb +13 -0
  38. data/lib/travis/yaml/serializer/yaml.rb +41 -0
  39. data/lib/travis/yaml/version.rb +1 -1
  40. data/play/spec.rb +24 -17
  41. data/spec/matrix_spec.rb +57 -0
  42. data/spec/nodes/addons_spec.rb +63 -0
  43. data/spec/nodes/cache_spec.rb +4 -4
  44. data/spec/nodes/deploy_spec.rb +12 -0
  45. data/spec/nodes/dist_spec.rb +11 -0
  46. data/spec/nodes/env_spec.rb +48 -0
  47. data/spec/nodes/git_spec.rb +1 -1
  48. data/spec/nodes/group_spec.rb +11 -0
  49. data/spec/nodes/node_js_spec.rb +14 -0
  50. data/spec/nodes/notifications_spec.rb +7 -0
  51. data/spec/nodes/os_spec.rb +13 -0
  52. data/spec/nodes/root_spec.rb +36 -0
  53. data/spec/nodes/secure_spec.rb +145 -0
  54. data/spec/parser/psych_spec.rb +6 -0
  55. data/spec/parser/ruby_spec.rb +1 -1
  56. data/spec/serializer/json_spec.rb +30 -0
  57. data/spec/serializer/legacy_spec.rb +47 -0
  58. data/spec/serializer/ruby_spec.rb +21 -0
  59. data/spec/serializer/yaml_spec.rb +47 -0
  60. data/spec/support/coverage.rb +9 -9
  61. data/spec/yaml_spec.rb +23 -0
  62. data/travis-yaml.gemspec +2 -3
  63. metadata +42 -22
  64. data/config.ru +0 -2
  65. data/play/weblint.rb +0 -296
@@ -0,0 +1,32 @@
1
+ module Travis::Yaml
2
+ module Serializer
3
+ class Legacy < Ruby
4
+ def serialize_root(node)
5
+ return serialize_error(node) if node.errors?
6
+ super.merge(serialize_warnings(node))
7
+ end
8
+
9
+ def serialize_error(node)
10
+ {
11
+ serialize_key('.result') => 'parse_error',
12
+ serialize_key('.result_message') => node.errors.join("\n")
13
+ }
14
+ end
15
+
16
+ def serialize_warnings(node)
17
+ {
18
+ serialize_key('.result') => 'configured',
19
+ serialize_key('.result_warnings') => node.nested_warnings
20
+ }
21
+ end
22
+
23
+ def serialize_encrypted(value)
24
+ { serialize_key('secure') => value.encrypted_string }
25
+ end
26
+
27
+ def serialize_decrypted(value)
28
+ value.decrypted_string
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,13 @@
1
+ module Travis::Yaml
2
+ module Serializer
3
+ class Ruby < Generic
4
+ def serialize_value(value)
5
+ value
6
+ end
7
+
8
+ def serialize_mapping(node)
9
+ Hash[super]
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,41 @@
1
+ module Travis::Yaml
2
+ module Serializer
3
+ class Yaml < Ruby
4
+ PSYCH_OPTIONS = [ :indentation, :line_width, :canonical ]
5
+
6
+ class Tagged
7
+ attr_accessor :tag, :value
8
+ def initialize(tag, value)
9
+ @tag, @value = tag, value
10
+ end
11
+
12
+ def encode_with(coder)
13
+ coder.represent_scalar(tag, value)
14
+ end
15
+ end
16
+
17
+ def self.serialize(node, options = nil)
18
+ psych_options = options.select { |key, _| PSYCH_OPTIONS.include? key } if options
19
+ ::Psych.dump(super, psych_options || {})
20
+ end
21
+
22
+ def avoid_tags?
23
+ !!options[:avoid_tags]
24
+ end
25
+
26
+ def serialize_encrypted(value)
27
+ value = value.encrypted_string
28
+ avoid_tags? ? { "secure" => value } : Tagged.new('!encrypted', value)
29
+ end
30
+
31
+ def serialize_decrypted(value)
32
+ value = value.decrypted_string
33
+ avoid_tags? ? value : Tagged.new('!decrypted', value)
34
+ end
35
+
36
+ def serialize_binary(value)
37
+ Tagged.new('!binary', [value].pack('m0'))
38
+ end
39
+ end
40
+ end
41
+ end
@@ -1,5 +1,5 @@
1
1
  module Travis
2
2
  module Yaml
3
- VERSION = '0.1.0'
3
+ VERSION = '0.2.0'
4
4
  end
5
5
  end
@@ -34,7 +34,7 @@ module Travis::Yaml
34
34
  description
35
35
  end
36
36
 
37
- def self.spec_format
37
+ def self.spec_format(*)
38
38
  end
39
39
 
40
40
  def self.spec(*prefix, **options)
@@ -45,7 +45,7 @@ module Travis::Yaml
45
45
  end
46
46
 
47
47
  class Scalar
48
- def self.spec_format(append = "")
48
+ def self.spec_format(append = "", *)
49
49
  formats = cast.any? ? cast : [default_type]
50
50
  formats.map { |f| TYPES[f] ? TYPES[f]+append : f.to_s }.join(', ').gsub(/, ([^,]+)$/, ' or \1')
51
51
  end
@@ -77,24 +77,24 @@ module Travis::Yaml
77
77
  end
78
78
 
79
79
  class Notifications::Notification
80
- def self.spec_notification_format
81
- "list of strings or encrypted strings"
82
- end
83
-
84
- def self.spec_format
85
- super + ", or #{spec_notification_format}, or boolean value"
86
- end
80
+ def self.spec_format_prefix(input, append = "")
81
+ super(input)
82
+ input << ", or boolean value#{append}"
83
+ end
87
84
  end
88
85
 
89
- class Notifications::Flowdoc
90
- def self.spec_notification_format
91
- "string, encrypted string"
92
- end
86
+ class Notifications::Flowdock
87
+ def self.spec_format_prefix(input, append = "")
88
+ input << ", or string#{append}, encrypted string#{append}, or boolean value#{append}"
89
+ end
93
90
  end
94
91
 
95
92
  class Sequence
96
- def self.spec_format
97
- "list of " << type.spec_format("s") << "; or a single " << type.spec_format if type.spec_format
93
+ def self.spec_format(append = "", children = true, *)
94
+ return unless type.spec_format
95
+ format = "list of " << type.spec_format("s")
96
+ format << "; or a single " << type.spec_format if children
97
+ format
98
98
  end
99
99
 
100
100
  def self.spec(*prefix, **options)
@@ -117,8 +117,15 @@ module Travis::Yaml
117
117
  end
118
118
 
119
119
  class Mapping
120
- def self.spec_format(append = "")
121
- "key value mapping#{append}"
120
+ def self.spec_format(append = "", *)
121
+ format = "key value mapping#{append}"
122
+ spec_format_prefix(format, append)
123
+ format
124
+ end
125
+
126
+ def self.spec_format_prefix(input, append = "")
127
+ input << ", or #{subnode_for(prefix_sequence).spec_format('s', prefix_sequence != prefix_scalar)}" if prefix_sequence
128
+ input << ", or #{subnode_for(prefix_scalar).spec_format(append)}" if prefix_scalar and prefix_scalar != prefix_sequence
122
129
  end
123
130
 
124
131
  def self.default_spec_description
@@ -0,0 +1,57 @@
1
+ describe Travis::Yaml::Matrix do
2
+ let(:matrix) { config.to_matrix }
3
+ let(:entries) { matrix.entries }
4
+ let(:matrix_attributes) { entries.first.matrix_attributes }
5
+
6
+ context 'no matrix' do
7
+ let(:config) { Travis::Yaml.load(language: "ruby") }
8
+ specify { expect(matrix.size) .to be == 1 }
9
+ specify { expect(entries.first.to_ruby) .to be == {"language"=>"ruby", "os"=>["linux"]} }
10
+ specify { expect(config.to_ruby) .to be == {"language"=>"ruby", "os"=>["linux"]} }
11
+ specify { expect(entries.first) .to be_a(Travis::Yaml::Matrix::Entry) }
12
+ specify { expect(matrix_attributes) .to be_empty }
13
+ specify { expect(matrix.axes) .to be_empty }
14
+ end
15
+
16
+ context 'simple matrix' do
17
+ let(:config) { Travis::Yaml.load(ruby: ["ruby", "jruby"]) }
18
+ specify { expect(matrix.size) .to be == 2 }
19
+ specify { expect(entries.first.to_ruby) .to be == {"language"=>"ruby", "os"=>["linux"], "ruby"=>"ruby"} }
20
+ specify { expect(config.to_ruby) .to be == {"language"=>"ruby", "os"=>["linux"], "ruby"=>["ruby", "jruby"]} }
21
+ specify { expect(entries.first) .to be_a(Travis::Yaml::Matrix::Entry) }
22
+ specify { expect(matrix_attributes) .to be == { ruby: "ruby"} }
23
+ specify { expect(matrix.axes) .to be == [:ruby] }
24
+ end
25
+
26
+ context 'two dimensional matrix' do
27
+ let(:config) { Travis::Yaml.load(ruby: ["ruby", "jruby"], os: ["linux", "osx"]) }
28
+ specify { expect(matrix.size) .to be == 4 }
29
+ specify { expect(entries.first.to_ruby) .to be == {"language"=>"ruby", "os"=>"linux", "ruby"=>"ruby"} }
30
+ specify { expect(config.to_ruby) .to be == {"language"=>"ruby", "os"=>["linux", "osx"], "ruby"=>["ruby", "jruby"]} }
31
+ specify { expect(entries.first) .to be_a(Travis::Yaml::Matrix::Entry) }
32
+ specify { expect(matrix_attributes) .to be == { ruby: "ruby", os: "linux" } }
33
+ specify { expect(matrix.axes) .to be == [:ruby, :os] }
34
+ end
35
+
36
+ context 'matrix env, no global env' do
37
+ let(:config) { Travis::Yaml.load(env: ['a', 'b']) }
38
+ specify { expect(matrix.size) .to be == 2 }
39
+ specify { expect(entries.first.to_ruby) .to be == {"env"=>{"global"=>["a"]}, "language"=>"ruby", "os"=>["linux"]} }
40
+ specify { expect(entries.last.to_ruby) .to be == {"env"=>{"global"=>["b"]}, "language"=>"ruby", "os"=>["linux"]} }
41
+ specify { expect(config.to_ruby) .to be == {"env"=>{"matrix"=>["a", "b"]}, "language"=>"ruby", "os"=>["linux"]} }
42
+ specify { expect(entries.first) .to be_a(Travis::Yaml::Matrix::Entry) }
43
+ specify { expect(matrix_attributes) .to be == { env: "a" } }
44
+ specify { expect(matrix.axes) .to be == [:env] }
45
+ end
46
+
47
+ context 'matrix env, global env' do
48
+ let(:config) { Travis::Yaml.load(env: { matrix: ['a', 'b'], global: ['x'] }) }
49
+ specify { expect(matrix.size) .to be == 2 }
50
+ specify { expect(entries.first.to_ruby) .to be == {"env"=>{"global"=>["x", "a"]}, "language"=>"ruby", "os"=>["linux"]} }
51
+ specify { expect(entries.last.to_ruby) .to be == {"env"=>{"global"=>["x", "b"]}, "language"=>"ruby", "os"=>["linux"]} }
52
+ specify { expect(config.to_ruby) .to be == {"env"=>{"matrix"=>["a", "b"], "global"=>["x"]}, "language"=>"ruby", "os"=>["linux"]} }
53
+ specify { expect(entries.first) .to be_a(Travis::Yaml::Matrix::Entry) }
54
+ specify { expect(matrix_attributes) .to be == { env: "a" } }
55
+ specify { expect(matrix.axes) .to be == [:env] }
56
+ end
57
+ end
@@ -0,0 +1,63 @@
1
+ describe Travis::Yaml::Nodes::Addons do
2
+ context 'from Ruby' do
3
+ def addons(input)
4
+ Travis::Yaml.parse!(language: 'ruby', addons: input).addons
5
+ end
6
+
7
+ context 'artifacts' do
8
+ let :config do
9
+ addons(artifacts: {
10
+ bucket: 'whatever',
11
+ branch: 'borken',
12
+ concurrency: 40,
13
+ debug: 1,
14
+ key: 'foo',
15
+ max_size: 1024 * 1024 * 10,
16
+ paths: '$(git ls-files -o | tr "\n" ":")',
17
+ secret: 'bar',
18
+ target_paths: 'somewhere/in/teh/clood',
19
+ log_format: 'special',
20
+ })
21
+ end
22
+
23
+ example { expect(config.artifacts.key).to be == 'foo' }
24
+ example { expect(config.artifacts.secret).to be == 'bar' }
25
+ example { expect(config.artifacts.bucket).to be == 'whatever' }
26
+ end
27
+
28
+ context 'code_climate' do
29
+ example { expect(addons(code_climate: true).code_climate).to be == {} }
30
+ example { expect(addons(code_climate: { repo_token: "foo" }).code_climate.repo_token).to be == "foo" }
31
+ end
32
+
33
+ context 'coverity_scan' do
34
+ example do
35
+ config = addons(coverity_scan: { project: { name: :foo } })
36
+ expect(config.coverity_scan.project.name).to be == "foo"
37
+ end
38
+ end
39
+
40
+ context 'firefox' do
41
+ example { expect(addons(firefox: '15').firefox).to be == '15' }
42
+ end
43
+
44
+ context 'hosts' do
45
+ example { expect(addons(hosts: 'foo.dev').hosts).to be == ['foo.dev'] }
46
+ example { expect(addons(hosts: ['foo.dev', 'bar.dev']).hosts).to be == ['foo.dev', 'bar.dev'] }
47
+ end
48
+
49
+ context 'postgresql' do
50
+ example { expect(addons(postgresql: '9.1').postgresql).to be == '9.1' }
51
+ end
52
+
53
+ context 'sauce_connect' do
54
+ example { expect(addons(sauce_connect: true).sauce_connect).to be == {} }
55
+ example { expect(addons(sauce_connect: { username: "foo" }).sauce_connect.username).to be == "foo" }
56
+ end
57
+
58
+ context 'ssh_known_hosts' do
59
+ example { expect(addons(ssh_known_hosts: 'git.example.org').ssh_known_hosts).to be == ['git.example.org'] }
60
+ example { expect(addons(ssh_known_hosts: ['git.example.org', 'git.example.com']).ssh_known_hosts).to be == ['git.example.org', 'git.example.com'] }
61
+ end
62
+ end
63
+ end
@@ -2,12 +2,12 @@ describe Travis::Yaml::Nodes::Cache do
2
2
  context 'from Ruby' do
3
3
  specify 'with true' do
4
4
  config = Travis::Yaml.parse(cache: true)
5
- expect(config.cache).to be == { 'apt' => true, 'bundler' => true }
5
+ expect(config.cache).to be == { 'apt' => true, 'bundler' => true, 'cocoapods' => true }
6
6
  end
7
7
 
8
8
  specify 'with false' do
9
9
  config = Travis::Yaml.parse(cache: false)
10
- expect(config.cache).to be == { 'apt' => false, 'bundler' => false }
10
+ expect(config.cache).to be == { 'apt' => false, 'bundler' => false, 'cocoapods' => false }
11
11
  end
12
12
 
13
13
  specify 'with string' do
@@ -29,12 +29,12 @@ describe Travis::Yaml::Nodes::Cache do
29
29
  context 'from YAML' do
30
30
  specify 'with true' do
31
31
  config = Travis::Yaml.parse('cache: on')
32
- expect(config.cache).to be == { 'apt' => true, 'bundler' => true }
32
+ expect(config.cache).to be == { 'apt' => true, 'bundler' => true, 'cocoapods' => true }
33
33
  end
34
34
 
35
35
  specify 'with false' do
36
36
  config = Travis::Yaml.parse('cache: off')
37
- expect(config.cache).to be == { 'apt' => false, 'bundler' => false }
37
+ expect(config.cache).to be == { 'apt' => false, 'bundler' => false, 'cocoapods' => false }
38
38
  end
39
39
 
40
40
  specify 'with string' do
@@ -46,6 +46,18 @@ describe Travis::Yaml::Nodes::Deploy do
46
46
  config = Travis::Yaml.parse(deploy: { provider: :heroku, on: { rvm: "2.0.0", repo: 'foo/bar', tags: true } })
47
47
  expect(config.deploy.first.on).to be == { 'ruby' => '2.0.0', 'repo' => 'foo/bar', 'tags' => true }
48
48
  end
49
+
50
+ specify 'with branch specific settings' do
51
+ config = Travis::Yaml.parse(deploy: { provider: :heroku, foo: { master: :bar, staging: :baz } })
52
+ expect(config.deploy.first['foo']) .to be == { 'master' => 'bar', 'staging' => 'baz' }
53
+ expect(config.deploy.nested_warnings) .to be_empty
54
+ end
55
+
56
+ specify 'branches in settings that are not in the condition' do
57
+ config = Travis::Yaml.parse(deploy: { provider: :heroku, foo: { master: :bar, staging: :baz }, on: :master })
58
+ expect(config.deploy.first['foo']) .to be == { 'master' => 'bar' }
59
+ expect(config.deploy.nested_warnings) .to include([['foo'], 'branch "staging" not permitted by deploy condition, dropping'])
60
+ end
49
61
  end
50
62
 
51
63
  describe 'from yaml' do
@@ -0,0 +1,11 @@
1
+ describe Travis::Yaml::Nodes::Dist do
2
+ it 'adds warnings about feature' do
3
+ expect(Travis::Yaml.parse(language: 'ruby', dist: 'precise').warnings).
4
+ to include('your repository must be feature flagged for the "dist" setting to be used')
5
+ end
6
+
7
+ specify 'set dist value' do
8
+ config = Travis::Yaml.parse(dist: 'trusty')
9
+ expect(config.dist).to eq 'trusty'
10
+ end
11
+ end
@@ -0,0 +1,48 @@
1
+ describe Travis::Yaml::Nodes::Deploy do
2
+ context 'from Ruby' do
3
+ specify 'list of values' do
4
+ config = Travis::Yaml.parse <<-YAML.gsub(/^ {8}/, '')
5
+ ---
6
+ language: ruby
7
+ env:
8
+ - "FOO=BAR"
9
+ - "FOX=BAZ"
10
+ YAML
11
+
12
+ expect(config.nested_warnings).to be_empty
13
+ expect(config.env.matrix.length).to be == 2
14
+ end
15
+
16
+ specify 'global with secure' do
17
+ config = Travis::Yaml.parse <<-YAML.gsub(/^ {8}/, '')
18
+ ---
19
+ language: ruby
20
+ env:
21
+ global:
22
+ - secure: "..."
23
+ - secure: "..."
24
+ YAML
25
+
26
+ expect(config.nested_warnings).to be_empty
27
+ expect(config.env.global.length).to be == 2
28
+ end
29
+
30
+ specify 'global and matrix' do
31
+ config = Travis::Yaml.parse <<-YAML.gsub(/^ {8}/, '')
32
+ ---
33
+ language: ruby
34
+ env:
35
+ matrix:
36
+ - "FOO=BAR"
37
+ - "FOX=BAZ"
38
+ global:
39
+ - secure: "..."
40
+ - secure: "..."
41
+ YAML
42
+
43
+ expect(config.nested_warnings).to be_empty
44
+ expect(config.env.global.length).to be == 2
45
+ expect(config.env.matrix.length).to be == 2
46
+ end
47
+ end
48
+ end
@@ -48,7 +48,7 @@ describe Travis::Yaml::Nodes::Git do
48
48
  expect(Travis::Yaml.parse('git: { depth: !str foo }').nested_warnings).to \
49
49
  include([['git'], 'dropping "depth" section: "str" not supported, dropping "foo"'])
50
50
  expect(Travis::Yaml.parse('git: { depth: foo }').nested_warnings).to \
51
- include([['git'], 'dropping "depth" section: failed to parse "int" - invalid value for Integer(): "foo"'])
51
+ include([['git'], 'dropping "depth" section: failed to parse "int" - invalid value for Integer: "foo"'])
52
52
  end
53
53
  end
54
54
  end
@@ -0,0 +1,11 @@
1
+ describe Travis::Yaml::Nodes::Group do
2
+ it 'adds warnings about feature' do
3
+ expect(Travis::Yaml.parse(group: 'dev').warnings).
4
+ to include('your repository must be feature flagged for the "group" setting to be used')
5
+ end
6
+
7
+ specify 'set group value' do
8
+ config = Travis::Yaml.parse(group: 'update')
9
+ expect(config.group).to eq 'update'
10
+ end
11
+ end
@@ -0,0 +1,14 @@
1
+ describe Travis::Yaml do
2
+ context 'from ruby' do
3
+ specify 'valid versions' do
4
+ config = Travis::Yaml.parse(node_js: ['0.10', '0.8.0'], language: 'node.js')
5
+ expect(config.node_js).to be == ['0.10', '0.8.0']
6
+ end
7
+
8
+ specify 'invalid versions' do
9
+ config = Travis::Yaml.parse(node_js: ['0.10.x', '0.8.0'], language: 'node.js')
10
+ expect(config.node_js).to be == ['0.8.0']
11
+ expect(config.nested_warnings).to include([['node_js'], 'value "0.10.x" is not a valid version'])
12
+ end
13
+ end
14
+ end
@@ -42,4 +42,11 @@ describe Travis::Yaml::Nodes::Notifications do
42
42
  expect(config.notifications.email).to be_enabled
43
43
  end
44
44
  end
45
+
46
+ context :flowdoc do
47
+ example "handles scalar value" do
48
+ config = Travis::Yaml.parse(notifications: { flowdock: "foo" })
49
+ expect(config.notifications.flowdock.api_token).to be == "foo"
50
+ end
51
+ end
45
52
  end