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
@@ -7,17 +7,20 @@ module Travis
7
7
  require 'travis/yaml/nodes'
8
8
  require 'travis/yaml/matrix'
9
9
  require 'travis/yaml/parser'
10
+ require 'travis/yaml/serializer'
10
11
 
11
12
  extend self
12
13
 
13
14
  def parse(value)
14
- Parser.parse(value)
15
+ result = Parser.parse(value)
16
+ yield result if block_given?
17
+ result
15
18
  end
16
19
 
17
20
  alias_method :load, :parse
18
21
 
19
- def parse!(value, file_name = '.travis.yml')
20
- result = parse(value)
22
+ def parse!(value, file_name = '.travis.yml', &block)
23
+ result = parse(value, &block)
21
24
  result.nested_warnings.each do |key, message|
22
25
  warn key.empty? ? "#{file_name}: #{message}" :
23
26
  "#{file_name}: #{key.join(?.)} section - #{message}"
@@ -10,23 +10,18 @@ module Travis::Yaml
10
10
  KEYS = EXPAND_KEYS + [:env]
11
11
 
12
12
  class Entry < DelegateClass(Nodes::Root)
13
- attr_reader :env, :matrix_attributes
14
-
13
+ attr_reader :matrix_attributes
15
14
  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}>"
15
+ @matrix_attributes = matrix_attributes
16
+ normal_attributes = matrix_attributes.select { |key| key != :env }
17
+ generated_root = root.with_value(normal_attributes)
18
+ if matrix_attributes[:env]
19
+ generated_root.env.global = Travis::Yaml::Nodes::Env::List.new(generated_root.env)
20
+ generated_root.env.global.add_value! root.env.global if root.env.global
21
+ generated_root.env.global.add_value! matrix_attributes[:env]
22
+ generated_root.env.mapping.delete "matrix"
23
+ end
24
+ super(generated_root)
30
25
  end
31
26
  end
32
27
 
@@ -53,7 +48,7 @@ module Travis::Yaml
53
48
  m.include.each { |i| entries << Hash[axes.map { |k| [k, i[k]] }] } if m.include
54
49
  end
55
50
  entries.map! { |attributes| Entry.new(root, attributes) }
56
- entries.any? ? entries : [root]
51
+ entries.any? ? entries : [Entry.new(root, {})]
57
52
  end
58
53
  end
59
54
 
@@ -35,6 +35,10 @@ module Travis::Yaml
35
35
  require 'travis/yaml/nodes/notifications'
36
36
  require 'travis/yaml/nodes/branches'
37
37
  require 'travis/yaml/nodes/cache'
38
+ require 'travis/yaml/nodes/addons'
39
+ require 'travis/yaml/nodes/android'
40
+ require 'travis/yaml/nodes/dist'
41
+ require 'travis/yaml/nodes/group'
38
42
  require 'travis/yaml/nodes/root'
39
43
  end
40
44
  end
@@ -0,0 +1,44 @@
1
+ module Travis::Yaml
2
+ module Nodes
3
+ class Addons < Mapping
4
+ class Addon < Mapping
5
+ def self.[](*keys)
6
+ Class.new(self) { map(*keys, to: Scalar[:str, :secure])}
7
+ end
8
+
9
+ def visit_scalar(visitor, type, value, implicit = true)
10
+ return super unless type == :bool
11
+ end
12
+ end
13
+
14
+ class CoverityScan < Addon
15
+ class Project < Mapping
16
+ map :name, to: Scalar[:str, :secure], required: true
17
+ end
18
+
19
+ map :project, to: Project
20
+ map :build_script_url, :branch_pattern, :notification_email, :build_command,
21
+ :build_command_prepend, to: Scalar[:str, :secure]
22
+ end
23
+
24
+ class Artifacts < Addon
25
+ map :bucket, to: Scalar[:str, :secure], required: true
26
+ map :key, to: Scalar[:str, :secure], required: true
27
+ map :paths, to: Sequence
28
+ map :secret, to: Scalar[:str, :secure], required: true
29
+
30
+ map :branch, :log_format, :target_paths, to: Scalar[:str, :secure]
31
+ map :debug, :concurrency, :max_size, to: Scalar[:str, :int, :secure]
32
+ end
33
+
34
+ map :artifacts, to: Artifacts, drop_empty: false
35
+ map :code_climate, to: Addon[:repo_token], drop_empty: false
36
+ map :coverity_scan, to: CoverityScan
37
+ map :firefox, to: Version
38
+ map :hosts, to: Sequence
39
+ map :postgresql, to: Version
40
+ map :sauce_connect, to: Addon[:username, :access_key], drop_empty: false
41
+ map :ssh_known_hosts, to: Sequence
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,7 @@
1
+ module Travis::Yaml
2
+ module Nodes
3
+ class Android < Mapping
4
+ map :components, :licenses, to: VersionList
5
+ end
6
+ end
7
+ end
@@ -1,14 +1,16 @@
1
1
  module Travis::Yaml
