sfn 3.0.10 → 3.0.12

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1dbf7d97959e1120a0d7b1194371c15b7a483ebd
4
- data.tar.gz: beaddca76c30c1d453449939de41693a6ec84554
3
+ metadata.gz: 844e08d945b817d040cd227631e30a62bb2bc591
4
+ data.tar.gz: a0b766931a02119319fa21c1b1e9158706ec2320
5
5
  SHA512:
6
- metadata.gz: ab20f19b50ed8db52d845c51a2194720b875627225d2a44574124b8a06e5a87ebc55382520e4368e068776703d3649738f99e6bfc41b0f074735a5eb33152496
7
- data.tar.gz: 5bce247327ec8b0cbd793c3b28a9b4a994dda012f9f5fb0031e48e17a1306826ff8678c90a7255ffada556c9d35af4677ce577c7fa9b3679b3fd08fff0ea529a
6
+ metadata.gz: 1fcb7c461101e3c7de5e253e4e024c3cbcd05c41277ae258e325f696a4dc88c10e74d491ea932be375075e43e7587409402c7147d7aa78f235f1348fb9d800b5
7
+ data.tar.gz: f5944d0b75b1356a5467ca6180ccecd68e5661f888982726f13d1dad7b3f8e98ffbac0fd78ac267a18c7192c87749adb70e4c2137c0cd5e75488970b78dbcf22
data/CHANGELOG.md CHANGED
@@ -1,3 +1,6 @@
1
+ # v3.0.12
2
+ * [feature] New linting foundation and `lint` command (#208)
3
+
1
4
  # v3.0.10
2
5
  * [fix] Template prompting within collections (#204)
3
6
  * [enhancement] Stack parameter matching via configuration (#203)
data/docs/README.md CHANGED
@@ -13,3 +13,4 @@
13
13
  - [Enabling Callbacks](callbacks.md#enabling-callbacks)
14
14
  - [Builtin Callbacks](callbacks.md#builtin-callbacks)
15
15
  - [Custom Callbacks](callbacks.md#custom-callbacks)
16
+ - [SparklePacks](sparkle-packs.md)
data/docs/lint.md ADDED
@@ -0,0 +1,72 @@
1
+ ---
2
+ title: "Lint"
3
+ weight: 5
4
+ ---
5
+
6
+ ## Lint
7
+
8
+ The lint framework built within the sfn tool utilizes the JMESPath query language
9
+ for identifying patterns and apply validation rules.
10
+
11
+ ### Lint RuleSets
12
+
13
+ #### Local
14
+
15
+ Create rule sets using the generator. Each file must contain a single
16
+ lint rule set. Below is a simple rule set used to flag non-AWS type
17
+ resources:
18
+
19
+ ~~~ruby
20
+ # tests/lint/resource_type_check.rb
21
+
22
+ RuleSet.build(:test) do
23
+ rule :aws_resources_only do
24
+ definition 'Resources.[*][0][*].Type' do |search|
25
+ unless(search.nil?)
26
+ result = search.find_all{|i| !i.start_with?('AWS')}
27
+ result.empty? ? true : result
28
+ else
29
+ true
30
+ end
31
+ end
32
+
33
+ fail_message 'All types must be within AWS root namespace'
34
+ end
35
+ end
36
+ ~~~
37
+
38
+ #### Library
39
+
40
+ When a rule set is defined within a library, it must use the full constant namespace and
41
+ must register to allow access to the rule set:
42
+
43
+ ~~~ruby
44
+ my_ruleset = Sfn::Lint::RuleSet.build(:test) do
45
+ rule :aws_resources_only do
46
+ definition 'Resources.[*][0][*].Type' do |search|
47
+ unless(search.nil?)
48
+ result = search.find_all{|i| !i.start_with?('AWS')}
49
+ result.empty? ? true : result
50
+ else
51
+ true
52
+ end
53
+ end
54
+
55
+ fail_message 'All types must be within AWS root namespace'
56
+ end
57
+ end
58
+ Sfn::Lint::RuleSet.register(my_ruleset)
59
+ ~~~
60
+
61
+ ### Usage
62
+
63
+ By default `sfn` will apply any registered rule sets that are defined for the target provider.
64
+
65
+ #### Local
66
+
67
+ Provide a template and lint directory to the `lint` command. For example,
68
+ if lint rule sets are defined within `tests/lint`:
69
+
70
+ ~~~
71
+ $ sfn lint --file my-template --lint-directory tests/lint
72
+ ~~~
@@ -0,0 +1,75 @@
1
+ ---
2
+ title: "SparklePacks"
3
+ weight: 4
4
+ anchors:
5
+ - title: "Enabling SparklePacks"
6
+ url: "#enabling-sparklepacks"
7
+ ---
8
+
9
+ ## What is a SparklePack?
10
+
11
+ SparklePacks are implemented as a feature of the SparkleFormation library,
12
+ providing a means to package SparkleFormation building blocks
13
+ and templates as reusable, redistributable software artifacts.
14
+ A SparklePack may package up any combination of SparkleFormation
15
+ [building blocks](http://www.sparkleformation.io/docs/sparkle_formation/building-blocks.html) and templates.
16
+
17
+ sfn supports loading SparklePacks distributed as [Ruby gems](http://www.sparkleformation.io/docs/sparkle_formation/sparkle-packs.html#distribution).
18
+ You can find published SparklePacks on the RubyGems site by
19
+ [searching for the sparkle-pack prefix](https://rubygems.org/search?query=sparkle-pack).
20
+
21
+ ### Enabling SparklePacks
22
+
23
+ The following examples use the [sparkle-pack-aws-availability-zones](https://rubygems.org/gems/sparkle-pack-aws-availability-zones) gem.
24
+ In reviewing [the source code of that project on Github](https://github.com/hw-labs/sparkle-pack-aws-availability-zones),
25
+ note that it provides a [`zones` registry](https://github.com/hw-labs/sparkle-pack-aws-availability-zones/blob/v0.1.2/lib/sparkleformation/registry/get_azs.rb)
26
+ which uses the aws-sdk-core library to return an array of available AZs.
27
+
28
+ When using sfn with Bundler, we'll add any SparklePacks we
29
+ want to enable to the `sfn` group in our Gemfile:
30
+
31
+ ~~~ruby
32
+ # Gemfile
33
+ source 'https://rubygems.org'
34
+
35
+ gem 'sfn'
36
+
37
+ group :sfn do
38
+ gem 'sparkle-pack-aws-availability-zones'
39
+ end
40
+ ~~~
41
+
42
+ After running `bundle`, the SparklePack is installed but not yet enabled:
43
+
44
+ ~~~
45
+ $ cat sparkleformation/zones_test.rb
46
+ SparkleFormation.new(:zones_test) do
47
+ zones registry!(:zones)
48
+ end
49
+
50
+ $ bundle exec sfn print --file zones_test
51
+ ERROR: SparkleFormation::Error::NotFound::Registry: Failed to locate item named: `zones`
52
+ ~~~
53
+
54
+ Adding the gem to an array of `sparkle_packs` in
55
+ the `.sfn` configuration file will activate it for use:
56
+
57
+ ~~~ruby
58
+ Configuration.new do
59
+ sparkle_pack [ 'sparkle-pack-aws-availability-zones' ]
60
+ end
61
+ ~~~
62
+
63
+ Invoking `zones` registry in the template is now functional:
64
+
65
+ ~~~
66
+ $ bundle exec sfn print --file zones_test
67
+ {
68
+ "Zones": [
69
+ "us-east-1a",
70
+ "us-east-1b",
71
+ "us-east-1c",
72
+ "us-east-1e"
73
+ ]
74
+ }
75
+ ~~~
data/lib/sfn.rb CHANGED
@@ -17,5 +17,6 @@ module Sfn
17
17
  autoload :Command, 'sfn/command'
18
18
  autoload :CommandModule, 'sfn/command_module'
19
19
  autoload :Planner, 'sfn/planner'
20
+ autoload :Lint, 'sfn/lint'
20
21
 
21
22
  end
data/lib/sfn/command.rb CHANGED
@@ -17,6 +17,7 @@ module Sfn
17
17
  autoload :Import, 'sfn/command/import'
18
18
  autoload :Init, 'sfn/command/init'
19
19
  autoload :Inspect, 'sfn/command/inspect'
20
+ autoload :Lint, 'sfn/command/lint'
20
21
  autoload :List, 'sfn/command/list'
21
22
  autoload :Print, 'sfn/command/print'
22
23
  autoload :Promote, 'sfn/command/promote'
@@ -0,0 +1,87 @@
1
+ require 'sfn'
2
+
3
+ module Sfn
4
+ class Command
5
+ # Lint command
6
+ class Lint < Command
7
+
8
+ include Sfn::CommandModule::Base
9
+ include Sfn::CommandModule::Template
10
+
11
+ # Perform linting
12
+ def execute!
13
+ print_only_original = config[:print_only]
14
+ config[:print_only] = true
15
+ file = load_template_file
16
+ ui.info "#{ui.color("Template Linting (#{provider.connection.provider}): ", :bold)} #{config[:file].sub(Dir.pwd, '').sub(%r{^/}, '')}"
17
+ config[:print_only] = print_only_original
18
+
19
+ raw_template = parameter_scrub!(template_content(file))
20
+
21
+ if(config[:print_only])
22
+ ui.puts raw_template
23
+ else
24
+ result = lint_template(raw_template)
25
+ if(result == true)
26
+ ui.puts ui.color(' -> VALID', :green, :bold)
27
+ else
28
+ ui.puts ui.color(' -> INVALID', :red, :bold)
29
+ result.each do |failure|
30
+ ui.error "Result Set: #{ui.color(failure[:rule_set].name, :red, :bold)}"
31
+ failure[:failures].each do |f_msg|
32
+ ui.puts "#{ui.color(' *', :red, :bold)} #{f_msg}"
33
+ end
34
+ end
35
+ raise 'Linting failure'
36
+ end
37
+ end
38
+ end
39
+
40
+ # Apply linting to given template
41
+ #
42
+ # @param template [Hash]
43
+ # @return [TrueClass, Array<Smash[:rule_set, :failures]>]
44
+ def lint_template(template)
45
+ results = rule_sets.map do |set|
46
+ result = set.apply(template)
47
+ unless(result == true)
48
+ Smash.new(:rule_set => set, :failures => result)
49
+ end
50
+ end.compact
51
+ results.empty? ? true : results
52
+ end
53
+
54
+ # @return [Array<Sfn::Lint::RuleSet>]
55
+ def rule_sets
56
+ sets = [config[:lint_directory]].flatten.compact.map do |directory|
57
+ if(File.directory?(directory))
58
+ files = Dir.glob(File.join(directory, '**', '**', '*.rb'))
59
+ files.map do |path|
60
+ begin
61
+ Sfn::Lint.class_eval(
62
+ IO.read(path), path, 1
63
+ )
64
+ rescue
65
+ ui.warn "Failed to load detected file: #{path}"
66
+ nil
67
+ end
68
+ end
69
+ end
70
+ end.flatten.compact.find_all{|rs| rs.provider == provider.connection.provider}
71
+ unless(config[:local_rule_sets_only])
72
+ sets += Sfn::Lint::RuleSet.get_all(provider.connection.provider)
73
+ end
74
+ if(config[:disabled_rule_set])
75
+ disabled = [config[:disabled_rule_set]].flatten.compact
76
+ sets.delete_if{|i| disabled.include?(i.name.to_s) }
77
+ end
78
+ if(config[:enabled_rule_set])
79
+ enabled = [config[:enabled_rule_set]].flatten.compact
80
+ sets.delete_if{|i| enabled.include?(i.name.to_s) }
81
+ end
82
+ sets
83
+ end
84
+
85
+ end
86
+ end
87
+ end
data/lib/sfn/config.rb CHANGED
@@ -52,6 +52,7 @@ module Sfn
52
52
  autoload :Import, 'sfn/config/import'
53
53
  autoload :Init, 'sfn/config/init'
54
54
  autoload :Inspect, 'sfn/config/inspect'
55
+ autoload :Lint, 'sfn/config/lint'
55
56
  autoload :List, 'sfn/config/list'
56
57
  autoload :Print, 'sfn/config/print'
57
58
  autoload :Promote, 'sfn/config/promote'
@@ -0,0 +1,28 @@
1
+ require 'sfn'
2
+
3
+ module Sfn
4
+ class Config
5
+ # Lint command configuration
6
+ class Lint < Validate
7
+ attribute(
8
+ :lint_directory, String,
9
+ :description => 'Directory containing lint rule sets',
10
+ :multiple => true
11
+ )
12
+ attribute(
13
+ :disabled_rule_set, String,
14
+ :description => 'Disable rule set from being applied',
15
+ :multiple => true
16
+ )
17
+ attribute(
18
+ :enabled_rule_set, String,
19
+ :description => 'Only apply this rule set',
20
+ :multiple => true
21
+ )
22
+ attribute(
23
+ :local_rule_sets_only, [TrueClass, FalseClass],
24
+ :description => 'Only apply rule sets provided by lint directory'
25
+ )
26
+ end
27
+ end
28
+ end
data/lib/sfn/lint.rb ADDED
@@ -0,0 +1,12 @@
1
+ require 'sfn'
2
+ require 'jmespath'
3
+
4
+ module Sfn
5
+ module Lint
6
+
7
+ autoload :Definition, 'sfn/lint/definition'
8
+ autoload :Rule, 'sfn/lint/rule'
9
+ autoload :RuleSet, 'sfn/lint/rule_set'
10
+
11
+ end
12
+ end
@@ -0,0 +1,57 @@
1
+ require 'sfn'
2
+
3
+ module Sfn
4
+ module Lint
5
+ # Lint defition
6
+ class Definition
7
+
8
+ # @return [String] search expression used for matching
9
+ attr_reader :search_expression
10
+ # @return [Proc-ish] must respond to #call
11
+ attr_reader :evaluator
12
+ # @return [Symbol] target provider
13
+ attr_reader :provider
14
+
15
+ # Create a new definition
16
+ #
17
+ # @param expr [String] search expression used for matching
18
+ # @param provider [String, Symbol] target provider
19
+ # @param evaluator [Proc] logic used to handle match
20
+ # @return [self]
21
+ def initialize(expr, provider=:aws, evaluator=nil, &block)
22
+ if(evaluator && block)
23
+ raise ArgumentError.new 'Only evaluator or block can be provided, not both.'
24
+ end
25
+ @provider = Bogo::Utility.snake(provider).to_sym
26
+ @search_expression = expr
27
+ @evaluator = evaluator || block
28
+ end
29
+
30
+ # Apply definition to template
31
+ #
32
+ # @param template [Hash] template being processed
33
+ # @return [TrueClass, Array<String>] true if passed. List of string results that failed
34
+ def apply(template)
35
+ result = JMESPath.search(search_expression, template)
36
+ run(result, template)
37
+ end
38
+
39
+ protected
40
+
41
+ # Check result of search expression
42
+ #
43
+ # @param result [Object] result(s) of search expression
44
+ # @param template [Hash] full template
45
+ # @return [TrueClass, Array<String>] true if passed. List of string results that failed
46
+ # @note override this method when subclassing
47
+ def run(result, template)
48
+ unless(evaluator)
49
+ raise NotImplementedError.new 'No evaluator has been defined for this definition!'
50
+ end
51
+ evaluator.call(result, template)
52
+ end
53
+
54
+ end
55
+
56
+ end
57
+ end
@@ -0,0 +1,118 @@
1
+ require 'sfn'
2
+
3
+ module Sfn
4
+ module Lint
5
+ # Composition of definitions
6
+ class Rule
7
+
8
+ # @return [Symbol] name of rule
9
+ attr_reader :name
10
+ # @return [Array<Definition>] definitions composing rule
11
+ attr_reader :definitions
12
+ # @return [String] message describing failure
13
+ attr_reader :fail_message
14
+ # @return [Symbol] target provider
15
+ attr_reader :provider
16
+
17
+ # Create a new rule
18
+ #
19
+ # @param name [String, Symbol] name of rule
20
+ # @param definitions [Array<Definition>] definitions composing rule
21
+ # @param fail_message [String] message to describe failure
22
+ # @param provider [String, Symbol] target provider
23
+ # @return [self]
24
+ def initialize(name, definitions, fail_message, provider=:aws)
25
+ @name = name.to_sym
26
+ @definitions = definitions.dup.uniq.freeze
27
+ @fail_message = fail_message
28
+ @provider = Bogo::Utility.snake(provider).to_sym
29
+ validate_definitions!
30
+ end
31
+
32
+ # Generate the failure message for this rule with given failure
33
+ # result set.
34
+ def generate_fail_message(results)
35
+ msg = fail_message.dup
36
+ unless(results.empty?)
37
+ failed_items = results.map do |item|
38
+ f_item = item[:failures]
39
+ next if f_item.nil? || f_item == true || f_item == false
40
+ f_item
41
+ end.flatten.compact.map(&:to_s)
42
+ unless(failed_items.empty?)
43
+ msg = "#{msg} (failures: `#{failed_items.join('`, `')}`)"
44
+ end
45
+ end
46
+ msg
47
+ end
48
+
49
+ # Apply all definitions to template
50
+ #
51
+ # @param template [Hash]
52
+ # @return [TrueClass, Array<Smash[:definition, :failures]>] true if passed. Definition failures if failed.
53
+ def apply(template)
54
+ results = definitions.map do |definition|
55
+ result = definition.apply(template)
56
+ result == true ? result : Smash.new(:definition => definition, :failures => result)
57
+ end
58
+ if(results.all?{|item| item == true})
59
+ true
60
+ else
61
+ results.delete_if{|item| item == true}
62
+ results
63
+ end
64
+ end
65
+
66
+ # Check if template passes this rule
67
+ #
68
+ # @param template [Hash]
69
+ # @return [TrueClass, FalseClass]
70
+ def pass?(template)
71
+ apply(template) == true
72
+ end
73
+
74
+ # Check if template fails this rule
75
+ #
76
+ # @param template [Hash]
77
+ # @return [TrueClass, FalseClass]
78
+ def fail?(template)
79
+ !pass?(template)
80
+ end
81
+
82
+ # Add a new definition to the collection
83
+ #
84
+ # @param definition [Definition] new definition to add
85
+ # @return [self]
86
+ def add_definition(definition)
87
+ new_defs = definitions.dup
88
+ new_defs << definition
89
+ @definitions = new_defs.uniq.freeze
90
+ validate_definitions!
91
+ self
92
+ end
93
+
94
+ # Remove a definition from the collection
95
+ #
96
+ # @param definition [Definition] definition to remove
97
+ # @return [self]
98
+ def remove_definition(definition)
99
+ new_defs = definitions.dup
100
+ new_defs.delete(definition)
101
+ @definitions = new_defs.uniq.freeze
102
+ self
103
+ end
104
+
105
+ # Check that provided definitions provider match rule defined provider
106
+ def validate_definitions!
107
+ non_match = definitions.find_all do |definition|
108
+ definition.provider != provider
109
+ end
110
+ unless(non_match.empty?)
111
+ raise ArgumentError.new "Rule defines `#{provider}` as provider but includes definitions for " \
112
+ "non matching providers. (#{non_match.map(&:provider).map(&:to_s).uniq.sort.join(', ')})"
113
+ end
114
+ end
115
+
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,177 @@
1
+ require 'sfn'
2
+
3
+ module Sfn
4
+ module Lint
5
+ # Named collection of rules
6
+ class RuleSet
7
+
8
+ # Helper class for ruleset generation
9
+ class Creator
10
+
11
+ attr_reader :items, :provider
12
+
13
+ def initialize(provider)
14
+ @provider = provider
15
+ @items = []
16
+ end
17
+
18
+ class RuleSet < Creator
19
+
20
+ def rule(name, &block)
21
+ r = Rule.new(provider)
22
+ r.instance_exec(&block)
23
+ items << Sfn::Lint::Rule.new(name, r.items, r.fail_message, provider)
24
+ end
25
+
26
+ end
27
+
28
+ class Rule < Creator
29
+
30
+ def definition(expr, evaluator=nil, &block)
31
+ items << Sfn::Lint::Definition.new(expr, provider, evaluator, &block)
32
+ end
33
+
34
+ def fail_message(val=nil)
35
+ unless(val.nil?)
36
+ @fail_message = val
37
+ end
38
+ @fail_message
39
+ end
40
+
41
+ end
42
+
43
+ end
44
+
45
+ class << self
46
+
47
+ @@_rule_set_registry = Smash.new
48
+
49
+ # RuleSet generator helper for quickly building simple rule sets
50
+ #
51
+ # @param name [String] name of rule set
52
+ # @param provider [String, Symbol] target provider
53
+ # @yieldblock rule set content
54
+ def build(name, provider=:aws, &block)
55
+ provider = Bogo::Utility.snake(provider).to_sym
56
+ rs = Creator::RuleSet.new(provider)
57
+ rs.instance_exec(&block)
58
+ self.new(name, provider, rs.items)
59
+ end
60
+
61
+ # Register a rule set
62
+ #
63
+ # @param rule_set [RuleSet]
64
+ # @return [TrueClass]
65
+ def register(rule_set)
66
+ @@_rule_set_registry.set(rule_set.provider, rule_set.name, rule_set)
67
+ true
68
+ end
69
+
70
+ # Get registered rule set
71
+ #
72
+ # @param name [String] name of rule set
73
+ # @param provider [String] target provider
74
+ # @return [RuleSet, NilClass]
75
+ def get(name, provider=:aws)
76
+ provider = Bogo::Utility.snake(provider)
77
+ @@_rule_set_registry.get(provider, name)
78
+ end
79
+
80
+ # Get all rule sets for specified provider
81
+ #
82
+ # @param provider [String] target provider
83
+ # @return [Array<RuleSet>]
84
+ def get_all(provider=:aws)
85
+ @@_rule_set_registry.fetch(provider, {}).values
86
+ end
87
+
88
+ end
89
+
90
+ include Bogo::Memoization
91
+
92
+ # @return [Symbol] name
93
+ attr_reader :name
94
+ # @return [Symbol] target provider
95
+ attr_reader :provider
96
+ # @return [Array<Rule>] rules of set
97
+ attr_reader :rules
98
+
99
+ # Create new rule set
100
+ #
101
+ # @param name [String, Symbol] name of rule set
102
+ # @param provider [String, Symbol] name of target provider
103
+ # @param rules [Array<Rule>] list of rules defining this set
104
+ # @return [self]
105
+ def initialize(name, provider=:aws, rules=[])
106
+ @name = name.to_sym
107
+ @provider = Bogo::Utility.snake(provider).to_sym
108
+ @rules = rules.dup.uniq.freeze
109
+ validate_rules!
110
+ end
111
+
112
+ # Add a new rule to the collection
113
+ #
114
+ # @param rule [Rule] new rule to add
115
+ # @return [self]
116
+ def add_rule(rule)
117
+ new_rules = rules.dup
118
+ new_rules << rule
119
+ @rules = new_rules.uniq.freeze
120
+ validate_rules!
121
+ self
122
+ end
123
+
124
+ # Remove a rule from the collection
125
+ #
126
+ # @param rule [Rule] rule to remove
127
+ # @return [self]
128
+ def remove_rule(rule)
129
+ new_rules = rules.dup
130
+ new_rules.delete(rule)
131
+ @rules = new_rules.uniq.freeze
132
+ self
133
+ end
134
+
135
+ # Apply rule set to template.
136
+ #
137
+ # @param template [Hash]
138
+ # @return [TrueClass, Array<String>] true on success, list failure messages on failure
139
+ def apply(template)
140
+ failures = collect_failures(template)
141
+ if(failures.empty?)
142
+ true
143
+ else
144
+ failures.map do |failure|
145
+ failure[:rule].generate_fail_message(failure[:result])
146
+ end
147
+ end
148
+ end
149
+
150
+ # Process template through rules defined in this set and
151
+ # store failure information
152
+ #
153
+ # @param template [Hash]
154
+ # @return [Array<Rule>] list of failures
155
+ def collect_failures(template)
156
+ results = rules.map do |rule|
157
+ result = rule.apply(template)
158
+ result == true ? true : Smash.new(:rule => rule, :result => result)
159
+ end
160
+ results.delete_if{|i| i == true}
161
+ results
162
+ end
163
+
164
+ # Check that provided rules provider match rule set defined provider
165
+ def validate_rules!
166
+ non_match = rules.find_all do |rule|
167
+ rule.provider != provider
168
+ end
169
+ unless(non_match.empty?)
170
+ raise ArgumentError.new "Rule set defines `#{provider}` as provider but includes rules for " \
171
+ "non matching providers. (#{non_match.map(&:provider).map(&:to_s).uniq.sort.join(', ')})"
172
+ end
173
+ end
174
+
175
+ end
176
+ end
177
+ end
data/lib/sfn/version.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  module Sfn
2
2
  # Current library version
3
- VERSION = Gem::Version.new('3.0.10')
3
+ VERSION = Gem::Version.new('3.0.12')
4
4
  end
data/sfn.gemspec CHANGED
@@ -18,6 +18,7 @@ Gem::Specification.new do |s|
18
18
  s.add_runtime_dependency 'miasma-open-stack', '>= 0.1.0', '< 0.3'
19
19
  s.add_runtime_dependency 'miasma-rackspace', '>= 0.1.0', '< 0.3'
20
20
  s.add_runtime_dependency 'miasma-google', '>= 0.1.0', '< 0.3'
21
+ s.add_runtime_dependency 'jmespath'
21
22
  s.add_runtime_dependency 'net-ssh'
22
23
  s.add_runtime_dependency 'sparkle_formation', '>= 3.0.3', '< 4'
23
24
  s.add_runtime_dependency 'hashdiff', '~> 0.2.2'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sfn
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.10
4
+ version: 3.0.12
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Roberts
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-05-19 00:00:00.000000000 Z
11
+ date: 2016-05-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bogo-cli
@@ -170,6 +170,20 @@ dependencies:
170
170
  - - "<"
171
171
  - !ruby/object:Gem::Version
172
172
  version: '0.3'
173
+ - !ruby/object:Gem::Dependency
174
+ name: jmespath
175
+ requirement: !ruby/object:Gem::Requirement
176
+ requirements:
177
+ - - ">="
178
+ - !ruby/object:Gem::Version
179
+ version: '0'
180
+ type: :runtime
181
+ prerelease: false
182
+ version_requirements: !ruby/object:Gem::Requirement
183
+ requirements:
184
+ - - ">="
185
+ - !ruby/object:Gem::Version
186
+ version: '0'
173
187
  - !ruby/object:Gem::Dependency
174
188
  name: net-ssh
175
189
  requirement: !ruby/object:Gem::Requirement
@@ -317,7 +331,9 @@ files:
317
331
  - docs/images/d_list.png
318
332
  - docs/images/d_update.png
319
333
  - docs/images/d_validate.png
334
+ - docs/lint.md
320
335
  - docs/overview.md
336
+ - docs/sparkle-packs.md
321
337
  - docs/usage.md
322
338
  - docs/v/0.3.2/marked.js
323
339
  - docs/v/bootstrap.min.css
@@ -347,6 +363,7 @@ files:
347
363
  - lib/sfn/command/import.rb
348
364
  - lib/sfn/command/init.rb
349
365
  - lib/sfn/command/inspect.rb
366
+ - lib/sfn/command/lint.rb
350
367
  - lib/sfn/command/list.rb
351
368
  - lib/sfn/command/print.rb
352
369
  - lib/sfn/command/promote.rb
@@ -369,11 +386,16 @@ files:
369
386
  - lib/sfn/config/import.rb
370
387
  - lib/sfn/config/init.rb
371
388
  - lib/sfn/config/inspect.rb
389
+ - lib/sfn/config/lint.rb
372
390
  - lib/sfn/config/list.rb
373
391
  - lib/sfn/config/print.rb
374
392
  - lib/sfn/config/promote.rb
375
393
  - lib/sfn/config/update.rb
376
394
  - lib/sfn/config/validate.rb
395
+ - lib/sfn/lint.rb
396
+ - lib/sfn/lint/definition.rb
397
+ - lib/sfn/lint/rule.rb
398
+ - lib/sfn/lint/rule_set.rb
377
399
  - lib/sfn/monkey_patch.rb
378
400
  - lib/sfn/monkey_patch/stack.rb
379
401
  - lib/sfn/monkey_patch/stack/azure.rb