terraspace 0.3.1 → 0.3.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (102) hide show
  1. checksums.yaml +4 -4
  2. data/.cody/aws/bin/build.sh +2 -0
  3. data/.cody/azurerm/bin/build.sh +2 -0
  4. data/.cody/google/bin/build.sh +2 -0
  5. data/CHANGELOG.md +24 -0
  6. data/README.md +2 -2
  7. data/lib/terraspace.rb +2 -0
  8. data/lib/terraspace/all/preview.rb +1 -1
  9. data/lib/terraspace/all/summary.rb +21 -1
  10. data/lib/terraspace/app.rb +1 -0
  11. data/lib/terraspace/builder.rb +3 -6
  12. data/lib/terraspace/cli.rb +25 -25
  13. data/lib/terraspace/cli/all.rb +9 -9
  14. data/lib/terraspace/cli/cloud.rb +3 -9
  15. data/lib/terraspace/cli/cloud/runs.rb +0 -2
  16. data/lib/terraspace/cli/help/all/down.md +32 -0
  17. data/lib/terraspace/cli/help/all/graph.md +21 -0
  18. data/lib/terraspace/cli/help/all/output.md +22 -0
  19. data/lib/terraspace/cli/help/all/plan.md +25 -0
  20. data/lib/terraspace/cli/help/all/providers.md +21 -0
  21. data/lib/terraspace/cli/help/all/refresh.md +17 -0
  22. data/lib/terraspace/cli/help/all/show.md +21 -0
  23. data/lib/terraspace/cli/help/all/up.md +27 -0
  24. data/lib/terraspace/cli/help/all/validate.md +21 -0
  25. data/lib/terraspace/cli/help/build.md +6 -0
  26. data/lib/terraspace/cli/help/bundle.md +9 -5
  27. data/lib/terraspace/cli/help/check_setup.md +9 -0
  28. data/lib/terraspace/cli/help/clean.md +5 -0
  29. data/lib/terraspace/cli/help/cloud/destroy.md +16 -0
  30. data/lib/terraspace/cli/help/cloud/list.md +7 -0
  31. data/lib/terraspace/cli/help/cloud/runs/list.md +3 -3
  32. data/lib/terraspace/cli/help/cloud/runs/prune.md +2 -2
  33. data/lib/terraspace/cli/help/cloud/sync.md +26 -2
  34. data/lib/terraspace/cli/help/console.md +8 -0
  35. data/lib/terraspace/cli/help/down.md +26 -0
  36. data/lib/terraspace/cli/help/info.md +43 -0
  37. data/lib/terraspace/cli/help/init.md +37 -0
  38. data/lib/terraspace/cli/help/list.md +20 -0
  39. data/lib/terraspace/cli/help/log.md +8 -2
  40. data/lib/terraspace/cli/help/logs/remove.md +5 -0
  41. data/lib/terraspace/cli/help/logs/truncate.md +5 -0
  42. data/lib/terraspace/cli/help/new/bootstrap_test.md +8 -0
  43. data/lib/terraspace/cli/help/new/example.md +8 -0
  44. data/lib/terraspace/cli/help/new/git_hook.md +6 -0
  45. data/lib/terraspace/cli/help/new/module.md +9 -0
  46. data/lib/terraspace/cli/help/new/module_test.md +12 -0
  47. data/lib/terraspace/cli/help/new/plugin.md +49 -0
  48. data/lib/terraspace/cli/help/new/project.md +40 -0
  49. data/lib/terraspace/cli/help/new/project_test.md +8 -0
  50. data/lib/terraspace/cli/help/new/shim.md +21 -0
  51. data/lib/terraspace/cli/help/new/stack.md +9 -0
  52. data/lib/terraspace/cli/help/output.md +6 -0
  53. data/lib/terraspace/cli/help/plan.md +29 -0
  54. data/lib/terraspace/cli/help/providers.md +18 -0
  55. data/lib/terraspace/cli/help/refresh.md +11 -0
  56. data/lib/terraspace/cli/help/seed.md +7 -0
  57. data/lib/terraspace/cli/help/show.md +36 -0
  58. data/lib/terraspace/cli/help/summary.md +11 -0
  59. data/lib/terraspace/cli/help/test.md +35 -0
  60. data/lib/terraspace/cli/help/up.md +30 -0
  61. data/lib/terraspace/cli/help/validate.md +9 -0
  62. data/lib/terraspace/cli/info.rb +4 -16
  63. data/lib/terraspace/cli/logs.rb +3 -1
  64. data/lib/terraspace/cli/logs/tasks.rb +13 -1
  65. data/lib/terraspace/cli/new.rb +18 -18
  66. data/lib/terraspace/cli/new/git_hook.rb +4 -1
  67. data/lib/terraspace/cli/new/project.rb +1 -1
  68. data/lib/terraspace/cli/summary.rb +2 -2
  69. data/lib/terraspace/command.rb +1 -1
  70. data/lib/terraspace/compiler/backend.rb +10 -0
  71. data/lib/terraspace/compiler/builder.rb +2 -1
  72. data/lib/terraspace/compiler/commands_concern.rb +18 -0
  73. data/lib/terraspace/compiler/dependencies/helpers.rb +34 -0
  74. data/lib/terraspace/compiler/dsl/syntax/helpers/common.rb +0 -26
  75. data/lib/terraspace/compiler/dsl/syntax/tfvar.rb +1 -0
  76. data/lib/terraspace/compiler/erb/context.rb +1 -1
  77. data/lib/terraspace/compiler/erb/helpers.rb +6 -0
  78. data/lib/terraspace/dependency/graph.rb +2 -1
  79. data/lib/terraspace/dependency/helper/base.rb +7 -0
  80. data/lib/terraspace/dependency/helper/depends_on.rb +12 -0
  81. data/lib/terraspace/dependency/helper/output.rb +11 -0
  82. data/lib/terraspace/plugin/summary/interface.rb +1 -1
  83. data/lib/terraspace/shell.rb +44 -16
  84. data/lib/terraspace/terraform/cloud/runs/lister.rb +0 -2
  85. data/lib/terraspace/terraform/cloud/syncer.rb +2 -2
  86. data/lib/terraspace/terraform/cloud/workspace.rb +0 -9
  87. data/lib/terraspace/terraform/remote_state/fetcher.rb +37 -7
  88. data/lib/terraspace/terraform/remote_state/marker/output.rb +3 -1
  89. data/lib/terraspace/terraform/remote_state/null_object.rb +40 -0
  90. data/lib/terraspace/terraform/remote_state/output_proxy.rb +18 -14
  91. data/lib/terraspace/version.rb +1 -1
  92. data/spec/fixtures/dependencies/app/stacks/a1/tfvars/dev.tfvars +1 -0
  93. data/spec/fixtures/fetcher/c1.json +4 -0
  94. data/spec/terraspace/all/summary_spec.rb +1 -1
  95. data/spec/terraspace/compiler/erb/render_spec.rb +15 -0
  96. data/spec/terraspace/dependency/helper/depends_on_spec.rb +27 -0
  97. data/spec/terraspace/dependency/helper/output_spec.rb +29 -0
  98. data/spec/terraspace/terraform/remote_state/fetcher_spec.rb +108 -27
  99. data/spec/terraspace/terraform/remote_state/marker/output_spec.rb +36 -0
  100. data/spec/terraspace/terraform/remote_state/output_proxy_spec.rb +69 -0
  101. metadata +62 -3
  102. data/lib/terraspace/cli/help/update.md +0 -5
