terraspace 0.3.4 → 0.3.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: 82d3075dd4d1feefc14c645c634b80fca976887120ccf4e531385745e7d4df3e
4
- data.tar.gz: e3c035ee09b574247d563e3261e4f51e7d93bc5a6bf5af4d3b0ab083864f25af
3
+ metadata.gz: 7bb02485a9ee2b429e36b562fc8ba36946472776c1cabd234db2d0fd210c830b
4
+ data.tar.gz: 972a0074d2528352bfcb596f608e883fb47a673202db1a00ef6de25d6d63408f
5
5
  SHA512:
6
- metadata.gz: 384d8c9ff03eec838719ebe438dd9ad047558e0e4d495732f66561364b9100879bf498609bf931e29def28c5e4e3c0cb5ad4875cde4955a46dd63f850ec43887
7
- data.tar.gz: f475ab2126fe8c7807c9811a2f9f734cc9c47c702c61daa7b3cd4c995a192aa5b3669cde26f92c57b0592adf0131f4dbc80b45e0641900bca2090162d4e7529b
6
+ metadata.gz: 06c10d199374f6d9b1ceac52f89fddc1b3b57402037e212e357622e7647c37a31959098cde5ecbee9f42b501f792bab85b702641bbb3ae692fe86b8e96fbdb07
7
+ data.tar.gz: 8b8e1cf28734fc14ac8e4aa27ba626bb82f5f685ac39688f737ceacfdf6fcfef59ac7a4198292ce41b314d3b73faed166c50bc22ebb00a05d0b305d195160053
@@ -3,6 +3,11 @@
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
+ ## [0.3.5]
7
+ * #43 rename `terraform_output` helper to `output`. Keep `terraform_output` for backwards compatibility
8
+ * to_ruby natural interface to access output with full power of Ruby
9
+ * output formatters removed in favor for `.to_ruby` method.
10
+
6
11
  ## [0.3.4]
7
12
  * #42 update cli docs and bug fixes
8
13
  * fix console by using system instead of popen3
data/README.md CHANGED
@@ -81,7 +81,7 @@ To choose multiple stacks to deploy
81
81
 
82
82
  terraspace all up instance vpc
83
83
 
