terraspace 0.4.4 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +15 -0
- data/lib/templates/base/arg/terraform.rb.tt +3 -0
- data/lib/templates/base/helper/%name%_helper.rb.tt +2 -0
- data/lib/templates/base/hook/%kind%.rb.tt +7 -0
- data/lib/terraspace.rb +4 -3
- data/lib/terraspace/all/base.rb +0 -1
- data/lib/terraspace/app.rb +1 -0
- data/lib/terraspace/autoloader.rb +20 -3
- data/lib/terraspace/cli/bundle.rb +0 -1
- data/lib/terraspace/cli/clean/base.rb +0 -1
- data/lib/terraspace/cli/clean/cache.rb +0 -1
- data/lib/terraspace/cli/help/new/arg.md +19 -0
- data/lib/terraspace/cli/help/new/helper.md +39 -0
- data/lib/terraspace/cli/help/new/hook.md +25 -0
- data/lib/terraspace/cli/help/new/test.md +34 -0
- data/lib/terraspace/cli/new.rb +22 -16
- data/lib/terraspace/cli/new/arg.rb +62 -0
- data/lib/terraspace/cli/new/helper.rb +44 -12
- data/lib/terraspace/cli/new/helpers.rb +22 -0
- data/lib/terraspace/cli/new/helpers/plugin_gem.rb +25 -0
- data/lib/terraspace/cli/new/hook.rb +70 -0
- data/lib/terraspace/cli/new/module.rb +0 -11
- data/lib/terraspace/cli/new/plugin.rb +4 -4
- data/lib/terraspace/cli/new/plugin/helper.rb +1 -1
- data/lib/terraspace/cli/new/project.rb +16 -7
- data/lib/terraspace/cli/new/sequence.rb +3 -10
- data/lib/terraspace/cli/new/source/core.rb +1 -1
- data/lib/terraspace/cli/new/stack.rb +1 -12
- data/lib/terraspace/cli/new/test.rb +50 -0
- data/lib/terraspace/cli/summary.rb +0 -1
- data/lib/terraspace/command.rb +16 -0
- data/lib/terraspace/compiler/builder.rb +2 -0
- data/lib/terraspace/compiler/dsl/mod.rb +2 -0
- data/lib/terraspace/compiler/dsl/syntax/mod.rb +2 -0
- data/lib/terraspace/compiler/dsl/syntax/mod/backend.rb +1 -1
- data/lib/terraspace/compiler/erb/context.rb +2 -0
- data/lib/terraspace/compiler/helper_extender.rb +27 -0
- data/lib/terraspace/core.rb +0 -6
- data/lib/terraspace/ext/core/module.rb +16 -0
- data/lib/terraspace/hooks/builder.rb +6 -7
- data/lib/terraspace/hooks/concern.rb +2 -2
- data/lib/terraspace/logger.rb +6 -0
- data/lib/terraspace/mod.rb +0 -1
- data/lib/terraspace/plugin.rb +8 -4
- data/lib/terraspace/plugin/config/interface.rb +2 -2
- data/lib/terraspace/plugin/helper/interface.rb +31 -0
- data/lib/terraspace/terraform/args/custom.rb +2 -3
- data/lib/terraspace/terraform/runner/retryer.rb +7 -3
- data/lib/terraspace/version.rb +1 -1
- data/spec/terraspace/terraform/args/custom_spec.rb +6 -4
- data/terraspace.gemspec +4 -4
- metadata +27 -21
- data/lib/terraspace/cli/help/new/bootstrap_test.md +0 -8
- data/lib/terraspace/cli/help/new/module_test.md +0 -12
- data/lib/terraspace/cli/help/new/project_test.md +0 -8
- data/lib/terraspace/cli/new/helper/plugin_gem.rb +0 -12
- data/lib/terraspace/cli/new/test/base.rb +0 -17
- data/lib/terraspace/cli/new/test/bootstrap.rb +0 -18
- data/lib/terraspace/cli/new/test/module.rb +0 -15
- data/lib/terraspace/cli/new/test/project.rb +0 -15
@@ -0,0 +1,22 @@
|
|
1
|
+
class Terraspace::CLI::New
|
2
|
+
module Helpers
|
3
|
+
include Helpers::PluginGem
|
4
|
+
|
5
|
+
private
|
6
|
+
def build_gemfile(*list)
|
7
|
+
lines = []
|
8
|
+
list.each do |name|
|
9
|
+
lines << gem_line(name)
|
10
|
+
end
|
11
|
+
lines.join("\n")
|
12
|
+
end
|
13
|
+
|
14
|
+
def gem_line(name)
|
15
|
+
if name == "terraspace"
|
16
|
+
%Q|gem "#{name}", '~> #{Terraspace::VERSION}'|
|
17
|
+
else
|
18
|
+
%Q|gem "#{name}"|
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Terraspace::CLI::New::Helpers
|
2
|
+
module PluginGem
|
3
|
+
private
|
4
|
+
def plugin_gem_name
|
5
|
+
if @options[:plugin_gem]
|
6
|
+
@options[:plugin_gem]
|
7
|
+
else
|
8
|
+
plugin = @options[:plugin] || autodetect_provider
|
9
|
+
"terraspace_plugin_#{plugin}"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def autodetect_provider
|
14
|
+
providers = Terraspace::Plugin.meta.keys
|
15
|
+
if providers.size == 1
|
16
|
+
providers.first
|
17
|
+
else
|
18
|
+
precedence = %w[aws azurerm google]
|
19
|
+
precedence.find do |p|
|
20
|
+
providers.include?(p)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
class Terraspace::CLI::New
|
2
|
+
class Hook < Thor::Group
|
3
|
+
include Thor::Actions
|
4
|
+
|
5
|
+
argument :stack, required: false
|
6
|
+
|
7
|
+
def self.options
|
8
|
+
[
|
9
|
+
[:force, aliases: %w[y], type: :boolean, desc: "Bypass overwrite are you sure prompt for existing files"],
|
10
|
+
[:kind, default: "terraform", desc: "terraform or terraspace"],
|
11
|
+
[:name, desc: "Command name. Defaults to apply for terraform kind and build for terraspace kind"],
|
12
|
+
[:type, default: "project", desc: "project, stack or module"],
|
13
|
+
]
|
14
|
+
end
|
15
|
+
options.each { |args| class_option(*args) }
|
16
|
+
|
17
|
+
def self.source_root
|
18
|
+
File.expand_path("../../../templates/base/hook", __dir__)
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
def kind
|
23
|
+
valid_kinds = %w[terraform terraspace]
|
24
|
+
kind = @options[:kind]
|
25
|
+
valid_kinds.include?(kind) ? kind : "terraform" # fallback to terraform if user provides invalid type
|
26
|
+
end
|
27
|
+
|
28
|
+
def type
|
29
|
+
valid_types = %w[project stack module]
|
30
|
+
type = @options[:type]
|
31
|
+
valid_types.include?(type) ? type : "project" # fallback to project if user provides invalid type
|
32
|
+
end
|
33
|
+
|
34
|
+
def name
|
35
|
+
return options[:name] if options[:name]
|
36
|
+
kind == "terraform" ? "apply" : "build"
|
37
|
+
end
|
38
|
+
|
39
|
+
def dest
|
40
|
+
map = {
|
41
|
+
project: "config/hooks",
|
42
|
+
stack: "app/stacks/#{stack}/config/hooks",
|
43
|
+
module: "app/modules/#{stack}/config/hooks",
|
44
|
+
}
|
45
|
+
map[type.to_sym]
|
46
|
+
end
|
47
|
+
|
48
|
+
def hook_path
|
49
|
+
"#{dest}/#{kind}.rb"
|
50
|
+
end
|
51
|
+
|
52
|
+
public
|
53
|
+
|
54
|
+
def check_stack_arg
|
55
|
+
return if type == "project"
|
56
|
+
return unless stack.nil?
|
57
|
+
# Else check for STACK argument for type module or stack
|
58
|
+
puts <<~EOL
|
59
|
+
Required STACK argument, either the module or stack name. Usage:
|
60
|
+
|
61
|
+
terraspace new hook STACK --type #{type}
|
62
|
+
EOL
|
63
|
+
exit 1
|
64
|
+
end
|
65
|
+
|
66
|
+
def create
|
67
|
+
directory ".", dest
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -11,16 +11,5 @@ class Terraspace::CLI::New
|
|
11
11
|
dest = "#{@options[:project_name]}/#{dest}" if @options[:project_name]
|
12
12
|
directory ".", dest
|
13
13
|
end
|
14
|
-
|
15
|
-
def create_test
|
16
|
-
args = component_args(name, @options[:project_name])
|
17
|
-
Test::Module.start(args)
|
18
|
-
end
|
19
|
-
|
20
|
-
def run_generator_hook_script
|
21
|
-
script = ENV['TS_GENERATOR_MODULE']
|
22
|
-
return unless script
|
23
|
-
run_script(script, "app/modules/#{name}")
|
24
|
-
end
|
25
14
|
end
|
26
15
|
end
|
@@ -1,16 +1,16 @@
|
|
1
1
|
class Terraspace::CLI::New
|
2
2
|
class Plugin < Sequence
|
3
|
-
include
|
3
|
+
include Helpers
|
4
|
+
|
5
|
+
argument :name
|
4
6
|
|
5
7
|
def self.options
|
6
8
|
[
|
7
|
-
[:force, type: :boolean, desc: "Bypass overwrite are you sure prompt for existing files"],
|
9
|
+
[:force, aliases: %w[y], type: :boolean, desc: "Bypass overwrite are you sure prompt for existing files"],
|
8
10
|
]
|
9
11
|
end
|
10
12
|
options.each { |args| class_option(*args) }
|
11
13
|
|
12
|
-
argument :name
|
13
|
-
|
14
14
|
def create_plugin
|
15
15
|
puts "=> Creating new plugin: #{name}"
|
16
16
|
core_template_source("plugin")
|
@@ -4,16 +4,23 @@ class Terraspace::CLI::New
|
|
4
4
|
[
|
5
5
|
[:bundle, type: :boolean, default: true, desc: "Runs bundle install on the project"],
|
6
6
|
[:config, type: :boolean, default: true, desc: "Whether or not to generate config files."],
|
7
|
-
[:force, type: :boolean, desc: "Bypass overwrite are you sure prompt for existing files."],
|
8
|
-
[:
|
7
|
+
[:force, aliases: %w[y], type: :boolean, desc: "Bypass overwrite are you sure prompt for existing files."],
|
8
|
+
[:quiet, type: :boolean, desc: "Quiet output."],
|
9
|
+
[:test_structure, type: :boolean, desc: "Create project bootstrap test structure."],
|
9
10
|
]
|
10
11
|
end
|
11
12
|
|
12
13
|
base_options.each { |args| class_option(*args) }
|
13
14
|
project_options.each { |args| class_option(*args) }
|
14
15
|
|
16
|
+
private
|
17
|
+
def log(msg)
|
18
|
+
logger.info(msg) unless @options[:quiet]
|
19
|
+
end
|
20
|
+
|
21
|
+
public
|
15
22
|
def creating_messaging
|
16
|
-
|
23
|
+
log "=> Creating new project called #{name}."
|
17
24
|
end
|
18
25
|
|
19
26
|
def create_base
|
@@ -60,15 +67,17 @@ class Terraspace::CLI::New
|
|
60
67
|
|
61
68
|
def bundle_install
|
62
69
|
return if @options[:bundle] == false
|
63
|
-
|
70
|
+
log "=> Installing dependencies with: bundle install"
|
64
71
|
Bundler.with_unbundled_env do
|
65
|
-
|
72
|
+
bundle = "BUNDLE_IGNORE_CONFIG=1 bundle install"
|
73
|
+
bundle << " > /dev/null 2>&1" if @options[:quiet]
|
74
|
+
system(bundle, chdir: name)
|
66
75
|
end
|
67
76
|
end
|
68
77
|
|
69
78
|
def welcome_message_examples
|
70
79
|
return unless options[:examples]
|
71
|
-
|
80
|
+
log <<~EOL
|
72
81
|
#{"="*64}
|
73
82
|
Congrats! You have successfully created a terraspace project.
|
74
83
|
Check out the created files. Adjust to the examples and then deploy with:
|
@@ -83,7 +92,7 @@ class Terraspace::CLI::New
|
|
83
92
|
|
84
93
|
def welcome_message_no_examples
|
85
94
|
return if options[:examples]
|
86
|
-
|
95
|
+
log <<~EOL
|
87
96
|
#{"="*64}
|
88
97
|
Congrats! You have successfully created a terraspace project.
|
89
98
|
Check out the created files.
|
@@ -3,12 +3,13 @@ require 'thor'
|
|
3
3
|
class Terraspace::CLI::New
|
4
4
|
class Sequence < Thor::Group
|
5
5
|
include Thor::Actions
|
6
|
-
include
|
6
|
+
include Terraspace::Util::Logging
|
7
|
+
include Helpers
|
7
8
|
|
8
9
|
def self.base_options
|
9
10
|
[
|
10
11
|
[:examples, type: :boolean, default: false, desc: "Also generate examples"],
|
11
|
-
[:force, type: :boolean, desc: "Bypass overwrite are you sure prompt for existing files"],
|
12
|
+
[:force, aliases: %w[y], type: :boolean, desc: "Bypass overwrite are you sure prompt for existing files"],
|
12
13
|
[:lang, default: "hcl", desc: "Language to use: HCL/ERB or Ruby DSL"],
|
13
14
|
[:plugin, aliases: %w[p], default: "aws", desc: "Cloud Plugin. Supports: aws, google"],
|
14
15
|
[:test, type: :boolean, desc: "Whether or not to generate tests"],
|
@@ -47,13 +48,5 @@ class Terraspace::CLI::New
|
|
47
48
|
source = Source::Plugin.new(self, @options)
|
48
49
|
source.set_source_paths(template, type)
|
49
50
|
end
|
50
|
-
|
51
|
-
# A generator script hook to allow for further customizations
|
52
|
-
# The dest folder like app/modules/demo is provided as a first argument to the command.
|
53
|
-
def run_script(script, dest)
|
54
|
-
command = "#{script} #{dest}"
|
55
|
-
puts "Running: #{command}" unless ENV['TS_GENERATOR_MUTE']
|
56
|
-
system(command)
|
57
|
-
end
|
58
51
|
end
|
59
52
|
end
|
@@ -5,22 +5,11 @@ class Terraspace::CLI::New
|
|
5
5
|
argument :name
|
6
6
|
|
7
7
|
def create_stack
|
8
|
-
plugin_template_source(@options[:lang], "stack") # IE: plugin_template_source("hcl", "stack")
|
9
|
-
|
10
8
|
puts "=> Creating new stack called #{name}."
|
9
|
+
plugin_template_source(@options[:lang], "stack") # IE: plugin_template_source("hcl", "stack")
|
11
10
|
dest = "app/stacks/#{name}"
|
12
11
|
dest = "#{@options[:project_name]}/#{dest}" if @options[:project_name]
|
13
12
|
directory ".", dest
|
14
13
|
end
|
15
|
-
|
16
|
-
def create_test
|
17
|
-
Test::Project.start(component_args(name, @options[:project_name]))
|
18
|
-
end
|
19
|
-
|
20
|
-
def run_generator_hook_script
|
21
|
-
script = ENV['TS_GENERATOR_STACK']
|
22
|
-
return unless script
|
23
|
-
run_script(script, "app/stacks/#{name}")
|
24
|
-
end
|
25
14
|
end
|
26
15
|
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
class Terraspace::CLI::New
|
2
|
+
class Test < Thor::Group
|
3
|
+
include Thor::Actions
|
4
|
+
include Terraspace::CLI::New::Helpers
|
5
|
+
|
6
|
+
argument :name
|
7
|
+
|
8
|
+
def self.options
|
9
|
+
[
|
10
|
+
[:force, aliases: %w[y], type: :boolean, desc: "Bypass overwrite are you sure prompt for existing files"],
|
11
|
+
[:test_name, desc: "Test name. Defaults to the project, module or stack name"],
|
12
|
+
[:type, default: "project", desc: "project, stack or module"],
|
13
|
+
]
|
14
|
+
end
|
15
|
+
options.each { |args| class_option(*args) }
|
16
|
+
|
17
|
+
private
|
18
|
+
def type
|
19
|
+
valid_types = %w[project stack module]
|
20
|
+
type = @options[:type]
|
21
|
+
valid_types.include?(type) ? type : "project" # fallback to project if user provides invalid type
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_name
|
25
|
+
options[:test_name] || name
|
26
|
+
end
|
27
|
+
|
28
|
+
def dest
|
29
|
+
map = {
|
30
|
+
project: ".", # Terraspace.root
|
31
|
+
stack: "app/stacks/#{name}",
|
32
|
+
module: "app/modules/#{name}",
|
33
|
+
}
|
34
|
+
map[type.to_sym]
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_template_source(template, type)
|
38
|
+
source = Terraspace::CLI::New::Source::Test.new(self, @options)
|
39
|
+
source.set_source_paths(template, type)
|
40
|
+
end
|
41
|
+
|
42
|
+
public
|
43
|
+
|
44
|
+
def create
|
45
|
+
test_template_source(@options[:lang], type)
|
46
|
+
puts "=> Creating #{type} test: #{name}"
|
47
|
+
directory ".", dest
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
data/lib/terraspace/command.rb
CHANGED
@@ -27,7 +27,11 @@ Thor::Util.singleton_class.prepend(ThorPrepend::Util)
|
|
27
27
|
module Terraspace
|
28
28
|
class Command < Thor
|
29
29
|
class << self
|
30
|
+
include Terraspace::Util::Logging
|
31
|
+
|
30
32
|
def dispatch(m, args, options, config)
|
33
|
+
check_project!(args.first)
|
34
|
+
|
31
35
|
# Allow calling for help via:
|
32
36
|
# terraspace command help
|
33
37
|
# terraspace command -h
|
@@ -54,6 +58,18 @@ module Terraspace
|
|
54
58
|
super
|
55
59
|
end
|
56
60
|
|
61
|
+
def check_project!(command_name)
|
62
|
+
return if subcommand?
|
63
|
+
return if %w[-h -v completion completion_script help new test version].include?(command_name)
|
64
|
+
return if File.exist?("#{Terraspace.root}/config/app.rb")
|
65
|
+
logger.error "ERROR: It doesnt look like this is a terraspace project. Are you sure you are in a terraspace project?".color(:red)
|
66
|
+
ENV['TS_TEST'] ? raise : exit(1)
|
67
|
+
end
|
68
|
+
|
69
|
+
def subcommand?
|
70
|
+
!!caller.detect { |l| l.include?('in subcommand') }
|
71
|
+
end
|
72
|
+
|
57
73
|
# Override command_help to include the description at the top of the
|
58
74
|
# long_description.
|
59
75
|
def command_help(shell, command_name)
|
@@ -73,6 +73,8 @@ module Terraspace::Compiler
|
|
73
73
|
def skip?(src_path)
|
74
74
|
return true unless File.file?(src_path)
|
75
75
|
# certain folders will be skipped
|
76
|
+
src_path.include?("#{@mod.root}/config/args") ||
|
77
|
+
src_path.include?("#{@mod.root}/config/hooks") ||
|
76
78
|
src_path.include?("#{@mod.root}/test")
|
77
79
|
end
|
78
80
|
end
|
@@ -11,7 +11,7 @@ module Terraspace::Compiler::Dsl::Syntax::Mod
|
|
11
11
|
Terraspace::Compiler::Expander.new(@mod, backend_name).expand(props)
|
12
12
|
end
|
13
13
|
|
14
|
-
# Can set opts to explicitly use an
|
14
|
+
# Can set opts to explicitly use an specific backend. Example:
|
15
15
|
#
|
16
16
|
# opts = {backend: s3}
|
17
17
|
#
|
@@ -1,11 +1,13 @@
|
|
1
1
|
module Terraspace::Compiler::Erb
|
2
2
|
class Context
|
3
3
|
include Helpers
|
4
|
+
include Terraspace::Compiler::HelperExtender
|
4
5
|
|
5
6
|
attr_reader :mod, :options
|
6
7
|
def initialize(mod)
|
7
8
|
@mod = mod
|
8
9
|
@options = mod.options # so user has access to cli options
|
10
|
+
extend_module_level_helpers
|
9
11
|
end
|
10
12
|
end
|
11
13
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Terraspace::Compiler
|
2
|
+
module HelperExtender
|
3
|
+
private
|
4
|
+
def extend_module_level_helpers
|
5
|
+
full_dir = "#{@mod.root}/config/helpers"
|
6
|
+
Dir.glob("#{full_dir}/**/*").each do |path|
|
7
|
+
regexp = Regexp.new(".*/helpers/")
|
8
|
+
klass = path.sub(regexp, '').sub('.rb','').camelize
|
9
|
+
klass = "#{mod_namespace}::#{klass}"
|
10
|
+
require path # able to use require instead of load since each helper has unique namespace
|
11
|
+
send :extend, klass.constantize
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# IE: mod_namespace = Terraspace::Module::Demo
|
16
|
+
# Use separate namespaces scope with module name so custom helper methods from different modules are isolated.
|
17
|
+
def mod_namespace
|
18
|
+
mod_name = @mod.name.camelize
|
19
|
+
ns = "Terraspace::#{@mod.type.camelize}".constantize # IE: Terraspace::Module or Terraspace::Stack
|
20
|
+
if ns.const_defined?(mod_name.to_sym)
|
21
|
+
"#{ns}::#{mod_name}".constantize
|
22
|
+
else
|
23
|
+
ns.const_set(mod_name, Module.new)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|