@@ -6,26 +6,39 @@ module Terraspace
6
6
 
7
7
  def initialize(mod, command, options={})
8
8
  @mod, @command, @options = mod, command, options
9
- @init_required, @init_messages = false, ''
9
+ @error_type, @error_messages = nil, ''
10
10
  end
11
11
 
12
12
  # requires @mod to be set
13
+ # quiet useful for RemoteState::Fetcher
13
14
  def run
14
- env = @options[:env] || {}
15
- env.stringify_keys!
16
-
17
- # quiet useful for RemoteState::Fetcher
18
15
  msg = "=> #{@command}"
19
16
  @options[:quiet] ? logger.debug(msg) : logger.info(msg)
20
17
  return if ENV['TS_TEST']
18
+ shell
19
+ end
21
20
 
21
+ def shell
22
+ env = @options[:env] || {}
23
+ env.stringify_keys!
24
+ if @options[:shell] == "system" # terraspace console
25
+ system(env, @command, chdir: @mod.cache_dir)
26
+ else
27
+ popen3(env)
28
+ end
29
+ end
30
+
31
+ def popen3(env)
22
32
  Open3.popen3(env, @command, chdir: @mod.cache_dir) do |stdin, stdout, stderr, wait_thread|
23
33
  mimic_terraform_input(stdin, stdout)
