terraspace 0.3.4 → 0.3.5

Sign up to get free protection for your applications and to get access to all the features.
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