terraspace 1.0.1 → 1.0.5

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b24e7a97ebf99ac393d03ef6ffec1381fae0508ae2c9f6bbaa9f0d7aad3139c3
4
- data.tar.gz: 5f553f4265a69128ef74dc7fdf22ea1dafbe0b2f73396fa4fa9b98cfcf24060a
3
+ metadata.gz: cfdfafd180a61f7e43131770457ffa446c8bae59d3db9e68c9b9a8930fa6ca88
4
+ data.tar.gz: 684480a5c4454ee457c5e236574ace9424a514d0822c2693190de41354aea40d
5
5
  SHA512:
6
- metadata.gz: 2cd672d6cd5bafdb40f2275a4ee34eab50ac3855b4df2ee535a89b3732f1fda7f07693da14bf2d9c82d49ae07871debdc115aca4e175068148917fa37b6694ec
7
- data.tar.gz: b3103984ef841b2082abf33fd84505db942e09b1a6a8bd0ca0a45774dbb018a31c202f1a3cf9fb0c7a87f1a51abf3825acbd12b325fa12264150d42deb323af8
6
+ metadata.gz: 73bef840c84345011a8246128537d81d76fee4c73215ac3856e43814e04304bfcf16d54213eee2fb940650f3fe4c13df249d1476805090cc0fbd7524f00fed00
7
+ data.tar.gz: a4b3f901aa19c01de17a059bd907197d4b2f8276a72de4ea29381ee803291ea9e4f33cc8c9667358247868297fb3b784dab1f0b127c7a04a98f37a56c4e2a773
data/CHANGELOG.md CHANGED
@@ -3,6 +3,18 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  This project *loosely tries* to adhere to [Semantic Versioning](http://semver.org/), even before v1.0.
5
5
 
6
+ ## [1.0.5] - 2022-01-23
7
+ - [#194](https://github.com/boltops-tools/terraspace/pull/194) ability to allow and deny envs, regions, and stacks
8
+
9
+ ## [1.0.4] - 2022-01-21
10
+ - [#193](https://github.com/boltops-tools/terraspace/pull/193) improve all include_stacks and exclude_stacks option
11
+
12
+ ## [1.0.3] - 2022-01-20
13
+ - [#192](https://github.com/boltops-tools/terraspace/pull/192) run super-early boot hooks before dotenv load
14
+
15
+ ## [1.0.2] - 2022-01-17
16
+ - [#190](https://github.com/boltops-tools/terraspace/pull/190) update terraspace-bundler gem depedency to 0.5.0
17
+
6
18
  ## [1.0.1] - 2022-01-15
7
19
  - [#189](https://github.com/boltops-tools/terraspace/pull/189) dotenv support
8
20
 
@@ -0,0 +1,12 @@
1
+ class Terraspace::App::CallableOption
2
+ module Concern
3
+ def callable_option(options={})
4
+ callable_option = Terraspace::App::CallableOption.new(
5
+ config_name: options[:config_name],
6
+ config_value: options[:config_value],
7
+ passed_args: options[:passed_args],
8
+ )
9
+ callable_option.object
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,58 @@
1
+ # Class represents a terraspace option that is possibly callable. Examples:
2
+ #
3
+ # config.allow.envs
4
+ # config.allow.regions
5
+ # config.deny.envs
6
+ # config.deny.regions
7
+ # config.all.include_stacks
8
+ # config.all.exclude_stacks
9
+ #
10
+ # Abstraction is definitely obtuse. Using it to get rid of duplication.
11
+ #
12
+ class Terraspace::App
13
+ class CallableOption
14
+ include Terraspace::Util::Logging
15
+
16
+ def initialize(options={})
17
+ @options = options
18
+ # Example:
19
+ # config_name: config.allow.envs
20
+ # config_value: ["dev"]
21
+ # args: [@stack_name] # passed to object.call
22
+ @config_name = options[:config_name]
23
+ @config_value = options[:config_value]
24
+ @passed_args = options[:passed_args]
25
+ end
26
+
27
+ # Returns either an Array or nil
28
+ def object
29
+ case @config_value
30
+ when nil
31
+ return nil
32
+ when Array
33
+ return @config_value
34
+ when -> (c) { c.respond_to?(:public_instance_methods) && c.public_instance_methods.include?(:call) }
35
+ object= @config_value.new
36
+ when -> (c) { c.respond_to?(:call) }
37
+ object = @config_value
38
+ else
39
+ raise "Invalid option for #{@config_name}"
40
+ end
41
+
42
+ if object
43
+ result = @passed_args.empty? ? object.call : object.call(*@passed_args)
44
+ unless result.is_a?(Array) || result.is_a?(NilClass)
45
+ message = "ERROR: The #{@config_name} needs to return an Array or nil"
46
+ logger.info message.color(:yellow)
47
+ logger.info <<~EOL
48
+ The #{@config_name} when assigned a class, object, or proc must implement
49
+ the call method and return an Array or nil.
50
+ The current return value is a #{result.class}
51
+ EOL
52
+ raise message
53
+ end
54
+ end
55
+ result
56
+ end
57
+ end
58
+ end
@@ -12,16 +12,26 @@ module Terraspace
12
12
 
13
13
  def defaults
14
14
  config = ActiveSupport::OrderedOptions.new
15
+
15
16
  config.all = ActiveSupport::OrderedOptions.new
16
17
  config.all.concurrency = 5
17
18
  config.all.exit_on_fail = ActiveSupport::OrderedOptions.new
18
19
  config.all.exit_on_fail.down = true
19
20
  config.all.exit_on_fail.up = true
20
- config.all.ignore_stacks = nil
21
- config.all.include_stacks = nil
21
+
22
22
  config.allow = ActiveSupport::OrderedOptions.new
23
23
  config.allow.envs = nil
24
24
  config.allow.regions = nil
25
+ config.allow.stacks = nil
26
+ config.deny = ActiveSupport::OrderedOptions.new
27
+ config.deny.envs = nil
28
+ config.deny.regions = nil
29
+ config.deny.stacks = nil
30
+
31
+ config.all.exclude_stacks = nil
32
+ config.all.include_stacks = nil
33
+ config.all.consider_allow_deny_stacks = true
34
+
25
35
  config.auto_create_backend = true
26
36
  config.build = ActiveSupport::OrderedOptions.new
27
37
  config.build.cache_dir = ":CACHE_ROOT/:REGION/:ENV/:BUILD_DIR"
@@ -1,8 +1,8 @@
1
1
  module Terraspace
2
2
  module Booter
3
3
  def boot
4
- Dotenv.new.load!
5
4
  run_hooks
5
+ Dotenv.new.load!
6
6
  Terraspace::Bundle.require # load plugins
7
7
  load_plugin_default_configs
8
8
  Terraspace::App::Inits.run_all
@@ -0,0 +1,59 @@
1
+ class Terraspace::Builder::Allow
2
+ class Base
3
+ include Terraspace::App::CallableOption::Concern
4
+
5
+ def initialize(mod)
6
+ @mod = mod # Only Region subclass uses @mod but keeping interface same for Env for simplicity
7
+ @stack_name = mod.name
8
+ end
9
+
10
+ def check!
11
+ messages = []
12
+ unless allowed?
13
+ messages << message # message is interface method
14
+ end
15
+ unless messages.empty?
16
+ puts "ERROR: The configs do not allow this.".color(:red)
17
+ puts messages
18
+ exit 1
19
+ end
20
+ end
21
+
22
+ def allowed?
23
+ if allows.nil? && denys.nil?
24
+ true
25
+ elsif denys.nil?
26
+ allows.include?(check_value)
27
+ elsif allows.nil?
28
+ !denys.include?(check_value)
29
+ else
30
+ allows.include?(check_value) && !denys.include?(check_value)
31
+ end
32
+ end
33
+
34
+ def allows
35
+ callable_option(
36
+ config_name: "config.allow.#{config_name}",
37
+ config_value: config.dig(:allow, config_name),
38
+ passed_args: [@stack_name],
39
+ )
40
+ end
41
+
42
+ def denys
43
+ callable_option(
44
+ config_name: "config.deny.#{config_name}",
45
+ config_value: config.dig(:deny, config_name),
46
+ passed_args: [@stack_name],
47
+ )
48
+ end
49
+
50
+ private
51
+ def config
52
+ Terraspace.config
53
+ end
54
+
55
+ def config_name
56
+ self.class.to_s.split('::').last.underscore.pluralize.to_sym # ActiveSuport::HashWithIndifferentAccess#dig requires symbol
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,17 @@
1
+ class Terraspace::Builder::Allow
2
+ class Env < Base
3
+ # interface method
4
+ def message
5
+ messages = []
6
+ messages << "This env is not allowed to be used: TS_ENV=#{Terraspace.env}"
7
+ messages << "Allow envs: #{allows.join(', ')}" if allows
8
+ messages << "Deny envs: #{denys.join(', ')}" if denys
9
+ messages.join("\n")
10
+ end
11
+
12
+ # interface method
13
+ def check_value
14
+ Terraspace.env
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,31 @@
1
+ class Terraspace::Builder::Allow
2
+ class Region < Base
3
+ # interface method
4
+ def message
5
+ messages = []
6
+ word = config_name.to_s # IE: regions or locations
7
+ messages << "This #{word.singularize} is not allowed to be used: Detected current #{word.singularize}=#{current_region}"
8
+ messages << "Allow #{word}: #{allows.join(', ')}" if allows
9
+ messages << "Deny #{word}: #{denys.join(', ')}" if denys
10
+ messages.join("\n")
11
+ end
12
+
13
+ # interface method
14
+ def check_value
15
+ current_region
16
+ end
17
+
18
+ def current_region
19
+ expander = Terraspace::Compiler::Expander.autodetect(@mod).expander
20
+ expander.region
21
+ end
22
+
23
+ def config_name
24
+ if config.allow.locations || config.deny.locations
25
+ :locations # ActiveSuport::HashWithIndifferentAccess#dig requires symbol
26
+ else
27
+ super # :regions
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,17 @@
1
+ class Terraspace::Builder::Allow
2
+ class Stack < Base
3
+ # interface method
4
+ def message
5
+ messages = []
6
+ messages << "This stack is not allowed to be used for TS_ENV=#{Terraspace.env}"
7
+ messages << "Allow stacks: #{allows.join(', ')}" if allows
8
+ messages << "Deny stacks: #{denys.join(', ')}" if denys
9
+ messages.join("\n")
10
+ end
11
+
12
+ # interface method
13
+ def check_value
14
+ @mod.name
15
+ end
16
+ end
17
+ end
@@ -5,39 +5,9 @@ class Terraspace::Builder
5
5
  end
6
6
 
7
7
  def check!
8
- messages = []
9
- unless env_allowed?
10
- messages << "This env is not allowed to be used: TS_ENV=#{Terraspace.env}"
11
- messages << "Allowed envs: #{config.allow.envs.join(', ')}"
12
- end
13
- unless region_allowed?
14
- messages << "This region is not allowed to be used: Detected current region=#{current_region}"
15
- messages << "Allowed regions: #{config.allow.regions.join(', ')}"
16
- end
17
- unless messages.empty?
18
- puts "ERROR: The configs do not allow this.".color(:red)
19
- puts messages
20
- exit 1
21
- end
22
- end
23
-
24
- def env_allowed?
25
- return true unless config.allow.envs
26
- config.allow.envs.include?(Terraspace.env)
27
- end
28
-
29
- def region_allowed?
30
- return true unless config.allow.regions
31
- config.allow.regions.include?(current_region)
32
- end
33
-
34
- def current_region
35
- expander = Terraspace::Compiler::Expander.autodetect(@mod).expander
36
- expander.region
37
- end
38
-
39
- def config
40
- Terraspace.config
8
+ Env.new(@mod).check!
9
+ Stack.new(@mod).check!
10
+ Region.new(@mod).check!
41
11
  end
42
12
  end
43
13
  end
@@ -1,28 +1,79 @@
1
1
  module Terraspace::Compiler
2
2
  class Select
3
+ include Terraspace::App::CallableOption::Concern
4
+ include Terraspace::Util::Logging
5
+
3
6
  def initialize(path)
4
7
  @path = path
5
8
  @stack_name = extract_stack_name(path)
6
9
  end
7
10
 
8
11
  def selected?
9
- all = Terraspace.config.all
10
- # Key difference between include_stacks vs all.include_stacks option is that
11
- # the option can be nil. The local variable is guaranteed to be an Array.
12
- # This simplifies the logic.
13
- include_stacks = all.include_stacks || []
14
- ignore_stacks = all.ignore_stacks || []
15
-
16
- if all.include_stacks.nil?
17
- !ignore_stacks.include?(@stack_name)
12
+ ignore_stacks_deprecation_warning
13
+ if include_stacks.nil? && exclude_stacks.nil?
14
+ true
15
+ elsif include_stacks.nil?
16
+ !exclude_stacks.include?(@stack_name)
17
+ elsif exclude_stacks.nil?
18
+ include_stacks.include?(@stack_name)
18
19
  else
19
- stacks = include_stacks - ignore_stacks
20
+ stacks = include_stacks - exclude_stacks
20
21
  stacks.include?(@stack_name)
21
22
  end
22
23
  end
23
24
 
25
+ def include_stacks
26
+ if config.all.include_stacks
27
+ config_name = "config.all.include_stacks"
28
+ config_value = config.dig(:all, :include_stacks)
29
+ elsif config.all.consider_allow_deny_stacks
30
+ config_name = "config.allow.stacks"
31
+ config_value = config.dig(:allow, :stacks)
32
+ else
33
+ return
34
+ end
35
+ callable_option(
36
+ config_name: config_name,
37
+ config_value: config_value,
38
+ passed_args: [@stack_name],
39
+ )
40
+ end
41
+
42
+ def exclude_stacks
43
+ if config.all.exclude_stacks
44
+ config_name = "config.all.exclude_stacks"
45
+ config_value = config.dig(:all, :exclude_stacks)
46
+ elsif config.all.consider_allow_deny_stacks
47
+ config_name = "config.deny.stacks"
48
+ config_value = config.dig(:deny, :stacks)
49
+ else
50
+ return
51
+ end
52
+ callable_option(
53
+ config_name: config_name,
54
+ config_value: config_value,
55
+ passed_args: [@stack_name],
56
+ )
57
+ end
58
+
59
+ private
60
+ def config
61
+ Terraspace.config
62
+ end
63
+
24
64
  def extract_stack_name(path)
25
65
  path.sub(%r{.*(app|vendor)/stacks/}, '')
26
66
  end
67
+
68
+ @@ignore_stacks_deprecation_warning = nil
69
+ def ignore_stacks_deprecation_warning
70
+ return unless config.all.ignore_stacks
71
+ return if @@ignore_stacks_deprecation_warning
72
+ puts <<~EOL.color(:yellow)
73
+ DEPRECATED: config.all.ignore_stacks
74
+ Instead use: config.all.exclude_stacks
75
+ EOL
76
+ @@ignore_stacks_deprecation_warning = true
77
+ end
27
78
  end
28
79
  end
@@ -1,3 +1,3 @@
1
1
  module Terraspace
2
- VERSION = "1.0.1"
2
+ VERSION = "1.0.5"
3
3
  end
data/terraspace.gemspec CHANGED
@@ -31,13 +31,13 @@ Gem::Specification.new do |spec|
31
31
  spec.add_dependency "rainbow"
32
32
  spec.add_dependency "render_me_pretty"
33
33
  spec.add_dependency "rexml"
34
- spec.add_dependency "terraspace-bundler", "~> 0.4.4"
34
+ spec.add_dependency "terraspace-bundler", ">= 0.5.0"
35
35
  spec.add_dependency "thor"
36
36
  spec.add_dependency "tty-tree"
37
37
  spec.add_dependency "zeitwerk"
38
38
 
39
39
  # core baseline plugins
40
- spec.add_dependency "rspec-terraspace", "~> 0.3.0"
40
+ spec.add_dependency "rspec-terraspace", ">= 0.3.1"
41
41
 
42
42
  spec.add_development_dependency "bundler"
43
43
  spec.add_development_dependency "byebug"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: terraspace
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tung Nguyen
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-01-15 00:00:00.000000000 Z
11
+ date: 2022-01-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -196,16 +196,16 @@ dependencies:
196
196
  name: terraspace-bundler
197
197
  requirement: !ruby/object:Gem::Requirement
198
198
  requirements:
199
- - - "~>"
199
+ - - ">="
200
200
  - !ruby/object:Gem::Version
201
- version: 0.4.4
201
+ version: 0.5.0
202
202
  type: :runtime
203
203
  prerelease: false
204
204
  version_requirements: !ruby/object:Gem::Requirement
205
205
  requirements:
206
- - - "~>"
206
+ - - ">="
207
207
  - !ruby/object:Gem::Version
208
- version: 0.4.4
208
+ version: 0.5.0
209
209
  - !ruby/object:Gem::Dependency
210
210
  name: thor
211
211
  requirement: !ruby/object:Gem::Requirement
@@ -252,16 +252,16 @@ dependencies:
252
252
  name: rspec-terraspace
253
253
  requirement: !ruby/object:Gem::Requirement
254
254
  requirements:
255
- - - "~>"
255
+ - - ">="
256
256
  - !ruby/object:Gem::Version
257
- version: 0.3.0
257
+ version: 0.3.1
258
258
  type: :runtime
259
259
  prerelease: false
260
260
  version_requirements: !ruby/object:Gem::Requirement
261
261
  requirements:
262
- - - "~>"
262
+ - - ">="
263
263
  - !ruby/object:Gem::Version
264
- version: 0.3.0
264
+ version: 0.3.1
265
265
  - !ruby/object:Gem::Dependency
266
266
  name: bundler
267
267
  requirement: !ruby/object:Gem::Requirement
@@ -478,12 +478,18 @@ files:
478
478
  - lib/terraspace/all/runner.rb
479
479
  - lib/terraspace/all/summary.rb
480
480
  - lib/terraspace/app.rb
481
+ - lib/terraspace/app/callable_option.rb
482
+ - lib/terraspace/app/callable_option/concern.rb
481
483
  - lib/terraspace/app/inits.rb
482
484
  - lib/terraspace/autodetect.rb
483
485
  - lib/terraspace/autoloader.rb
484
486
  - lib/terraspace/booter.rb
485
487
  - lib/terraspace/builder.rb
486
488
  - lib/terraspace/builder/allow.rb
489
+ - lib/terraspace/builder/allow/base.rb
490
+ - lib/terraspace/builder/allow/env.rb
491
+ - lib/terraspace/builder/allow/region.rb
492
+ - lib/terraspace/builder/allow/stack.rb
487
493
  - lib/terraspace/bundle.rb
488
494
  - lib/terraspace/cli.rb
489
495
  - lib/terraspace/cli/all.rb