2
2
  module Nodes
3
3
  class Cache < Mapping
4
- map :apt, :bundler, to: Scalar[:bool]
4
+ map :apt, :bundler, :cocoapods, to: Scalar[:bool]
5
+ map :edge, to: Scalar[:bool], experimental: true
5
6
  map :directories, to: Sequence
6
7
 
7
8
  def visit_scalar(visitor, type, value, implicit = true)
8
9
  case type
9
10
  when :bool
10
- visit_key_value(visitor, :bundler, value)
11
- visit_key_value(visitor, :apt, value)
11
+ visit_key_value(visitor, :bundler, value)
12
+ visit_key_value(visitor, :apt, value)
13
+ visit_key_value(visitor, :cocoapods, value)
12
14
  when :str
13
15
  key = visitor.generate_key(self, value)
14
16
  self[key] = true
@@ -4,7 +4,8 @@ module Travis::Yaml
4
4
  include LanguageSpecific
5
5
  map :jdk, :node, :perl, :php, :python, :ruby, :scala, :node, to: Version
6
6
  map :rvm, to: :ruby
7
- map :repo, :branch, :condition, to: Scalar[:str]
7
+ map :repo, to: Scalar[:str]
8
+ map :branch, :condition, to: Sequence[:str]
8
9
  map :all_branches, :tags, to: Scalar[:bool]
9
10
  prefix_scalar :branch
10
11
  end
@@ -1,10 +1,56 @@
1
1
  module Travis::Yaml
2
2
  module Nodes
3
3
  class DeployEntry < OpenMapping
4
+ class Setting < OpenMapping
5
+ KEY = ''
6
+ prefix_scalar KEY
7
+ default_type Scalar[:str, :secure]
8
+
9
+ def ==(other)
10
+ return true if super
11
+ return false unless branch_specific?
12
+ generic == other
13
+ end
14
+
15
+ def __getobj__
16
+ branch_specific? ? generic : super
17
+ end
18
+
19
+ def inspect
20
+ branch_specific? ? generic.inspect : super
21
+ end
22
+
23
+ def branch_specific?
24
+ @mapping.size == 1 and @mapping.include? KEY
25
+ end
26
+
27
+ def branches
28
+ @mapping.keys - [KEY]
29
+ end
30
+
31
+ def generic
32
+ @mapping[KEY]
33
+ end
34
+
35
+ def verify_branch(name)
36
+ branches.each do |branch|
37
+ next if branch.to_s == name.to_s
38
+ warning "branch %p not permitted by deploy condition, dropping", branch
39
+ @mapping.delete(branch)
40
+ end
41
+ end
42
+ end
43
+
44
+ default_type Setting
4
45
  prefix_scalar :provider
5
46
  map :provider, to: Scalar, required: true
6
47
  map :edge, to: Scalar[:bool], experimental: true
7
48
  map :on, to: DeployConditions
49
+
50
+ def verify
51
+ @mapping.each_value { |v| v.verify_branch(on.branch) if v.respond_to? :verify_branch } if on and on.branch
52
+ super
53
+ end
8
54
  end
9
55
  end
10
56
  end
@@ -0,0 +1,6 @@
1
+ module Travis::Yaml
2
+ module Nodes
3
+ class Dist < Scalar
4
+ end
5
+ end
6
+ end
@@ -11,7 +11,7 @@ module Travis::Yaml
11
11
  visitor.apply_mapping(self, value)
12
12
  end
13
13
 
14
- def visit_mapping(visitor, key, value)
14
+ def visit_key_value(visitor, key, value)
15
15
  key = visitor.generate_key(self, key)
16
16
  node = Scalar.new
17
17
  visitor.accept(node, value)
@@ -0,0 +1,6 @@
1
+ module Travis::Yaml
2
+ module Nodes
3
+ class Group < Scalar
4
+ end
5
+ end
6
+ end
@@ -9,10 +9,11 @@ module Travis::Yaml
9
9
  value jvm: :java, javascript: :node_js, node: :node_js, nodejs: :node_js, golang: :go,
