terradactyl 0.13.2 → 0.15.0

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: f0bcbb7e3e6b90e0099b5e9619a58e804382de149a01b8125eb66b05a2124e7f
4
- data.tar.gz: 33653dc380bc7177bc32de91cf1e1c1d87a668d33a28e06d3cdd6c3bfaf77f72
3
+ metadata.gz: f2a88b521150fa75bede628b6a89642b308b873439b8ab1c321c5c0c4f223670
4
+ data.tar.gz: ac90f280fec5f7f3ce98b734c407f335b158863df5c324b577dce98e34878f91
5
5
  SHA512:
6
- metadata.gz: 88ab36f3422ecb3ce7e4898d94de40fdb745e725ecefbf9c01bda7b9324e68b049fa872072cada1d3ca942ed909798032be310cc8c01dc1d333de26e4c4abfce
7
- data.tar.gz: 5e20eb83847c02b02a5d92029135232906abd40ffb4327ce4fde71f7b038361e0da49b463a665298bf7d40683829edc3c8b8c2ddde36632be924299880e2281b
6
+ metadata.gz: 525638ac61294ee05b8cbc0618b467fb4b32910c09bb5c6f8269e690ae2f70ae9764543bc2923fa3d1629591a5b9d952019fbfee0326202f39514bdf234c087a
7
+ data.tar.gz: ff919fb3c9b2bc11227d0c1d6668aa270d05e273af136a96d85d7afe67139c26979d1e375f51a69792101c50d8acf400f2e3f6629b009b928491f07c43213aa6
data/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## 0.15.0 (2021-04-27)
4
+
5
+ NEW FEATURES:
6
+
7
+ * add support for Terraform version `0.14.x`
8
+ * add support for Terraform version `0.15.x`
9
+ * add new subcommand `install`
10
+ * generic component installation; presently only supports `terraform`
11
+ - permits on-demand installation of any available Terraform binary
12
+ * add new subcommand `upgrade`
13
+ * performs a Terraform upgrade of the target stack
14
+ * add support for native HCL Terraform contraints
15
+ * terradactyl will now search for Terraform version contraints in the following files: `settings.tf`, `versions.tf` and `backend.tf`
16
+ * update version expression parsing to match Terraform's own
17
+ * terradactyl version expression parsing should now operate the same way Terraform's own does, including support for version ranges
18
+
3
19
  ## 0.13.2 (2020-12-09)
4
20
 
5
21
  BUG FIXES:
data/README.md CHANGED
@@ -19,7 +19,7 @@ Terradactyl simplifies managing large heterogeneous Terraform monorepos by intro
19
19
 
20
20
  Requires Ruby 2.5 or greater.
21
21
 
22
- NOTE: Terraform sub-command operations are only supported between stable versions `~> 0.11.x` and `~> 0.13.x`.
22
+ NOTE: Terraform sub-command operations are only supported between stable versions `>= 0.11.x` to `~> 0.15.x`.
23
23
 
24
24
  ## Installation
25
25
 
@@ -83,6 +83,14 @@ The Terradactyl CLI is installed with a symlink so it may be called by its full
83
83
  $ terradactyl help
84
84
  $ td help
85
85
 
86
+ #### install terraform
87
+
88
+ ##### NOTE: You do not need to explicitly install Terraform, it will be downloaded and installed automatically, if your stack is configured to do so -- this is just to demonstrate on-demand installs ...
89
+
90
+ This is optional!
91
+
92
+ $ terradactyl install terraform --version=0.15.1
93
+
86
94
  #### quickplan a single stack
87
95
 
88
96
  You can specify the relative path to the stack OR the just the stack name. These two commands are equivalent:
@@ -110,6 +118,18 @@ When complete, you should have a JSON report that you can pass to other processe
110
118
 
111
119
  $ terradactyl smartapply
112
120
 
