terraspace 0.4.2 → 0.5.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/.cody/aws/bin/build.sh +2 -2
  3. data/.cody/azurerm/bin/build.sh +2 -2
  4. data/.cody/google/bin/build.sh +2 -2
  5. data/.github/ISSUE_TEMPLATE.md +1 -1
  6. data/CHANGELOG.md +31 -0
  7. data/README.md +4 -3
  8. data/lib/templates/base/arg/terraform.rb.tt +3 -0
  9. data/lib/templates/base/helper/%name%_helper.rb.tt +2 -0
  10. data/lib/templates/base/hook/%kind%.rb.tt +7 -0
  11. data/lib/terraspace.rb +7 -4
  12. data/lib/terraspace/all/base.rb +0 -1
  13. data/lib/terraspace/app.rb +1 -0
  14. data/lib/terraspace/autoloader.rb +16 -1
  15. data/lib/terraspace/bundle.rb +6 -0
  16. data/lib/terraspace/cli.rb +1 -0
  17. data/lib/terraspace/cli/bundle.rb +0 -1
  18. data/lib/terraspace/cli/check_setup.rb +5 -0
  19. data/lib/terraspace/cli/clean/base.rb +0 -1
  20. data/lib/terraspace/cli/clean/cache.rb +0 -1
  21. data/lib/terraspace/cli/cloud.rb +2 -0
  22. data/lib/terraspace/cli/help/new/arg.md +19 -0
  23. data/lib/terraspace/cli/help/new/helper.md +39 -0
  24. data/lib/terraspace/cli/help/new/hook.md +25 -0
  25. data/lib/terraspace/cli/help/new/test.md +34 -0
  26. data/lib/terraspace/cli/info.rb +12 -0
  27. data/lib/terraspace/cli/new.rb +22 -16
  28. data/lib/terraspace/cli/new/arg.rb +62 -0
  29. data/lib/terraspace/cli/new/helper.rb +44 -12
  30. data/lib/terraspace/cli/new/helpers.rb +22 -0
  31. data/lib/terraspace/cli/new/helpers/plugin_gem.rb +25 -0
  32. data/lib/terraspace/cli/new/hook.rb +70 -0
  33. data/lib/terraspace/cli/new/module.rb +0 -11
  34. data/lib/terraspace/cli/new/plugin.rb +4 -4
  35. data/lib/terraspace/cli/new/plugin/helper.rb +1 -1
  36. data/lib/terraspace/cli/new/project.rb +16 -7
  37. data/lib/terraspace/cli/new/sequence.rb +3 -10
  38. data/lib/terraspace/cli/new/source/core.rb +1 -1
  39. data/lib/terraspace/cli/new/stack.rb +1 -12
  40. data/lib/terraspace/cli/new/test.rb +50 -0
  41. data/lib/terraspace/cli/summary.rb +0 -1
  42. data/lib/terraspace/command.rb +50 -0
  43. data/lib/terraspace/compiler/builder.rb +2 -0
  44. data/lib/terraspace/compiler/dsl/mod.rb +2 -0
  45. data/lib/terraspace/compiler/dsl/syntax/mod.rb +2 -0
  46. data/lib/terraspace/compiler/dsl/syntax/mod/backend.rb +1 -1
  47. data/lib/terraspace/compiler/erb/context.rb +2 -0
  48. data/lib/terraspace/compiler/helper_extender.rb +27 -0
  49. data/lib/terraspace/core.rb +0 -6
  50. data/lib/terraspace/ext/core/module.rb +16 -0
  51. data/lib/terraspace/hooks/builder.rb +6 -7
  52. data/lib/terraspace/hooks/concern.rb +2 -2
  53. data/lib/terraspace/logger.rb +6 -0
  54. data/lib/terraspace/mod.rb +0 -1
  55. data/lib/terraspace/plugin.rb +8 -4
  56. data/lib/terraspace/plugin/config/interface.rb +2 -2
  57. data/lib/terraspace/plugin/helper/interface.rb +31 -0
  58. data/lib/terraspace/shell.rb +5 -33
  59. data/lib/terraspace/shell/error.rb +46 -0
  60. data/lib/terraspace/terraform/args/custom.rb +2 -3
  61. data/lib/terraspace/terraform/runner.rb +5 -13
  62. data/lib/terraspace/terraform/runner/retryer.rb +69 -0
  63. data/lib/terraspace/version.rb +1 -1
  64. data/spec/terraspace/terraform/args/custom_spec.rb +6 -4
  65. data/terraspace.gemspec +4 -4
  66. metadata +29 -21
  67. data/lib/terraspace/cli/help/new/bootstrap_test.md +0 -8
  68. data/lib/terraspace/cli/help/new/module_test.md +0 -12
  69. data/lib/terraspace/cli/help/new/project_test.md +0 -8
  70. data/lib/terraspace/cli/new/helper/plugin_gem.rb +0 -12
  71. data/lib/terraspace/cli/new/test/base.rb +0 -17
  72. data/lib/terraspace/cli/new/test/bootstrap.rb +0 -18
  73. data/lib/terraspace/cli/new/test/module.rb +0 -15
  74. data/lib/terraspace/cli/new/test/project.rb +0 -15