10
10
  objective_c: :"objective-c", obj_c: :"objective-c", objc: :"objective-c"
11
11
  value "c++" => :cpp, "node.js" => :node_js, "obj-c" => :"objective-c"
12
+ value :generic, bash: :generic, sh: :generic, shell: :generic
12
13
 
13
14
  def default_os
14
- value == "objective-c" ? :osx : OSEntry.default
15
+ value == "objective-c" ? "osx" : OSEntry.default
15
16
  end
16
17
  end
17
18
  end
18
- end
19
+ end
@@ -24,12 +24,12 @@ module Travis::Yaml
24
24
  gemfile: %w[ruby objective-c],
25
25
  composer_args: %w[php],
26
26
  npm_args: %w[node_js],
27
- sdk_components: %w[android]
27
+ android: %w[android]
28
28
  }
29
29
 
30
30
  def verify_language(language)
31
31
  LANGUAGE_SPECIFIC.each do |key, languages|
32
- next unless include? key and not languages.include? language
32
+ next unless include? key and not languages.include? language.value
33
33
  mapping.delete mapped_key(key)
34
34
  warning "specified %p, but setting is not relevant for %p", key.to_s, language
35
35
  end
@@ -42,17 +42,27 @@ module Travis::Yaml
42
42
  prefix_scalar(key)
43
43
  end
44
44
 
45
- def self.prefix_sequence(key)
46
- define_method(:visit_sequence) do |visitor, value|
47
- visit_key_value(visitor, key, value)
45
+ def self.prefix_sequence(key = nil)
46
+ @prefix_sequence ||= superclass.respond_to?(:prefix_sequence) ? superclass.prefix_sequence : nil
47
+ if key
48
+ @prefix_sequence = key.to_s
49
+ define_method(:visit_sequence) do |visitor, value|
50
+ visit_key_value(visitor, key, value)
51
+ end
48
52
  end
53
+ @prefix_sequence
49
54
  end
50
55
 
51
- def self.prefix_scalar(key, *types)
52
- define_method(:visit_scalar) do |visitor, type, value, implicit = true|
53
- return super(visitor, type, value, implicit = true) if types.any? and not types.include?(type)
54
- visit_key_value(visitor, key, value)
56
+ def self.prefix_scalar(key = nil, *types)
57
+ @prefix_scalar ||= superclass.respond_to?(:prefix_scalar) ? superclass.prefix_scalar : nil
58
+ if key
59
+ @prefix_scalar = key.to_s
60
+ define_method(:visit_scalar) do |visitor, type, value, implicit = true|
61
+ return super(visitor, type, value, implicit = true) if types.any? and not types.include?(type)
62
+ visit_key_value(visitor, key, value)
63
+ end
55
64
  end
65
+ @prefix_scalar
56
66
  end
57
67
 
58
68
  def self.define_map_accessor(key)
@@ -84,6 +94,7 @@ module Travis::Yaml
84
94
 
85
95
  def visit_key_value(visitor, key, value)
86
96
  return warning("unexpected key %p, dropping", key) unless node = subnode_for(key)
97
+ warning("has multiple %p entries, keeping last entry", key) if self[key]
87
98
  self[key] = node
88
99
  visitor.accept(node, value)
89
100
  end
@@ -93,12 +104,12 @@ module Travis::Yaml
93
104
  end
94
105
 
95
106
  def []=(key, value)
96
- if key = mapped_key(key)
107
+ if mapped_key = mapped_key(key)
97
108
  unless value.is_a? Node
98
- node = subnode_for(key)
109
+ node = subnode_for(mapped_key)
99
110
  value = node if Parser::Ruby.new(value).parse(node)
100
111
  end
101
- @mapping[key] = value
112
+ @mapping[mapped_key] = value
102
113
  else
103
114
  warning("unexpected key %p, dropping", key)
104
115
  end
@@ -199,6 +210,24 @@ module Travis::Yaml
199
210
  list = value.nested_warnings(*prefix, key) + list
200
211
  end
201
212
  end
213
+
214
+ def with_value!(value)
215
+ value = value.mapping while value.is_a? Mapping
216
+ value.each { |key, value| self[key] = value }
217
+ end
218
+
219
+ def each_scalar(type = nil, &block)
220
+ return enum_for(:each_scalar, type) unless block
221
+ @mapping.each_value { |v| v.each_scalar(type, &block) }
222
+ end
223
+
224
+ protected
225
+
226
+ def dup_values
227
+ duped_mapping = @mapping.map { |key, value| [key.dup, value.dup] }
228
+ @mapping = Hash[duped_mapping]
229
+ self
230
+ end
202
231
  end