121
+ #### upgrade a legacy stack
122
+
123
+ Running this one time will upgrade it to next minor revision of Terraform ...
124
+
125
+ # Take me to Terraform v12
126
+ $ terradactyl upgrade stacks/tfv11
127
+
128
+ Running it again will bump it again!
129
+
130
+ # Take me to Terraform v13
131
+ $ terradactyl upgrade stacks/tfv11
132
+
113
133
  #### clean all the stacks
114
134
 
115
135
  $ terradactyl clean-all
@@ -122,7 +142,7 @@ See the [Configuration](#configuration) section for more info on how to control
122
142
 
123
143
  ## Operation
124
144
 
125
- NOTE: `terradactyl` (symlinked as `td`) ONLY operates in the root of your monorepo. In order to execute any sub-commands, your working directory must contain your project-level configuration file, otherwise you will receive this:
145
+ NOTE: `terradactyl` (symlinked as `td`) ONLY operates in the root of your monorepo. In order to execute any subcommands, your working directory must contain your project-level configuration file, otherwise you will receive this:
126
146
 
127
147
  FATAL: Could not load project file: `terradactyl.yaml`, No such file or directory @ rb_sysopen - terradactyl.yaml
128
148
 
@@ -135,9 +155,9 @@ Generally speaking, Terradactyl operates on the principle of **plan file** (`*.t
135
155
 
136
156
  In some cases, this might seem onerous, but it pays dividends in team workflow and CI/CD contexts.
137
157
 
138
- ### Supported sub-commands
158
+ ### Supported subcommands
139
159
 
140
- Terradactyl was created to facilitate the using Terraform in a CI environment. As such, some of the more exotic ad hoc user-focused sub-commands have not received any effort in integration. The following is a list of the supported Terraform sub-commands:
160
+ Terradactyl was created to facilitate the using Terraform in a CI environment. As such, some of the more exotic ad hoc user-focused subcommands have not received any effort in integration. The following is a list of the supported Terraform subcommands:
141
161
 
142
162
  * apply
143
163
  * destroy
@@ -147,6 +167,32 @@ Terradactyl was created to facilitate the using Terraform in a CI environment. A
147
167
  * refresh
148
168
  * validate
149
169
 
170
+ ### Special utility subcommands
171
+
172
+ Terradactyl add some unique utility commands that permit you to more readily manage your Terraform stacks.
173
+
174
+ #### install
175
+
176
+ Installs supporting components, namely Terraform itself...
177
+
178
+ # Install the latest terraform binary
179
+ terradactly install terraform
180
+
181
+ # Install pessimistic version
182
+ terradactyl install terraform --version="~> 0.13.0"
183
+
184
+ # Install ranged version
185
+ terradactyl install terraform --version=">= 0.14.5, <= 0.14.7"
186
+
187
+ # Install explicit version
188
+ terradactyl install terraform --version=0.15.0-beta2
189
+
190
+ #### upgrade
191
+
192
+ Upgrade abstracts the various Terraform subcommands related to upgrading individual stacks (`0.12upgrade` and `0.13upgrade`).
193
+
194
+ terradactyl upgrade <stack>
195
+
150
196
  ### Meta-commands
151
197
 
152
198
  Terradactyl provides a few useful meta-commands that can help you avoid repetitive multi-phase Terraform operations. Here are a few ...
@@ -166,7 +212,7 @@ Apply or Refresh _ANY_ stack containing a plan file.
166
212
 
167
213
  ### Getting Help
168
214
 
169
- For a list of available sub-commands do:
215
+ For a list of available subcommands do:
170
216
 
171
217
  $ terradactyl help
172
218
 
@@ -195,7 +241,7 @@ You can dump the compiled configuration for your project using the `defaults` su
195
241
  ```yaml
196
242
  terradactyl: <Object, Terradactyl config>
197
243
  base_folder: <String, the sub-directory for all your Terraform stacks, default=stacks>
198
- terraform: <Object, configuration to Terraform sub-commands and binaries>
244
+ terraform: <Object, configuration to Terraform subcommands and binaries>
199
245
  binary: <String, path to the Terraform binary you wish to use, default=nil>
200
246
  version: <String, explicit or implict Terraform version, default=nil>
201
247
  autoinstall: <Bool, perform automatic Terraform installations, default=true>
@@ -228,7 +274,7 @@ terradactyl: <Object, Terradactyl config>
228
274
 
229
275
  ### Terraform sub-command arguments
230
276
 
231
- Note that the config above contains config for Terraform sub-commands. for example:
277
+ Note that the config above contains config for Terraform subcommands. for example:
232
278
 
233
279
  ```yaml
234
280
  terradactyl:
@@ -243,12 +289,12 @@ Each of the keys in the `plan` object correspond to an argument passed to the `t
243
289
 
244
290
  terraform -lock=false -parallelism=5 -detailed-exitcode
245
291
 
246
- There are two conventions to keep in mind when configuring sub-commands:
292
+ There are two conventions to keep in mind when configuring subcommands:
247
293
 
248
294
  1. any sub-command option which toggles behaviour (i.e. `-detailed-exitcode`) requires a specific Boolean value of `true` OR `false`
249
295
  2. any sub-command option that is hyphenated (i.e. `-detailed-exitcode`) is set in the config using an **underscore** (i.e `detailed_exitcode`)
250
296
 
251
- If you need to tweak or augment any of the default arguments passed to any of the supported Terraform sub-commands, you can do so by adding them to the config.
297
+ If you need to tweak or augment any of the default arguments passed to any of the supported Terraform subcommands, you can do so by adding them to the config.
252
298
 
253
299
  Example:
254
300
 
@@ -260,7 +306,7 @@ terradactyl:
260
306
  backup: /tmp/tfbackup
261
307
  ```
262
308
 
263
- In addition, you can override the `echo` and `quiet` settings for any of the Terraform sub-commands:
309
+ In addition, you can override the `echo` and `quiet` settings for any of the Terraform subcommands:
264
310
 
265
311
  ```yaml
266
312
  terradactyl:
@@ -279,9 +325,29 @@ This can assist in debugging.
279
325
 
280
326
  ### Terraform version management
281
327
 
328
+ Terradactyl gives you some powerful ways to manage which versions of Terraform you support and where.
329
+
330
+ You may set **project-wide** OR **stack-explicit** versions, by using a config file (`terradactyl.yaml`, see [Configuration](#configuration)).
331
+
332
+ In addition, Terradactyl will also, search for a stack's desired Terraform version from one of **your HCL files**.
333
+
334
+ terraform {
335
+ required_version = "~> 0.13.0"
336
+ }
337
+
338
+ If a configuration like the one above is discovered in your stack's ...
339
+
340
+ * `settings.tf`
341
+ * `versions.tf`
342
+ * `backend.tf`
343
+
344
+ ... file, Terradactyl will download and use that version as required.
345
+
346
+ NOTE: These files are searched in the order you see above. If you specify `required_version` multiple times, the last one discovered is used.
347
+
282
348
  #### Explicit versions
283
349
 
284
- By default, Terradactyl will always use the **latest** stable version of Terraform. If you do not specify a version, you will always get the latest stable version of Terraform available.
350
+ By default, Terradactyl will always use the **latest** stable version of Terraform. So, if you don't specify a version, you will always get the latest stable version of Terraform available.
285
351
 
286
352
  But, as part of Terradactyl's configuration, you can specify a **project** Terraform version, making it the default for _your_ monorepo:
287
353
 
@@ -291,7 +357,9 @@ terradactyl:
291
357
  version: 0.12.29
292
358
  ```
293
359
 
294
- Still, because Terradactyl's configuration is hierarchic, in addition the default version you specify at the project level, **each stack** may also specify a different version of Terraform.
360
+ Still, because Terradactyl's configuration is hierarchic, you can also specify a version at the project level ...
361
+
362
+ Yes! **Each stack may use a different version of Terradactyl independent of any other.**
295
363
 
296
364
  See [examples/multi-tf-version](examples/multi-tf-version) for this setup.
297
365
 
@@ -1,3 +1,3 @@
1
1
  terradactyl:
2
2
  terraform:
3
- version: '0.11.14' # an explicit version
3
+ version: ~> 0.11.14
@@ -1 +1,3 @@
1
- resource "null_resource" "bar" {}
1
+ resource "null_resource" "bar" {
2
+ }
3
+
@@ -0,0 +1,3 @@
1
+ terraform {
2
+ required_version = "~> 0.12.0"
3
+ }
@@ -0,0 +1,8 @@
1
+ terraform {
2
+ required_providers {
3
+ null = {
4
+ source = "hashicorp/null"
5
+ }
6
+ }
7
+ required_version = "~> 0.13.0"
8
+ }
@@ -0,0 +1 @@
1
+ resource "null_resource" "baz" {}
@@ -0,0 +1,8 @@
1
+ terraform {
2
+ required_providers {
3
+ null = {
4
+ source = "hashicorp/null"
5
+ }
6
+ }
7
+ required_version = "~> 0.14.0"
8
+ }
@@ -0,0 +1 @@
1
+ resource "null_resource" "baz" {}
@@ -0,0 +1,8 @@
1
+ terraform {
2
+ required_providers {
3
+ null = {
4
+ source = "hashicorp/null"
5
+ }
6
+ }
7
+ required_version = "~> 0.15.0"
8
+ }
@@ -1,3 +1,3 @@
1
1
  terradactyl:
2
2
  terraform:
3
- version: 0.12.29
3
+ version: 0.15.1
@@ -1,5 +1,24 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # Fix for https://github.com/erikhuda/thor/issues/398
4
+ class Thor
5
+ module Shell
6
+ class Basic
7
+ def print_wrapped(message, options = {})
8
+ indent = (options[:indent] || 0).to_i
9
+ if indent.zero?
10
+ stdout.puts message
11
+ else
12
+ message.each_line do |message_line|
13
+ stdout.print ' ' * indent
14
+ stdout.puts message_line.chomp
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+
3
22
  module Terradactyl
4
23
  # rubocop:disable Metrics/ClassLength
5
24
  class CLI < Thor
@@ -14,6 +33,7 @@ module Terradactyl
14
33
  super
15
34
  end
16
35
 
36
+ # rubocop:disable Metrics/BlockLength
17
37
  no_commands do
18
38
  # Monkey-patch Thor internal method to break out of nested calls
19
39
  def invoke_command(command, *args)
@@ -43,7 +63,12 @@ module Terradactyl
43
63
  File.write data_file, JSON.pretty_generate(report)
44
64
  print_ok 'Done!'
45
65
  end
66
+
67
+ def terraform_latest
68
+ Terradactyl::Terraform::VersionManager.latest
69
+ end
46
70
  end
71
+ # rubocop:enable Metrics/BlockLength
47
72
 
48
73
  #################################################################
49
74
  # GENERIC TASKS
@@ -247,7 +272,7 @@ module Terradactyl
247
272
  when 1
248
273
  Stacks.error!(@stack)
249
274
  print_crit "Plan failed: #{@stack.name}"
250
- @stack.print_plan
275
+ @stack.print_error
251
276
  throw :error
252
277
  when 2
253
278
  Stacks.dirty!(@stack)
@@ -289,13 +314,7 @@ module Terradactyl
289
314
  print_ok "Cleaned: #{@stack.name}"
290
315
  end
291
316
 
292
- #################################################################
293
- # HIDDEN TARGETED STACK TASKS
294
- # * These tasks are destructive in nature and do not require
295
- # regular use.
296
- #################################################################
297
-
298
- desc 'apply NAME', 'Apply an individual stack, by name', hide: true
317
+ desc 'apply NAME', 'Apply an individual stack, by name'
299
318
  def apply(name)
300
319
  @stack ||= Stack.new(name)
301
320
  print_warning "Applying: #{@stack.name}"
@@ -307,7 +326,7 @@ module Terradactyl
307
326
  end
308
327
  end
309
328
 
310
- desc 'refresh NAME', 'Refresh state on an individual stack, by name', hide: true
329
+ desc 'refresh NAME', 'Refresh state on an individual stack, by name'
311
330
  def refresh(name)
312
331
  @stack ||= Stack.new(name)
313
332
  print_crit "Refreshing: #{@stack.name}"
@@ -319,7 +338,7 @@ module Terradactyl
319
338
  end
320
339
  end
321
340
 
322
- desc 'destroy NAME', 'Destroy an individual stack, by name', hide: true
341
+ desc 'destroy NAME', 'Destroy an individual stack, by name'
323
342
  def destroy(name)
324
343
  @stack ||= Stack.new(name)
325
344
  print_crit "Destroying: #{@stack.name}"
@@ -330,6 +349,63 @@ module Terradactyl
330
349
  print_crit "Failed to apply changes: #{@stack.name}"
331
350
  end
332
351
  end
352
+
353
+ #################################################################
354
+ # PROJECT-LEVEL UTILITY TASKS
355
+ # * These tasks are managing project-wide characteristics or
356
+ # invoking useful commands.
357
+ #################################################################
358
+
359
+ desc 'install COMPONENT', 'Installs specified component'
360
+ long_desc <<~LONGDESC
361
+ The `terradactyl install COMPONENT` subcommand perfoms installations of
362
+ prerequisties. At present, only Terraform binaries are supported.
363
+ Here are a few examples:
364
+ # Install latest
365
+ `terradactyl install terraform`
366
+ # Install pessimistic version
367
+ `terradactyl install terraform --version="~> 0.13.0"`
368
+ # Install ranged version
369
+ `terradactyl install terraform --version=">= 0.14.5, <= 0.14.7"`
370
+ # Install explicit version
371
+ `terradactyl install terraform --version=0.15.0-beta2`
372
+
373
+ LONGDESC
374
+ option :version, type: :string, default: 'latest'
375
+ # rubocop:disable Metrics/AbcSize
376
+ def install(component)
377
+ case component.to_sym
378
+ when :terraform
379
+ print_warning "Installing: #{component}, version: #{options[:version]}"
380
+ version = options[:version] == 'latest' ? terraform_latest : options[:version]
381
+ Terradactyl::Terraform::VersionManager.reset!
382
+ Terradactyl::Terraform::VersionManager.version = version
383
+ Terradactyl::Terraform::VersionManager.install
384
+ if Terradactyl::Terraform::VersionManager.binary
385
+ print_ok "Installed: #{Terradactyl::Terraform::VersionManager.binary}"
386
+ end
387
+ else
388
+ msg = %(Operation not supported -- I don't know how to install: #{component})
389
+ print_crit msg
390
+ exit 1
391
+ end
392
+ end
393
+ # rubocop:enable Metrics/AbcSize
394
+
395
+ desc 'upgrade NAME', 'Upgrade an individual stack, by name'
396
+ def upgrade(name)
397
+ @stack ||= Stack.new(name)
398
+ print_warning "Upgrading: #{@stack.name}"
399
+ if @stack.upgrade.zero?
400
+ print_ok "Upgraded: #{@stack.name}"
401
+ else
402
+ Stacks.error!(@stack)
403
+ print_crit "Failed to upgrade: #{@stack.name}"
404
+ end
405
+ rescue Terradactyl::Terraform::Commands::UnsupportedCommandError => e
406
+ print_crit "Error: #{e.message}"
407
+ exit 1
408
+ end
333
409
  end
334
410
  # rubocop:enable Metrics/ClassLength
335
411
  end
@@ -1,6 +1,70 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Terradactyl
4
+ module Terraform
5
+ module Subcommands
6
+ module Upgrade
7
+ def defaults
8
+ {
9
+ 'yes' => false
10
+ }
11
+ end
12
+
13
+ def switches
14
+ %w[
15
+ yes
16
+ ]
17
+ end
18
+ end
19
+ end
20
+
21
+ module Commands
22
+ class UnsupportedCommandError < RuntimeError
23
+ def initialize(msg)
24
+ super(msg)
25
+ end
26
+ end
27
+
28
+ class Upgrade < Base
29
+ ERROR_UNSUPPORTED = <<~ERROR
30
+ subcommand `upgrade` is not supported on this stack!
31
+
32
+ This stack may already be upgraded. Check the stack's specified
33
+ Terraform version and consult its builtin help for further
34
+ details.
35
+ ERROR
36
+
37
+ class << self
38
+ def error_unsupported
39
+ raise UnsupportedCommandError, ERROR_UNSUPPORTED
40
+ end
41
+ end
42
+
43
+ def version
44
+ @version ||= calculate_upgrade(super)
45
+ end
46
+
47
+ private
48
+
49
+ def calculate_upgrade(current_version)
50
+ maj, min, _rev = current_version.split('.')
51
+ min = min.to_i < 13 ? (min.to_i + 1) : min
52
+ resolution = VersionManager.resolve("~> #{maj}.#{min}.0")
53
+ VersionManager.version = resolution
54
+ VersionManager.install
55
+ VersionManager.version
56
+ end
57
+
58
+ def subcmd
59
+ pre = version.slice(/\d+\.\d+/)
60
+ sig = self.class.name.split('::').last.downcase
61
+ sig == 'base' ? '' : "#{pre}#{sig}"
62
+ end
63
+ end
64
+ end
65
+ end
66
+
67
+ # rubocop:disable Metrics/ModuleLength
4
68
  module Commands
5
69
  class << self
6
70
  def extend_by_revision(tf_version, object)
@@ -63,18 +127,17 @@ module Terradactyl
63
127
  options: options,
64
128
  capture: true)
65
129
 
66
- output = case captured.exitstatus
67
- when 0
68
- 'No changes. Infrastructure is up-to-date.'
69
- when 1
70
- captured.stderr
71
- when 2
72
- captured.stdout
73
- end
130
+ @plan_file_obj = load_plan_file
74
131
 
75
- @plan_file_obj = load_plan_file
76
- @plan_file_obj.plan_output = output
77
- @plan_file_obj.save
132
+ case captured.exitstatus
133
+ when 0
134
+ 'No changes. Infrastructure is up-to-date.'
135
+ when 1
136
+ @plan_file_obj.error_output = captured.stderr
137
+ when 2
138
+ @plan_file_obj.plan_output = captured.stdout
139
+ @plan_file_obj.save
140
+ end
78
141
 
79
142
  captured.exitstatus
80
143
  end
@@ -118,8 +181,30 @@ module Terradactyl
118
181
  end
119
182
  # rubocop:enable Metrics/AbcSize
120
183
 
184
+ def upgrade
185
+ Upgrade.error_unsupported
186
+ end
187
+
121
188
  private
122
189
 
190
+ def perform_upgrade
191
+ options = command_options.tap { |dat| dat.yes = true }
192
+ upgrade = Upgrade.new(dir_or_plan: nil, options: options)
193
+ req_ver = /((?:\n\s)*required_version\s=\s)".*"/m
194
+ result = upgrade.execute
195
+
196
+ if result.zero?
197
+ settings = File.read('versions.tf').lstrip
198
+ settings.sub!(req_ver, %(#{Regexp.last_match(1)}"~> #{upgrade.version}"))
199
+
200
+ if File.write('versions.tf', settings)
201
+ FileUtils.rm_rf('terradactyl.yaml') if File.exist?('terradactyl.yaml')
202
+ end
203
+ end
204
+
205
+ result
206
+ end
207
+
123
208
  def load_plan_file
124
209
  Terraform::PlanFile.new(plan_path: plan_file, parser: parser)
125
210
  end
@@ -127,8 +212,8 @@ module Terradactyl
127
212
  module Rev011
128
213
  include Terraform::Commands
129
214
 
130
- def checklist
131
- Checklist.execute(dir_or_plan: nil, options: command_options)
215
+ def upgrade
216
+ perform_upgrade
132
217
  end
133
218
 
134
219
  private
@@ -141,6 +226,10 @@ module Terradactyl
141
226
  module Rev012
142
227
  include Terraform::Commands
143
228
 
229
+ def upgrade
230
+ perform_upgrade
231
+ end
232
+
144
233
  private
145
234
 
146
235
  def parser
@@ -151,11 +240,36 @@ module Terradactyl
151
240
  module Rev013
152
241
  include Terraform::Commands
153
242
 
243
+ def upgrade
244
+ perform_upgrade
245
+ end
246
+
154
247
  private
155
248
 
156
249
  def parser
157
- Terraform::Rev012::PlanFileParser
250
+ Terraform::Rev013::PlanFileParser
251
+ end
252
+ end
253
+
254
+ module Rev014
255
+ include Terraform::Commands
256
+
257
+ private
258
+
259
+ def parser
260
+ Terraform::Rev014::PlanFileParser
261
+ end
262
+ end
263
+
264
+ module Rev015
265
+ include Terraform::Commands
266
+
267
+ private
268
+
269
+ def parser
270
+ Terraform::Rev015::PlanFileParser
158
271
  end
159
272
  end
160
273
  end
274
+ # rubocop:enable Metrics/ModuleLength
161
275
  end
@@ -132,6 +132,12 @@ module Terradactyl
132
132
  end
133
133
 
134
134
  class ConfigStack < ConfigApplication
135
+ TERRAFORM_SETTINGS_FILES = %w[
136
+ settings.tf
137
+ versions.tf
138
+ backend.tf
139
+ ].freeze
140
+
135
141
  attr_reader :stack_name, :stack_path, :base_folder
136
142
 
137
143
  def initialize(stack_name)
@@ -163,5 +169,44 @@ module Terradactyl
163
169
  def plan_path
164
170
  "#{stack_path}/#{plan_file}"
165
171
  end
172
+
173
+ private
174
+
175
+ def terraform_required_version
176
+ matches = TERRAFORM_SETTINGS_FILES.map do |file|
177
+ path = File.join(stack_path, file)
178
+ if File.exist?(path)
179
+ File.read(path).match(terraform_required_version_re)
180
+ end
181
+ end
182
+
183
+ return {} unless matches.compact!.any?
184
+
185
+ {
186
+ 'terradactyl' => {
187
+ 'terraform' => {
188
+ 'version' => matches.last[:version]
189
+ }
190
+ }
191
+ }
192
+ end
193
+
194
+ def load_overlay(config_file)
195
+ overlay = super(config_file)
196
+
197
+ unless overlay_specifies_version?(overlay)
198
+ overlay.merge!(terraform_required_version)
199
+ end
200
+
201
+ overlay
202
+ end
203
+
204
+ def overlay_specifies_version?(overlay)
205
+ overlay['terradactyl']&.fetch('terraform', {})&.fetch('version', nil)
206
+ end
207
+
208
+ def terraform_required_version_re
209
+ /(?:\s*terraform\s*{(?:\n|\s)*.+required_version\s*=\s*)"(?<version>.*)"(?:(?:\n|\s)*.+})/m
210
+ end
166
211
  end
167
212
  end
@@ -48,6 +48,10 @@ module Terradactyl
48
48
  print_content(plan_file_obj.plan_output)
49
49
  end
50
50
 
51
+ def print_error
52
+ print_content(plan_file_obj.error_output)
53
+ end
54
+
51
55
  def plan_file_obj
52
56
  @plan_file_obj ||= load_plan_file
53
57
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Terradactyl
4
- VERSION = '0.13.2'
4
+ VERSION = '0.15.0'
5
5
  end
data/terradactyl.gemspec CHANGED
@@ -33,11 +33,10 @@ Gem::Specification.new do |spec|
33
33
  spec.add_dependency 'deep_merge', '~> 1.2'
34
34
  spec.add_dependency 'bundler', '>= 1.16'
35
35
  spec.add_dependency 'rake', '>= 10.0'
36
- spec.add_dependency 'terradactyl-terraform', '>= 0.3.1'
36
+ spec.add_dependency 'terradactyl-terraform', '>= 0.15.0'
37
37
 
38
38
  spec.add_development_dependency 'rspec', '~> 3.0'
39
39
  spec.add_development_dependency 'pry', '~> 0.12'
40
40
  spec.add_development_dependency 'pry-remote', '~> 0.1.8'
41
41
  spec.add_development_dependency 'rubocop', '~> 0.71.0'
42
42
  end
43
-
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: terradactyl
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.13.2
4
+ version: 0.15.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brian Warsing
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-12-09 00:00:00.000000000 Z
11
+ date: 2021-04-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
@@ -100,14 +100,14 @@ dependencies:
100
100
  requirements:
101
101
  - - ">="
102
102
  - !ruby/object:Gem::Version
103
- version: 0.3.1
103
+ version: 0.15.0
104
104
  type: :runtime
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
108
  - - ">="
109
109
  - !ruby/object:Gem::Version
110
- version: 0.3.1
110
+ version: 0.15.0
111
111
  - !ruby/object:Gem::Dependency
112
112
  name: rspec
113
113
  requirement: !ruby/object:Gem::Requirement
@@ -186,9 +186,13 @@ files:
186
186
  - examples/multi-tf-version/stacks/tfv11/example.tf
187
187
  - examples/multi-tf-version/stacks/tfv11/terradactyl.yaml
188
188
  - examples/multi-tf-version/stacks/tfv12/example.tf
189
- - examples/multi-tf-version/stacks/tfv12/terradactyl.yaml
189
+ - examples/multi-tf-version/stacks/tfv12/versions.tf
190
190
  - examples/multi-tf-version/stacks/tfv13/example.tf
191
- - examples/multi-tf-version/stacks/tfv13/terradactyl.yaml
191
+ - examples/multi-tf-version/stacks/tfv13/versions.tf
192
+ - examples/multi-tf-version/stacks/tfv14/example.tf
193
+ - examples/multi-tf-version/stacks/tfv14/versions.tf
194
+ - examples/multi-tf-version/stacks/tfv15/example.tf
195
+ - examples/multi-tf-version/stacks/tfv15/versions.tf
192
196
  - examples/multi-tf-version/terradactyl.yaml
193
197
  - examples/simple/stacks/demo/example.tf
194
198
  - examples/simple/terradactyl.yaml
@@ -227,7 +231,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
227
231
  - !ruby/object:Gem::Version
228
232
  version: '0'
229
233
  requirements: []
230
- rubygems_version: 3.1.4
234
+ rubygems_version: 3.1.6
231
235
  signing_key:
232
236
  specification_version: 4
233
237
  summary: Manage a Terraform monorepo
@@ -1,3 +0,0 @@
1
- terradactyl:
2
- terraform:
3
- version: 0.12.29
@@ -1,3 +0,0 @@
1
- terradactyl:
2
- terraform:
3
- version: '~> 0.13.5' # >= 0.13.5 && < 0.14.0