24
34
  while err = stderr.gets
25
- @init_required ||= reinitialization_required?(err)
26
- if @init_required
27
- @init_messages << err
35
+ @error_type ||= known_error_type(err)
36
+ if @error_type
37
+ @error_messages << err
28
38
  else
39
+ # Sometimes may print a "\e[31m\n" which like during dependencies fetcher init
40
+ # suppress it so dont get a bunch of annoying "newlines"
41
+ next if err == "\e[31m\n" && @options[:suppress_error_color]
29
42
  logger.error(err)
30
43
  end
31
44
  end
@@ -35,24 +48,39 @@ module Terraspace
35
48
  end
36
49
  end
37
50
 
51
+ def known_error_type(err)
52
+ if reinitialization_required?(err)
53
+ :reinitialization_required
54
+ elsif bucket_not_found?(err)
55
+ :bucket_not_found
56
+ end
57
+ end
58
+
59
+ def bucket_not_found?(err)
60
+ # Message is included in aws, azurerm, and google. See: https://bit.ly/3iOKDri
61
+ err.include?("Failed to get existing workspaces")
62
+ end
63
+
64
+ def reinitialization_required?(err)
65
+ err.include?("reinitialization required") ||
66
+ err.include?("terraform init") ||
67
+ err.include?("require reinitialization")
68
+ end
69
+
38
70
  def exit_status(status)
39
71
  return if status == 0
40
72
 
41
73
  exit_on_fail = @options[:exit_on_fail].nil? ? true : @options[:exit_on_fail]
42
- if @init_required
43
- raise InitRequiredError.new(@init_messages)
74
+ if @error_type == :reinitialization_required
75
+ raise InitRequiredError.new(@error_messages)
76
+ elsif @error_type == :bucket_not_found
77
+ raise BucketNotFoundError.new(@error_messages)
44
78
  elsif exit_on_fail
45
79
  logger.error "Error running command: #{@command}".color(:red)
46
80
  exit status
47
81
  end
48
82
  end
49
83
 
50
- def reinitialization_required?(err)
51
- err.include?("reinitialization required") ||
52
- err.include?("terraform init") ||
53
- err.include?("require reinitialization")
54
- end
55
-
56
84
  # Terraform doesnt seem to stream the line that prompts with "Enter a value:" when using Open3.popen3
57
85
  # Hack around it by mimicking the "Enter a value:" prompt
58
86
  #
@@ -1,5 +1,3 @@
1
- require 'cli-format'
2
-
3
1
  class Terraspace::Terraform::Cloud::Runs
4
2
  class Lister < Base
5
3
  def run
@@ -12,8 +12,8 @@ module Terraspace::Terraform::Cloud
12
12
  end
13
13
 
14
14
  def mods
15
- mod = @options[:mod]
16
- mod ? [mod] : stack_names
15
+ stacks = @options[:stacks]
16
+ stacks.empty? ? stack_names : stacks
17
17
  end
18
18
 
19
19
  def run_sync(mod)
@@ -20,15 +20,6 @@ module Terraspace::Terraform::Cloud
20
20
  logger.info names.join("\n")
21
21
  end
22
22
 
23
- def setup
24
- build
25
- unless backend.dig('remote','workspaces') # in case called by terraspace down demo -y --destroy-workspace with a non-remote backend
26
- logger.info "ERROR: Workspace not configured in backend.tf"
27
- exit 1
28
- end
29
- init
30
- end
31
-
32
23
  def init
33
24
  Terraspace::CLI::Init.new(@options.merge(calling_command: "cloud-setup")).run
34
25
  end
@@ -1,29 +1,40 @@
1
1
  module Terraspace::Terraform::RemoteState
2
2
  class Fetcher
3
3
  extend Memoist
4
+ include Terraspace::Compiler::CommandsConcern
4
5
  include Terraspace::Util::Logging
5
6
 
6
7
  def initialize(parent, identifier, options={})
7
8
  @parent, @identifier, @options = parent, identifier, options
8
9
  child_name, @output_key = identifier.split('.')
9
10
  @child = Terraspace::Mod.new(child_name)
11
+ @child.resolved = @parent.resolved
10
12
  end
11
13
 
12
14
  def run
13
- validate!
15
+ validate! # check child stack exists
14
16
  pull
15
17
  load
16
18
  end
17
19
 