84
- When you use the all command, the dependency graph is calculated and the stacks are deployed in the right order. To learn more: [Deploy Multiple Stacks](https://terraspace.cloud/docs/dependencies/deploy-all/).
84
+ When you use the all command, the dependency graph is calculated and the stacks are deployed in the right order. To learn more: [Deploy Multiple Stacks](https://terraspace.cloud/docs/intro/deploy-all/).
85
85
 
86
86
  ## Features
87
87
 
@@ -22,7 +22,7 @@ module Terraspace::All
22
22
  @batches.map do |batch|
23
23
  i += 1
24
24
  batch.map do |stack|
25
- command = " terraspace #{@command}"
25
+ command = " terraspace #{@command}"
26
26
  ljust = command.size + max_name_size + 1
27
27
  command = "#{command} #{stack.name}"
28
28
  command.ljust(ljust, ' ') + " # batch #{i}"
@@ -0,0 +1,34 @@
1
+ module Terraspace::Compiler::Dependencies
2
+ # This is a separate module specifically because the DSL also has an output method.
3
+ # The module allows us to include dependency related methods only within tfvars context for the DSL.
4
+ #
5
+ # 1. Only include this module to DSL tfvars context.
6
+ # So the output method works in tfvars .rb files works.
7
+ # At the same time, the DSL usage of output also works for normal main.tf files.
8
+ # Passing specs prove this.
9
+ # 2. For ERB, there's currently only one ERB context. So this module is included in all contexts.
10
+ # The builder only processes dependencies from tfvars, so these helpers are only respected there.
11
+ #
12
+ # Where the module is included in the code:
13
+ #
14
+ # 1. lib/terraspace/compiler/dsl/syntax/tfvar.rb
15
+ # 2. lib/terraspace/compiler/erb/helpers.rb
16
+ #
17
+ module Helpers
18
+ def output(identifier, options={})
19
+ Terraspace::Dependency::Helper::Output.new(@mod, identifier, options).result
20
+ end
21
+ alias_method :terraform_output, :output # backwards compatibility
22
+
23
+ def depends_on(*child_names, **options)
24
+ child_names.flatten!
25
+ child_names.map do |child_name|
26
+ each_depends_on(child_name, options)
27
+ end.join("\n")
28
+ end
29
+
30
+ def each_depends_on(child_name, options={})
31
+ Terraspace::Dependency::Helper::DependsOn.new(@mod, child_name, options).result
32
+ end
33
+ end
34
+ end
@@ -1,8 +1,6 @@
1
1
  module Terraspace::Compiler::Dsl::Syntax::Helpers
2
2
  module Common
3
3
  extend Memoist
4
- Fetcher = Terraspace::Terraform::RemoteState::Fetcher
5
- Marker = Terraspace::Terraform::RemoteState::Marker
6
4
  Meta = Terraspace::Compiler::Dsl::Meta
7
5
 
8
6
  def var
@@ -25,29 +23,5 @@ module Terraspace::Compiler::Dsl::Syntax::Helpers
25
23
  command = ["terraspace"] + args
26
24
  command.join(separator)
27
25
  end
28
-
29
- def terraform_output(identifier, options={})
30
- if @mod.resolved # dependencies have been resolved
31
- Fetcher.new(@mod, identifier, options).output
32
- else
33
- Marker::Output.new(@mod, identifier, options).build
34
- end
35
- end
36
-
37
- def depends_on(*child_names, **options)
38
- child_names.flatten!
39
- child_names.map do |child_name|
40
- each_depends_on(child_name, options)
41
- end.join("\n")
42
- end
43
-
44
- def each_depends_on(child_name, options={})
45
- if @mod.resolved # dependencies have been resolved
46
- # Note: A generated line is not really needed. Dependencies are stored in memory. Added to assist users with debugging
47
- "# #{@mod.name} depends on #{child_name}"
48
- else
49
- Marker::Output.new(@mod, child_name, options).build
50
- end
51
- end
52
26
  end
53
27
  end
@@ -1,5 +1,6 @@
1
1
  module Terraspace::Compiler::Dsl::Syntax
2
2
  module Tfvar
3
3
  include_dir("tfvar")
4
+ include Terraspace::Compiler::Dependencies::Helpers
4
5
  end
5
6
  end
@@ -1,6 +1,6 @@
1
1
  module Terraspace::Compiler::Erb
2
2
  class Context
3
- include Terraspace::Compiler::Dsl::Syntax::Mod
3
+ include Helpers
4
4
 
5
5
  attr_reader :mod, :options
6
6
  def initialize(mod)
@@ -0,0 +1,6 @@
1
+ module Terraspace::Compiler::Erb
2
+ module Helpers
3
+ include Terraspace::Compiler::Dsl::Syntax::Mod
4
+ include Terraspace::Compiler::Dependencies::Helpers
5
+ end
6
+ end
@@ -0,0 +1,7 @@
1
+ module Terraspace::Dependency::Helper
2
+ class Base
3
+ def initialize(mod, identifier, options)
4
+ @mod, @identifier, @options = mod, identifier, options
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,12 @@
1
+ module Terraspace::Dependency::Helper
2
+ class DependsOn < Base
3
+ def result
4
+ if @mod.resolved # dependencies have been resolved
5
+ # Note: A generated line is not really needed. Dependencies are stored in memory. Added to assist users with debugging
6
+ "# #{@mod.name} depends on #{@identifier}" # raw String value
7
+ else
8
+ Terraspace::Terraform::RemoteState::Marker::Output.new(@mod, @identifier, @options).build # Returns OutputProxy which defaults to json
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,11 @@
1
+ module Terraspace::Dependency::Helper
2
+ class Output < Base
3
+ def result
4
+ if @mod.resolved # dependencies have been resolved
5
+ Terraspace::Terraform::RemoteState::Fetcher.new(@mod, @identifier, @options).output # Returns OutputProxy which defaults to json
6
+ else
7
+ Terraspace::Terraform::RemoteState::Marker::Output.new(@mod, @identifier, @options).build # Returns OutputProxy is NullObject when unresolved
8
+ end
9
+ end
10
+ end
11
+ end
@@ -8,6 +8,7 @@ module Terraspace::Terraform::RemoteState
8
8
  @parent, @identifier, @options = parent, identifier, options
9
9
  child_name, @output_key = identifier.split('.')
10
10
  @child = Terraspace::Mod.new(child_name)
11
+ @child.resolved = @parent.resolved
11
12
  end
12
13
 
13
14
  def run
@@ -16,16 +17,24 @@ module Terraspace::Terraform::RemoteState
16
17
  load
17
18
  end
18
19
 
20
+ # Returns OutputProxy
19
21
  def output
20
22
  run
21
23
  if pull_success?
22
- value = output_value
23
- error = output_error(:key_not_found) unless @outputs.key?(@output_key)
24
- OutputProxy.new(value, @options.merge(error: error))
24
+ pull_success_output
25
25
  else
26
26
  @error_type ||= :state_not_found # could be set to :bucket_not_found by bucket_not_found_error
27
27
  error = output_error(@error_type)
28
- OutputProxy.new(nil, @options.merge(error: error))
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))
29
38
  end
