terraspace 1.0.2 → 1.0.6
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 +4 -4
- data/CHANGELOG.md +12 -0
- data/lib/terraspace/app/callable_option/concern.rb +12 -0
- data/lib/terraspace/app/callable_option.rb +58 -0
- data/lib/terraspace/app.rb +14 -2
- data/lib/terraspace/autodetect.rb +3 -7
- data/lib/terraspace/booter.rb +1 -1
- data/lib/terraspace/builder/allow/base.rb +59 -0
- data/lib/terraspace/builder/allow/env.rb +17 -0
- data/lib/terraspace/builder/allow/region.rb +31 -0
- data/lib/terraspace/builder/allow/stack.rb +17 -0
- data/lib/terraspace/builder/allow.rb +3 -33
- data/lib/terraspace/compiler/expander/backend.rb +1 -1
- data/lib/terraspace/compiler/expander.rb +38 -14
- data/lib/terraspace/compiler/select.rb +61 -10
- data/lib/terraspace/version.rb +1 -1
- metadata +8 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 57c0c4f1c1fce5c1dd8fcd7447f5bc5a82e17d66e5353f4d092d492c137021e5
|
4
|
+
data.tar.gz: 81a4ba08410e898a1dd057625ca556392e746c4b48a3453874472c60424c3949
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e629795fd75ad23d343ec28390e76756650f11740c6b380ad3df87cb216f7a998acfea282ebb1a1399343c3db2b5abe452705bb82fd61e76a8cd1a2ca258300b
|
7
|
+
data.tar.gz: 7104217cb56ee3ba2317d4d2abe0d4f760fe35de359903349a97bef4c2de3c92aaff3e0605789fd9e970f8a841a2203dedc9d740d9bddf127d2555a3f3818f30
|
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.6] - 2022-01-24
|
7
|
+
- [#195](https://github.com/boltops-tools/terraspace/pull/195) improve autodetection for plugin expander for backend like remote
|
8
|
+
|
9
|
+
## [1.0.5] - 2022-01-23
|
10
|
+
- [#194](https://github.com/boltops-tools/terraspace/pull/194) ability to allow and deny envs, regions, and stacks
|
11
|
+
|
12
|
+
## [1.0.4] - 2022-01-21
|
13
|
+
- [#193](https://github.com/boltops-tools/terraspace/pull/193) improve all include_stacks and exclude_stacks option
|
14
|
+
|
15
|
+
## [1.0.3] - 2022-01-20
|
16
|
+
- [#192](https://github.com/boltops-tools/terraspace/pull/192) run super-early boot hooks before dotenv load
|
17
|
+
|
6
18
|
## [1.0.2] - 2022-01-17
|
7
19
|
- [#190](https://github.com/boltops-tools/terraspace/pull/190) update terraspace-bundler gem depedency to 0.5.0
|
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
|
data/lib/terraspace/app.rb
CHANGED
@@ -12,17 +12,29 @@ 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
|
-
|
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
|
36
|
+
config.autodetect = ActiveSupport::OrderedOptions.new
|
37
|
+
config.autodetect.expander = nil
|
26
38
|
config.build = ActiveSupport::OrderedOptions.new
|
27
39
|
config.build.cache_dir = ":CACHE_ROOT/:REGION/:ENV/:BUILD_DIR"
|
28
40
|
config.build.cache_root = nil # defaults to /full/path/to/.terraspace-cache
|
@@ -2,13 +2,9 @@ module Terraspace
|
|
2
2
|
class Autodetect
|
3
3
|
def plugin
|
4
4
|
plugins = Terraspace::Plugin.meta.keys
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
precedence = %w[aws azurerm google]
|
9
|
-
precedence.find do |p|
|
10
|
-
plugins.include?(p)
|
11
|
-
end
|
5
|
+
precedence = %w[aws azurerm google]
|
6
|
+
precedence.find do |p|
|
7
|
+
plugins.include?(p)
|
12
8
|
end
|
13
9
|
end
|
14
10
|
end
|
data/lib/terraspace/booter.rb
CHANGED
@@ -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
|
-
|
9
|
-
|
10
|
-
|
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
|
@@ -3,8 +3,8 @@ module Terraspace::Compiler
|
|
3
3
|
extend Memoist
|
4
4
|
delegate :expand, :expansion, to: :expander
|
5
5
|
|
6
|
-
def initialize(mod,
|
7
|
-
@mod, @
|
6
|
+
def initialize(mod, backend=nil)
|
7
|
+
@mod, @backend = mod, backend
|
8
8
|
end
|
9
9
|
|
10
10
|
def expander
|
@@ -12,27 +12,51 @@ module Terraspace::Compiler
|
|
12
12
|
end
|
13
13
|
memoize :expander
|
14
14
|
|
15
|
+
# IE: TerraspacePluginAws::Interfaces::Expander
|
15
16
|
def expander_class
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
17
|
+
class_name = expander_class_name
|
18
|
+
class_name ? class_name.constantize : Terraspace::Plugin::Expander::Generic
|
19
|
+
rescue NameError => e
|
20
|
+
logger.debug "#{e.class}: #{e.message}"
|
20
21
|
Terraspace::Plugin::Expander::Generic
|
21
22
|
end
|
22
23
|
|
24
|
+
def expander_class_name
|
25
|
+
plugin = Terraspace.config.autodetect.expander # contains plugin name. IE: aws, azurerm, google
|
26
|
+
if plugin
|
27
|
+
# early return for user override of autodetection
|
28
|
+
return Terraspace::Plugin.klass("Expander", plugin: plugin) # can return nil
|
29
|
+
end
|
30
|
+
|
31
|
+
backend = @backend || parse_backend
|
32
|
+
class_name = Terraspace::Plugin.klass("Expander", backend: backend) # can return nil
|
33
|
+
unless class_name
|
34
|
+
backend = plugin_backend
|
35
|
+
class_name = Terraspace::Plugin.klass("Expander", backend: backend) # can return nil
|
36
|
+
end
|
37
|
+
class_name
|
38
|
+
end
|
39
|
+
|
40
|
+
# autodetect by parsing backend.tf or backend.rb
|
41
|
+
def parse_backend
|
42
|
+
Backend.new(@mod).detect
|
43
|
+
end
|
44
|
+
|
45
|
+
# autodetect by looking up loaded plugins
|
46
|
+
def plugin_backend
|
47
|
+
plugin = Terraspace::Autodetect.new.plugin # IE: aws, azurerm, google
|
48
|
+
if plugin
|
49
|
+
data = Terraspace::Plugin.meta[plugin]
|
50
|
+
data[:backend] # IE: s3, azurerm, gcs
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
23
54
|
class << self
|
24
55
|
extend Memoist
|
25
|
-
|
26
56
|
def autodetect(mod, opts={})
|
27
|
-
|
28
|
-
new(mod, backend)
|
57
|
+
new(mod, opts)
|
29
58
|
end
|
30
59
|
memoize :autodetect
|
31
|
-
|
32
|
-
def find_backend(mod)
|
33
|
-
Backend.new(mod).detect
|
34
|
-
end
|
35
|
-
memoize :find_backend
|
36
60
|
end
|
37
61
|
end
|
38
62
|
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
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
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 -
|
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
|
data/lib/terraspace/version.rb
CHANGED
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.
|
4
|
+
version: 1.0.6
|
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-
|
11
|
+
date: 2022-01-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -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
|