203
232
  end
204
233
  end
@@ -5,7 +5,7 @@ module Travis::Yaml
5
5
  false
6
6
  end
7
7
 
8
- attr_accessor :partent
8
+ attr_accessor :parent
9
9
  def initialize(parent)
10
10
  @nested_warnings = []
11
11
  @parent = parent
@@ -97,6 +97,63 @@ module Travis::Yaml
97
97
  def to_s
98
98
  __getobj__.to_s
99
99
  end
100
+
101
+ def decrypt(&block)
102
+ each_scalar(SecureString) { |v| v.decrypt(&block) }
103
+ end
104
+
105
+ def encrypt(&block)
106
+ each_scalar(SecureString) { |v| v.encrypt(&block) }
107
+ end
108
+
109
+ def decrypted?
110
+ each_scalar(SecureString).all? { |v| v.decrypted? }
111
+ end
112
+
113
+ def encrypted?
114
+ each_scalar(SecureString).all? { |v| v.encrypted? }
115
+ end
116
+
117
+ def serialize(serializer, options = nil)
118
+ Serializer[serializer].serialize(self, options)
119
+ end
120
+
121
+ def to_yaml(options = nil)
122
+ serialize(:yaml, options)
123
+ end
124
+
125
+ def to_json(options = nil)
126
+ serialize(:json, options)
127
+ end
128
+
129
+ def to_ruby(options = nil)
130
+ serialize(:ruby, options)
131
+ end
132
+
133
+ def to_legacy_ruby(options = nil)
134
+ serialize(:legacy, options)
135
+ end
136
+
137
+ def with_value(value)
138
+ node = dup
139
+ node.with_value!(value)
140
+ node
141
+ end
142
+
143
+ def dup
144
+ super.dup_values
145
+ end
146
+
147
+ protected
148
+
149
+ def dup_values
150
+ self
151
+ end
152
+
153
+ def dup_ivar(name)
154
+ instance_variable_set(name, instance_variable_get(name).dup)
155
+ rescue TypeError
156
+ end
100
157
  end
101
158
  end
102
159
  end
@@ -3,6 +3,10 @@ module Travis::Yaml
3
3
  class Notifications < Mapping
4
4
  Callbacks ||= FixedValue[:always, :never, :change]
5
5
 
6
+ class List < Sequence
7
+ type Scalar[:str, :secure]
8
+ end
9
+
6
10
  class Notification < Mapping
7
11
  map :enabled, :disabled, to: Scalar[:bool]
8
12
  map :on_success, :on_failure, :on_start, to: Callbacks
@@ -12,7 +16,7 @@ module Travis::Yaml
12
16
  end
13
17
 
14
18
  def self.list(name)
15
- map name, to: Sequence
19
+ map name, to: List
16
20
  prefix_sequence name
17
21
  prefix_scalar name, :str, :secure
18
22
  end
@@ -32,7 +36,7 @@ module Travis::Yaml
32
36
  end
33
37
 
34
38
  class Template < Sequence
35
- VARIABLES = %w[repository_slug repository_name repository build_number branch commit author message duration compare_url build_url]
39
+ VARIABLES = %w[repository_slug repository_name repository build_number branch commit author message duration compare_url build_url commit_message]
36
40
 
37
41
  def verify
38
42
  super
@@ -60,18 +64,18 @@ module Travis::Yaml
60
64
  list :rooms
61
65
  end
62
66
 
63
- class Flowdoc < Notification
67
+ class Flowdock < Notification
64
68
  map :api_token, to: Scalar[:str, :secure]
65
- prefix_scalar name, :str, :secure
69
+ prefix_scalar :api_token, :str, :secure
66
70
  end
67
71
 
68
72
  map :webhooks, to: Notification[:urls]
69
73
  map :email, to: Notification[:recipients]
70
74
  map :sqwiggle, :slack, :campfire, to: WithTemplate[:rooms]
71
- map :flowdoc, to: Flowdoc
75
+ map :flowdock, to: Flowdock
72
76
  map :hipchat, to: Hipchat
73
77
  map :irc, to: IRC
74
78
  map :webhook, to: :webhooks
75
79
  end
76
80
  end
77
- end
81
+ end