20
+ # Returns OutputProxy
18
21
  def output
19
22
  run
20
23
  if pull_success?
21
- value = output_value
22
- error = output_error(:key_not_found) unless @outputs.key?(@output_key)
23
- OutputProxy.new(value, @options.merge(error: error))
24
+ pull_success_output
24
25
  else
25
- error = output_error(:state_not_found)
26
- OutputProxy.new(nil, @options.merge(error: error))
26
+ @error_type ||= :state_not_found # could be set to :bucket_not_found by bucket_not_found_error
27
+ error = output_error(@error_type)
28
+ OutputProxy.new(@child, nil, @options.merge(error: error))
29
+ end
30
+ end
31
+
32
+ def pull_success_output
33
+ if @outputs.key?(@output_key)
34
+ OutputProxy.new(@child, output_value, @options)
35
+ else
36
+ error = output_error(:key_not_found)
37
+ OutputProxy.new(@child, nil, @options.merge(error: error))
27
38
  end
28
39
  end
29
40
 
@@ -39,6 +50,8 @@ module Terraspace::Terraform::RemoteState
39
50
  "Output #{@output_key} was not found for the #{@parent.name} tfvars file. Either #{@child.name} stack has not been deployed yet or it does not have this output: #{@output_key}"
40
51
  when :state_not_found
41
52
  "Output #{@output_key} could not be looked up for the #{@parent.name} tfvars file. #{@child.name} stack needs to be deployed"
53
+ when :bucket_not_found
54
+ "The bucket for the backend could not be found"
42
55
  end
43
56
  msg = "(#{msg})"
44
57
  log_message(msg)
@@ -52,7 +65,10 @@ module Terraspace::Terraform::RemoteState
52
65
  logger.info "Downloading tfstate files for dependencies defined in tfvars..." unless @@download_shown || @options[:quiet]
53
66
  @@download_shown = true
54
67
  logger.debug "Downloading tfstate for stack: #{@child.name}"
55
- Terraspace::CLI::Init.new(mod: @child.name, calling_command: "apply", quiet: true).init # init not run, so only init
68
+
69
+ success = init # init not yet run. only run .init directly, not .run. init can completely error and early exit.
70
+ return unless success
71
+
56
72
  FileUtils.mkdir_p(File.dirname(state_path))
57
73
  command = "cd #{@child.cache_dir} && terraform state pull > #{state_path}"
58
74
  logger.debug "=> #{command}"
@@ -67,6 +83,20 @@ module Terraspace::Terraform::RemoteState
67
83
  @@pull_successes[cache_key] = success
68
84
  end
69
85
 
86
+ def init
87
+ Terraspace::CLI::Init.new(mod: @child.name, calling_command: "apply", quiet: true, suppress_error_color: true).init
88
+ true
89
+ rescue Terraspace::BucketNotFoundError # from Terraspace::Shell
90
+ bucket_not_found_error
91
+ false
92
+ end
93
+
94
+ # mimic pull error
95
+ def bucket_not_found_error
96
+ @@pull_successes[cache_key] = false
97
+ @error_type = :bucket_not_found
98
+ end
99
+
70
100
  def load
71
101
  return self unless pull_success?
72
102
 
@@ -8,6 +8,7 @@ module Terraspace::Terraform::RemoteState::Marker
8
8
  @child_name, @output_key = @identifier.split('.')
9
9
  end
10
10
 
11
+ # Returns OutputProxy
11
12
  def build
12
13
  if valid?
13
14
  Terraspace::Dependency::Registry.register(@parent_name, @child_name)
@@ -16,7 +17,7 @@ module Terraspace::Terraform::RemoteState::Marker
16
17
  end
17
18
  # MARKER for debugging. Only appears on 1st pass. Will not see unless changing Terraspace code for debugging.
18
19
  marker = "MARKER:terraform_output('#{@identifier}')"
19
- Terraspace::Terraform::RemoteState::OutputProxy.new(marker, @options)
20
+ Terraspace::Terraform::RemoteState::OutputProxy.new(@mod, marker, @options)
20
21
  end
21
22
 
22
23
  def valid?
@@ -26,6 +27,7 @@ module Terraspace::Terraform::RemoteState::Marker
26
27
  def warning
27
28
  logger.warn "WARN: The #{@child_name} stack does not exist".color(:yellow)
28
29
  caller_line = caller.find { |l| l.include?('.tfvars') }