@@ -1,5 +1,9 @@
1
1
  class Terraspace::CLI
2
2
  class New < Terraspace::Command
3
+ long_desc Help.text("new/arg")
4
+ Arg.options.each { |args| option(*args) }
5
+ register(Arg, "arg", "arg NAME", "Generates new arg.")
6
+
3
7
  long_desc Help.text("new/git_hook")
4
8
  GitHook.cli_options.each { |args| option(*args) }
5
9
  register(GitHook, "git_hook", "git_hook", "Generates new git hook.")
@@ -8,33 +12,35 @@ class Terraspace::CLI
8
12
  Shim.cli_options.each { |args| option(*args) }
9
13
  register(Shim, "shim", "shim", "Generates terraspace shim.")
10
14
 
15
+ long_desc Help.text("new/helper")
16
+ Helper.options.each { |args| option(*args) }
17
+ register(Helper, "helper", "helper NAME", "Generates new helper.")
18
+
19
+ long_desc Help.text("new/hook")
20
+ Hook.options.each { |args| option(*args) }
21
+ register(Hook, "hook", "hook NAME", "Generates new hook.")
22
+
11
23
  long_desc Help.text("new/module")
12
24
  Module.base_options.each { |args| option(*args) }
13
25
  Module.component_options.each { |args| option(*args) }
14
26
  register(Module, "module", "module NAME", "Generates new module.")
15
27
 
16
- long_desc Help.text("new/stack")
17
- Stack.base_options.each { |args| option(*args) }
18
- Stack.component_options.each { |args| option(*args) }
19
- register(Stack, "stack", "stack NAME", "Generates new stack.")
20
-
21
28
  long_desc Help.text("new/project")
22
29
  Project.base_options.each { |args| option(*args) }
23
30
  Project.project_options.each { |args| option(*args) }
24
31
  register(Project, "project", "project NAME", "Generates new project.")
25
32
 
26
- long_desc Help.text("new/project_test")
27
- register(Test::Project, "project_test", "project_test NAME", "Generates new project test.")
28
-
29
- long_desc Help.text("new/module_test")
30
- register(Test::Module, "module_test", "module_test NAME", "Generates new module test.")
31
-
32
- long_desc Help.text("new/bootstrap_test")
33
- Test::Bootstrap.options.each { |args| option(*args) }
34
- register(Test::Bootstrap, "bootstrap_test", "bootstrap_test", "Generates bootstrap test setup.")
35
-
36
33
  long_desc Help.text("new/plugin")
37
34
  Plugin.options.each { |args| option(*args) }
38
- register(Plugin, "plugin", "plugin", "Generates plugin.")
35
+ register(Plugin, "plugin", "plugin NAME", "Generates plugin.")
36
+
37
+ long_desc Help.text("new/stack")
38
+ Stack.base_options.each { |args| option(*args) }
39
+ Stack.component_options.each { |args| option(*args) }
40
+ register(Stack, "stack", "stack NAME", "Generates new stack.")
41
+
42
+ long_desc Help.text("new/test")
43
+ Test.options.each { |args| option(*args) }
44
+ register(Test, "test", "test NAME", "Generates new test.")
39
45
  end
40
46
  end