30
39
  end
31
40
 
@@ -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.4"
2
+ VERSION = "0.3.5"
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"
@@ -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
@@ -0,0 +1,36 @@
1
+ describe Terraspace::Terraform::RemoteState::Marker::Output do
2
+ let(:output) do
3
+ output = described_class.new(mod, identifier, options)
4
+ allow(output).to receive(:warning) # supress warning messaging about missing child stack
5
+ output
6
+ end
7
+ let (:mod) { Terraspace::Mod.new("a1") }
8
+ let (:options) { {} }
9
+
10
+ before(:each) do
11
+ Terraspace::Dependency::Registry.class_variable_set("@@data", Set.new)
12
+ end
13
+
14
+ # markers are always only called during unresolved stage
15
+ context "child stack found" do
16
+ let(:identifier) { "b1.length" }
17
+ it "registers dependency and always return a OutputProxy" do
18
+ allow(output).to receive(:valid?).and_return(true) # child stack found
19
+ result = output.build
20
+ expect(result).to be_a(Terraspace::Terraform::RemoteState::OutputProxy)
21
+ set = Terraspace::Dependency::Registry.data
22
+ expect(set).not_to be_empty
23
+ end
24
+ end
25
+
26
+ context "child stack not found" do
27
+ let(:identifier) { "b1.length" }
28
+ it "does not registers dependency and always return a OutputProxy" do
29
+ allow(output).to receive(:valid?).and_return(false) # child stack not found
30
+ result = output.build
31
+ expect(result).to be_a(Terraspace::Terraform::RemoteState::OutputProxy)
32
+ set = Terraspace::Dependency::Registry.data
33
+ expect(set).to be_empty
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,69 @@
1
+ NullObject = Terraspace::Terraform::RemoteState::NullObject
2
+
3
+ describe Terraspace::Terraform::RemoteState::OutputProxy do
4
+ let(:proxy) do
5
+ described_class.new(mod, raw, options)
6
+ end
7
+ let (:mod) { Terraspace::Mod.new("foo") }
8
+ let (:raw) { nil }
9
+ let (:options) { {} }
10
+
11
+ context "unresolved" do
12
+ before(:each) { mod.resolved = false }
13
+ it "always return NullObject" do
14
+ value = proxy.to_s
15
+ expect(value).to be_a(NullObject)
16
+ expect(value.to_str).to eq "(unresolved)"
17
+ end
18
+ end
19
+
20
+ # Resolved value should always return a String because ERB requires string.
21
+ # Always use to_json.
22
+ context "resolved with mock" do
23
+ before(:each) { mod.resolved = true }
24
+ let (:raw) { nil }
25
+ let (:options) { {mock: "mock value"} }
26
+
27
+ it "return to_json String with mock value" do
28
+ value = proxy.to_s
29
+ expect(value).to be_a(String)
30
+ expect(value.to_str).to eq '"mock value"' # note double quotes from the to_json
31
+ end
32
+ end
33
+
34
+ context "resolved with errors" do
35
+ before(:each) { mod.resolved = true }
36
+ let (:raw) { nil }
37
+ let (:options) { {error: "error message"} }
38
+
39
+ it "return to_json String with error message" do
40
+ value = proxy.to_s
41
+ expect(value).to be_a(String)
42
+ expect(value.to_str).to eq '"error message"' # note double quotes from the to_json
43
+ end
44
+ end
45
+
46
+ context "to_ruby resolved with mock" do
47
+ before(:each) { mod.resolved = true }
48
+ let (:raw) { nil }
49
+ let (:options) { {mock: "mock value"} }
50
+
51
+ it "return to_json String with mock value" do
52
+ value = proxy.to_ruby
53
+ expect(value).to be_a(String)
54
+ expect(value.to_str).to eq "mock value"
55
+ end
56
+ end
57
+
58
+ context "to_ruby resolved with errors" do
59
+ before(:each) { mod.resolved = true }
60
+ let (:raw) { nil }
61
+ let (:options) { {error: "error message"} }
62
+
63
+ it "return to_json String with error message" do
64
+ value = proxy.to_ruby
65
+ expect(value).to be_a(String)
66
+ expect(value.to_str).to eq "error message"
67
+ end
68
+ end
69
+ end
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: 0.3.4
4
+ version: 0.3.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: 2020-09-20 00:00:00.000000000 Z
11
+ date: 2020-09-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -561,6 +561,7 @@ files:
561
561
  - lib/terraspace/compiler/cleaner.rb