30
+ return unless caller_line # specs dont have a tfvars file
29
31
  source_code = PrettyTracer.new(caller_line).source_code
30
32
  logger.info source_code
31
33
  end
@@ -0,0 +1,40 @@
1
+ module Terraspace::Terraform::RemoteState
2
+ class NullObject
3
+ def to_a
4
+ []
5
+ end
6
+
7
+ def to_ary
8
+ []
9
+ end
10
+
11
+ def to_s
12
+ "(unresolved)" # always returned as part of first unresolved processing pass
13
+ end
14
+ alias_method :to_str, :to_s # ERB requires to_str
15
+
16
+ def to_f
17
+ 0.0
18
+ end
19
+
20
+ def to_i
21
+ 0
22
+ end
23
+
24
+ def nil?
25
+ true
26
+ end
27
+
28
+ def inspect
29
+ format("#<%s:0x%x>", self.class, object_id)
30
+ end
31
+
32
+ def method_missing(*_args, &_block)
33
+ self
34
+ end
35
+
36
+ def respond_to?(_message, _include_private = false)
37
+ true
38
+ end
39
+ end
40
+ end
@@ -1,29 +1,33 @@
1
1
  module Terraspace::Terraform::RemoteState
2
2
  class OutputProxy
3
3
  # raw: can be anything: String, Array, Hash, etc
4
- # options: original options passed by user with terraform_output
4
+ # options: original options passed by user from the output helper in tfvars
5
5
  attr_reader :raw, :options
6
- def initialize(raw, options={})
7
- @raw, @options = raw, options
6
+ def initialize(mod, raw, options={})
7
+ @mod, @raw, @options = mod, raw, options
8
8
  @format = @options[:format]
9
9
  end
10
10
 
11
11
  # Should always return a String
12
12
  def to_s
13
- case @format
14
- when "string"
15
- content.to_s
16
- else # "json"
17
- content.to_json
13
+ if @mod.resolved
14
+ # Dont use NullObject wrapper because Integer get changed to Strings.
15
+ # Want raw value to be used for the to_json call
16
+ value = @raw.nil? ? mock_or_error : @raw
17
+ value.to_json
18
+ else
19
+ NullObject.new # to_s => (unresolved)
18
20
  end
19
21
  end
20
22
 
21
- def content
22
- if @raw.nil?
23
- @options[:mock] || @options[:error]
24
- else
25
- @raw
26
- end
23
+ def to_ruby
24
+ data = @raw.nil? ? mock_or_error : @raw
25
+ @mod.resolved ? data : NullObject.new
26
+ end
27
+
28
+ private
29
+ def mock_or_error
30
+ @options[:mock] || @options[:error]
27
31
  end
28
32
  end
29
33
  end
@@ -1,3 +1,3 @@
1
1
  module Terraspace
2
- VERSION = "0.3.1"
2
+ VERSION = "0.3.6"
3
3
  end
@@ -0,0 +1 @@
1
+ length = <%= output('b1.length') %>
@@ -8,6 +8,10 @@
8
8
  "value": 1,
9
9
  "type": "number"
10
10
  },