@@ -0,0 +1,62 @@
1
+ class Terraspace::CLI::New
2
+ class Arg < 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
+ [:name, default: "apply", desc: "command name"],
11
+ [:type, default: "project", desc: "project, stack or module"],
12
+ ]
13
+ end
14
+ options.each { |args| class_option(*args) }
15
+
16
+ def self.source_root
17
+ File.expand_path("../../../templates/base/arg", __dir__)
18
+ end
19
+
20
+ private
21
+ def type
22
+ valid_types = %w[project stack module]
23
+ type = @options[:type]
24
+ valid_types.include?(type) ? type : "project" # fallback to project if user provides invalid type
25
+ end
26
+
27
+ def name
28
+ options[:name] ? options[:name] : "apply"
29
+ end
30
+
31
+ def dest
32
+ map = {
33
+ project: "config/args",
34
+ stack: "app/stacks/#{stack}/config/args",
35
+ module: "app/modules/#{stack}/config/args",
36
+ }
37
+ map[type.to_sym]
38
+ end
39
+
40
+ def arg_path
41
+ "#{dest}/#{kind}.rb"
42
+ end
43
+
44
+ public
45
+
46
+ def check_stack_arg
47
+ return if type == "project"
48
+ return unless stack.nil?
49
+ # Else check for STACK argument for type module or stack
50
+ puts <<~EOL
51
+ Required STACK argument, either the module or stack name. Usage:
52
+
53
+ terraspace new arg STACK --type #{type}
54
+ EOL
55
+ exit 1
56
+ end
57
+
58
+ def create
59
+ directory ".", dest
60
+ end
61
+ end
62
+ end
@@ -1,22 +1,54 @@
1
1
  class Terraspace::CLI::New
2
- module Helper
3
- include Helper::PluginGem
2
+ class Helper < Thor::Group
3
+ include Thor::Actions
4
+
5
+ argument :stack
6
+
7
+ def self.options
8
+ [
9
+ [:force, aliases: %w[y], type: :boolean, desc: "Bypass overwrite are you sure prompt for existing files"],
10
+ [:name, desc: "Helper name used for the filename. Defaults to the project, module or stack name"],
11
+ [:type, default: "project", desc: "project, stack or module"],
12
+ ]
13
+ end
14
+ options.each { |args| class_option(*args) }
15
+
16
+ def self.source_root
17
+ File.expand_path("../../../templates/base/helper", __dir__)
18
+ end
4
19
 
5
20
  private
6
- def build_gemfile(*list)
7
- lines = []
8
- list.each do |name|
9
- lines << gem_line(name)
10
- end
11
- lines.join("\n")
21
+ def type
22
+ valid_types = %w[project stack module]
23
+ type = @options[:type]
24
+ valid_types.include?(type) ? type : "project" # fallback to project if user provides invalid type
12
25
  end
13
26
 
14
- def gem_line(name)
15
- if name == "terraspace"
16
- %Q|gem "#{name}", '~> #{Terraspace::VERSION}'|
27
+ def helper_class
28
+ if type == "project"
29
+ "Terraspace::#{type.camelize}::#{name.camelize}Helper"
17
30
  else
18
- %Q|gem "#{name}"|
31
+ "Terraspace::#{type.camelize}::#{stack.camelize}::#{name.camelize}Helper"
19
32
  end
20
33
  end
34
+
35
+ def name
36
+ options[:name] || stack
37
+ end
38
+
39
+ def dest
40
+ map = {
41
+ project: "config/helpers",
42
+ stack: "app/stacks/#{stack}/config/helpers",
43
+ module: "app/modules/#{stack}/config/helpers",
44
+ }
45
+ map[type.to_sym]
46
+ end
47
+
48
+ public
49
+
50
+ def create
51
+ directory ".", dest
52
+ end
21
53
  end
22
54
  end
@@ -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 Helper
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")
@@ -1,5 +1,5 @@
1
1
  class Terraspace::CLI::New::Plugin
2
- module Helper
2
+ module Helpers
3
3
  private
4
4
  # helper
5
5
  def camel_name
@@ -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
- [:test_structure, type: :boolean, desc: "Create project bootstrap test structure."]
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
- puts "=> Creating new project called #{name}."
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
- puts "=> Installing dependencies with: bundle install"
70
+ log "=> Installing dependencies with: bundle install"
64
71
  Bundler.with_unbundled_env do
65
- system("BUNDLE_IGNORE_CONFIG=1 bundle install", chdir: name)
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
- puts <<~EOL
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
- puts <<~EOL
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 Helper
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
@@ -1,6 +1,6 @@
1
1
  module Terraspace::CLI::New::Source
2
2
  class Core
3
- include Terraspace::CLI::New::Helper::PluginGem
3
+ include Terraspace::CLI::New::Helpers::PluginGem
4
4
  include Terraspace::Util
5
5
 
6
6
  def initialize(sequence, options)