562
562
  - lib/terraspace/compiler/cleaner/backend_change.rb
563
563
  - lib/terraspace/compiler/commands_concern.rb
564
+ - lib/terraspace/compiler/dependencies/helpers.rb
564
565
  - lib/terraspace/compiler/dirs_concern.rb
565
566
  - lib/terraspace/compiler/dsl/base.rb
566
567
  - lib/terraspace/compiler/dsl/meta/local.rb
@@ -581,6 +582,7 @@ files:
581
582
  - lib/terraspace/compiler/dsl/syntax/tfvar/common.rb
582
583
  - lib/terraspace/compiler/dsl/tfvars.rb
583
584
  - lib/terraspace/compiler/erb/context.rb
585
+ - lib/terraspace/compiler/erb/helpers.rb
584
586
  - lib/terraspace/compiler/erb/render.rb
585
587
  - lib/terraspace/compiler/expander.rb
586
588
  - lib/terraspace/compiler/strategy/abstract_base.rb
@@ -600,6 +602,9 @@ files:
600
602
  - lib/terraspace/completer/script.sh
601
603
  - lib/terraspace/core.rb
602
604
  - lib/terraspace/dependency/graph.rb
605
+ - lib/terraspace/dependency/helper/base.rb
606
+ - lib/terraspace/dependency/helper/depends_on.rb
607
+ - lib/terraspace/dependency/helper/output.rb
603
608
  - lib/terraspace/dependency/node.rb
604
609
  - lib/terraspace/dependency/registry.rb
605
610
  - lib/terraspace/ext.rb
@@ -655,6 +660,7 @@ files:
655
660
  - lib/terraspace/terraform/remote_state/fetcher.rb