11
+ "complex": {
12
+ "value": ["a","b"],
13
+ "type": "list"
14
+ },
11
15
  "random_pet_id": {
12
16
  "value": "valued-buzzard",
13
17
  "type": "string"
@@ -68,7 +68,7 @@ describe Terraspace::All::Summary do
68
68
  let(:log_path) { "spec/fixtures/summary/output.log" }
69
69
  it "run" do
70
70
  summary.run
71
- expect(@io.string).to include "=> terraform output"
71
+ expect(@io.string).to include "pet1 = krill"
72
72
  end
73
73
  end
74
74
 
@@ -0,0 +1,15 @@
1
+ describe Terraspace::Compiler::Erb::Render do
2
+ let(:render) { described_class.new(mod, src_path) }
3
+ let(:mod) { Terraspace::Mod.new("a1") }
4
+
5
+ # Only testing mod unresolved as a sanity check and its worth the ROI.
6
+ # The resolved would the Fetcher. We have unit tests to cover those other changes.
7
+ context "a1" do
8
+ let(:src_path) { fixture("dependencies/app/stacks/a1/tfvars/dev.tfvars") }
9
+ it "build" do
10
+ allow(Terraspace::Terraform::RemoteState::Marker::Output).to receive(:stack_names).and_return("b1")
11
+ result = render.build
12
+ expect(result).to eq "length = (unresolved)"
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,27 @@
1
+ describe Terraspace::Dependency::Helper::DependsOn do
2
+ let(:depends_on) do
3
+ described_class.new(mod, identifier, options)
4
+ end
5
+ let (:mod) { Terraspace::Mod.new("a1") }
6
+ # follow args dont matter for spec
7
+ let (:identifier) { "b1" }
8
+ let (:options) { {} }
9
+
10
+ context "unresolved" do
11
+ before(:each) { mod.resolved = false }
12
+ it "result calls Marker::Output" do
13
+ allow(Terraspace::Terraform::RemoteState::Marker::Output).to receive(:new).and_return(double(:marker_output).as_null_object)
14
+ result = depends_on.result
15
+ expect(result).to be_a(RSpec::Mocks::Double)
16
+ expect(result.instance_variable_get(:@name)).to eq :marker_output
17
+ end
18
+ end
19
+
20
+ context "resolved" do
21
+ before(:each) { mod.resolved = true }
22
+ it "return an raw String" do
23
+ result = depends_on.result
24
+ expect(result).to eq "# a1 depends on b1"
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,29 @@
1
+ describe Terraspace::Dependency::Helper::Output do
2
+ let(:output) do
3
+ described_class.new(mod, identifier, options)
4
+ end
5
+ let (:mod) { Terraspace::Mod.new("foo") }
6
+ # doesnt matter for spec
7
+ let (:identifier) { nil }
8
+ let (:options) { nil }
9
+
10
+ context "unresolved" do
11
+ before(:each) { mod.resolved = false }
12
+ it "result calls Marker::Output" do
13
+ allow(Terraspace::Terraform::RemoteState::Marker::Output).to receive(:new).and_return(double(:marker_output).as_null_object)
14
+ result = output.result
15
+ expect(result).to be_a(RSpec::Mocks::Double)
16
+ expect(result.instance_variable_get(:@name)).to eq :marker_output
17
+ end
18
+ end
19
+
20
+ context "resolved" do
21
+ before(:each) { mod.resolved = true }
22
+ it "result calls Fetcher" do
23
+ allow(Terraspace::Terraform::RemoteState::Fetcher).to receive(:new).and_return(double(:fetcher_output).as_null_object)
24
+ result = output.result
25
+ expect(result).to be_a(RSpec::Mocks::Double)
26
+ expect(result.instance_variable_get(:@name)).to eq :fetcher_output
27
+ end
28
+ end
29
+ end
@@ -11,41 +11,122 @@ describe Terraspace::Terraform::RemoteState::Fetcher do
11
11
  double("c1").as_null_object
12
12
  end
13
13
 
14
- context "pull success" do
15
- let(:state_path) { "spec/fixtures/fetcher/c1.json" }
16
- let(:pull_success) { true }
14
+ context "to_s uses to_json by default" do
15
+ context "pull success" do
16
+ let(:state_path) { "spec/fixtures/fetcher/c1.json" }
17
+ let(:pull_success) { true }
17
18
 
18
- context "c1.length" do
19
- let(:identifier) { "c1.length" }
20
- it "fetched found attribute" do
21
- expect(fetcher.output.raw).to eq 1 # matches spec/fixtures/fetcher/c1.json outputs.length.value
19
+ context "c1.length" do
20
+ let(:identifier) { "c1.length" }
21
+ it "fetched found attribute" do
22
+ expect(fetcher.output.to_s).to eq '1' # Integer as json matches spec/fixtures/fetcher/c1.json outputs.length.value
23
+ end
24
+ end
25
+
26
+ context "c1.complex" do
27
+ let(:identifier) { "c1.complex" }
28
+ it "fetched found attribute" do
29
+ expect(fetcher.output.to_s).to eq ["a","b"].to_json # matches spec/fixtures/fetcher/c1.json outputs.complex.value
30
+ end
31
+ end
32
+
33
+ context "c1.does-not-exist" do
34
+ let(:identifier) { "c1.does-not-exist" }
35
+ it "fetched missing output" do
36
+ output_proxy = fetcher.output
37
+ expect(output_proxy.raw).to be nil
38
+ value = output_proxy.to_s
39
+ # (Output length9 was not found for the b1 tfvars file. Either c1 stack has not been deployed yet or it does not have this output: length9)
40
+ expect(value).to include "not found"
41
+ end
22
42
  end
23
43
  end
24
44
 
25
- context "c1.does-not-exist" do
26
- let(:identifier) { "c1.does-not-exist" }
27
- it "fetched missing output" do
28
- output_proxy = fetcher.output
29
- expect(output_proxy.raw).to be nil
30
- # (Output length9 was not found for the b1 tfvars file. Either c1 stack has not been deployed yet or it does not have this output: length9)
31
- error = output_proxy.options[:error]
32
- expect(error).to include "not found"
45
+ context "pull fail" do
46
+ let(:state_path) { nil }
47
+ let(:pull_success) { false }
48
+
49
+ context "stack needs to be deployed" do
50
+ let(:identifier) { "c1.length" }
51
+ it "fetched" do
52
+ output_proxy = fetcher.output
53
+ expect(output_proxy.raw).to be nil
54
+ # (Output length could not be looked up for the b1 tfvars file. c1 stack needs to be deployed)
55
+ value = output_proxy.to_s
56
+ expect(value).to include "stack needs to be deployed"
57
+ end
58
+ end
59
+
60
+ context "bucket does not exist" do
61
+ let(:identifier) { "c1.length" }
62
+ it "fetched" do
63
+ fetcher.bucket_not_found_error # fake it!
64
+ output_proxy = fetcher.output
65
+ expect(output_proxy.raw).to be nil
66
+ # (Output length could not be looked up for the b1 tfvars file. c1 stack needs to be deployed)
67
+ value = output_proxy.to_s
68
+ expect(value).to include "bucket for the backend could not be found"
69
+ end
33
70
  end
34
71
  end
35
72
  end
36
73
 
37
- context "pull fail" do
38
- let(:state_path) { nil }
39
- let(:pull_success) { false }
40
-
41
- context "c1.length" do
42
- let(:identifier) { "c1.length" }
43
- it "fetched" do
44
- output_proxy = fetcher.output
45
- expect(output_proxy.raw).to be nil
46
- # (Output length could not be looked up for the b1 tfvars file. c1 stack needs to be deployed)
47
- error = output_proxy.options[:error]
48
- expect(error).to include "stack needs to be deployed"
74
+ context "to_ruby" do
75
+ context "pull success" do
76
+ let(:state_path) { "spec/fixtures/fetcher/c1.json" }
77
+ let(:pull_success) { true }
78
+
79
+ context "c1.length" do
80
+ let(:identifier) { "c1.length" }
81
+ it "fetched found attribute" do
82
+ expect(fetcher.output.to_ruby).to eq 1 # raw Integer
83
+ end
84
+ end
85
+
86
+ context "c1.complex" do
87
+ let(:identifier) { "c1.complex" }
88
+ it "fetched found attribute" do
89
+ expect(fetcher.output.to_ruby).to eq ["a","b"] # raw Array
90
+ end
91
+ end
92
+
93
+ context "c1.does-not-exist" do
94
+ let(:identifier) { "c1.does-not-exist" }
95
+ it "fetched missing output" do
96
+ output_proxy = fetcher.output
97
+ expect(output_proxy.raw).to be nil
98
+ value = output_proxy.to_ruby
99
+ # (Output length9 was not found for the b1 tfvars file. Either c1 stack has not been deployed yet or it does not have this output: length9)
100
+ expect(value).to include "not found"
101
+ end
102
+ end
103
+ end
104
+
105
+ context "pull fail" do
106
+ let(:state_path) { nil }
107
+ let(:pull_success) { false }
108
+
109
+ context "stack needs to be deployed" do
110
+ let(:identifier) { "c1.length" }
111
+ it "fetched" do
112
+ output_proxy = fetcher.output
113
+ expect(output_proxy.raw).to be nil
114
+ # (Output length could not be looked up for the b1 tfvars file. c1 stack needs to be deployed)
115
+ value = output_proxy.to_s
116
+ expect(value).to include "stack needs to be deployed"
117
+ end
118
+ end
119
+
120
+ context "bucket does not exist" do
121
+ let(:identifier) { "c1.length" }
122
+ it "fetched" do
123
+ fetcher.bucket_not_found_error # fake it!
124
+ output_proxy = fetcher.output
125
+ expect(output_proxy.raw).to be nil
126
+ # (Output length could not be looked up for the b1 tfvars file. c1 stack needs to be deployed)
127
+ value = output_proxy.to_s
128
+ expect(value).to include "bucket for the backend could not be found"
129
+ end
49
130
  end
50
131
  end
51
132
  end