656
661
  - lib/terraspace/terraform/remote_state/marker/output.rb
657
662
  - lib/terraspace/terraform/remote_state/marker/pretty_tracer.rb
663
+ - lib/terraspace/terraform/remote_state/null_object.rb
658
664
  - lib/terraspace/terraform/remote_state/output_proxy.rb
659
665
  - lib/terraspace/terraform/runner.rb
660
666
  - lib/terraspace/tester.rb
@@ -667,6 +673,7 @@ files:
667
673
  - lib/terraspace/version.rb
668
674
  - spec/cli_spec.rb
669
675
  - spec/fixtures/cache_dir/variables.tf
676
+ - spec/fixtures/dependencies/app/stacks/a1/tfvars/dev.tfvars
670
677
  - spec/fixtures/fetcher/c1.json
671
678
  - spec/fixtures/initialized/modules.json
672
679
  - spec/fixtures/orphans/config/backend.rb
@@ -780,13 +787,18 @@ files:
780
787
  - spec/terraspace/compiler/dsl/resource_spec.rb
781
788
  - spec/terraspace/compiler/dsl/terraform_spec.rb
782
789
  - spec/terraspace/compiler/dsl/variable_spec.rb
790
+ - spec/terraspace/compiler/erb/render_spec.rb
783
791
  - spec/terraspace/dependency/graph_spec.rb
792
+ - spec/terraspace/dependency/helper/depends_on_spec.rb
793
+ - spec/terraspace/dependency/helper/output_spec.rb
784
794
  - spec/terraspace/provider/expander/generic_spec.rb
785
795
  - spec/terraspace/seeder/content_spec.rb
786
796
  - spec/terraspace/seeder_spec.rb
787
797
  - spec/terraspace/terraform/args/custom_spec.rb
788
798
  - spec/terraspace/terraform/hooks/builder_spec.rb
789
799
  - spec/terraspace/terraform/remote_state/fetcher_spec.rb
800
+ - spec/terraspace/terraform/remote_state/marker/output_spec.rb
801
+ - spec/terraspace/terraform/remote_state/output_proxy_spec.rb
790
802
  - terraspace.gemspec
791
803
  homepage: https://github.com/boltops-tools/terraspace
792
804
  licenses:
@@ -814,6 +826,7 @@ summary: 'Terraspace: The Terraspace Framework'
814
826
  test_files:
815
827
  - spec/cli_spec.rb
816
828
  - spec/fixtures/cache_dir/variables.tf
829
+ - spec/fixtures/dependencies/app/stacks/a1/tfvars/dev.tfvars
817
830
  - spec/fixtures/fetcher/c1.json
818
831
  - spec/fixtures/initialized/modules.json
819
832
  - spec/fixtures/orphans/config/backend.rb
@@ -927,10 +940,15 @@ test_files:
927
940
  - spec/terraspace/compiler/dsl/resource_spec.rb
928
941
  - spec/terraspace/compiler/dsl/terraform_spec.rb
929
942
  - spec/terraspace/compiler/dsl/variable_spec.rb
943
+ - spec/terraspace/compiler/erb/render_spec.rb
930
944
  - spec/terraspace/dependency/graph_spec.rb
945
+ - spec/terraspace/dependency/helper/depends_on_spec.rb
946
+ - spec/terraspace/dependency/helper/output_spec.rb
931
947
  - spec/terraspace/provider/expander/generic_spec.rb
932
948
  - spec/terraspace/seeder/content_spec.rb
933
949
  - spec/terraspace/seeder_spec.rb
934
950
  - spec/terraspace/terraform/args/custom_spec.rb
935
951
  - spec/terraspace/terraform/hooks/builder_spec.rb
936
952
  - spec/terraspace/terraform/remote_state/fetcher_spec.rb
953
+ - spec/terraspace/terraform/remote_state/marker/output_spec.rb
954
+ - spec/terraspace/terraform/remote_state/output_proxy_spec.rb