tfwrapper 0.2.0.beta1

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 0d770015f26d1cc19424567299a4cf0d300c7c9d
4
+ data.tar.gz: 682aecc64e4c300ff15140221f7b69b47a7042d1
5
+ SHA512:
6
+ metadata.gz: 0501b6c78f2c23afc807ab5f2942798929d177fdfd07230504135c5470360655bd5705c6b4086977b763f6337d0a5dc28d997c816d78519e1b0bef8c1243db4c
7
+ data.tar.gz: 2361518650e15fef68dab14983345195935b8a46bdd2fd88dc1c8a70813140a5f43ba57781efed2a0ce79e79867dda1e950e340bfe8e51d47feacf1e381ef449
data/.gitignore ADDED
@@ -0,0 +1,54 @@
1
+ *.gem
2
+ *.rbc
3
+ /.config
4
+ /coverage/
5
+ /InstalledFiles
6
+ /pkg/
7
+ /spec/reports/
8
+ /spec/examples.txt
9
+ /test/tmp/
10
+ /test/version_tmp/
11
+ /tmp/
12
+ /results/
13
+ /vendor/
14
+ .terraform
15
+ build.tfvars.json
16
+
17
+ # Used by dotenv library to load environment variables.
18
+ # .env
19
+
20
+ ## Specific to RubyMotion:
21
+ .dat*
22
+ .repl_history
23
+ build/
24
+ *.bridgesupport
25
+ build-iPhoneOS/
26
+ build-iPhoneSimulator/
27
+
28
+ ## Specific to RubyMotion (use of CocoaPods):
29
+ #
30
+ # We recommend against adding the Pods directory to your .gitignore. However
31
+ # you should judge for yourself, the pros and cons are mentioned at:
32
+ # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
33
+ #
34
+ # vendor/Pods/
35
+
36
+ ## Documentation cache and generated files:
37
+ /.yardoc/
38
+ /_yardoc/
39
+ /doc/
40
+ /rdoc/
41
+
42
+ ## Environment normalization:
43
+ /.bundle/
44
+ /vendor/bundle
45
+ /lib/bundler/man/
46
+
47
+ # for a library or gem, you might want to ignore these files since the code is
48
+ # intended to run in multiple environments; otherwise, check them in:
49
+ Gemfile.lock
50
+ .ruby-version
51
+ .ruby-gemset
52
+
53
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
54
+ .rvmrc
data/.rubocop.yml ADDED
@@ -0,0 +1,22 @@
1
+ Metrics/AbcSize:
2
+ Max: 22
3
+
4
+ Metrics/BlockLength:
5
+ Max: 1000
6
+
7
+ Metrics/ClassLength:
8
+ Max: 500
9
+
10
+ Metrics/MethodLength:
11
+ Max: 100
12
+
13
+ # These are to compensate for some warnings that differ by
14
+ # rubocop/ruby version
15
+ Lint/UnneededDisable:
16
+ Exclude:
17
+ - 'lib/tfwrapper/raketasks.rb'
18
+
19
+ Style/MutableConstant:
20
+ Exclude:
21
+ - 'lib/tfwrapper/version.rb'
22
+ - 'spec/acceptance/acceptance_spec.rb'
data/ChangeLog.md ADDED
@@ -0,0 +1,3 @@
1
+ Version 0.1.0
2
+
3
+ - initial release (migrated from previous internal/private gem)
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+ gemspec
data/Guardfile ADDED
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ guard :bundler do
4
+ watch('tfwrapper.gemspec')
5
+ end
6
+
7
+ guard :rubocop do
8
+ watch(/.+\.rb$/)
9
+ watch(%r{(?:.+\/)?\.rubocop\.yml$}) { |m| File.dirname(m[0]) }
10
+ end
11
+
12
+ guard :rspec, cmd: 'bundle exec rspec' do
13
+ watch('spec/spec_helper.rb') { 'spec' }
14
+ watch(%r{^spec/.+_spec\.rb})
15
+ watch(%r{^spec/(.+)/.+_spec\.rb})
16
+ watch(%r{^lib\/tfwrapper/(.+)\.rb$}) { |m| "spec/unit/#{m[1]}_spec.rb" }
17
+ end
18
+
19
+ guard 'yard', port: '8808' do
20
+ watch(/README\.md/)
21
+ end
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2017 Manheim
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,320 @@
1
+ # tfwrapper
2
+
3
+ Build of master branch: [![CircleCI](https://circleci.com/gh/manheim/tfwrapper.svg?style=svg)](https://circleci.com/gh/manheim/tfwrapper)
4
+
5
+ Documentation: [http://www.rubydoc.info/gems/tfwrapper/](http://www.rubydoc.info/gems/tfwrapper/)
6
+
7
+ tfwrapper provides Rake tasks for working with [Hashicorp Terraform](https://www.terraform.io/) 0.9+, ensuring proper initialization and passing in variables from the environment or Ruby, as well as optionally pushing some information to Consul. tfwrapper also attempts to detect and retry
8
+ failed runs due to AWS throttling or access denied errors.
9
+
10
+ ## Overview
11
+
12
+ This Gem provides the following Rake tasks:
13
+
14
+ * __tf:init__ - run ``terraform init`` to pull down dependency modules and configure remote
15
+ state backend. This task also checks that any configured environment variables are set and
16
+ that the ``terraform`` version is compatible with this gem.
17
+ * __tf:plan__ - run ``terraform plan`` with all variables and configuration, and TF variables written to disk. You can specify
18
+ one or more optional [resource address](https://www.terraform.io/docs/internals/resource-addressing.html) targets to pass to
19
+ terraform with the ``-target`` flag as Rake task arguments, i.e. ``bundle exec rake tf:plan[aws_instance.foo[1]]`` or
20
+ ``bundle exec rake tf:plan[aws_instance.foo[1],aws_instance.bar[2]]``; see the
21
+ [plan documentation](https://www.terraform.io/docs/commands/plan.html) for more information.
22
+ * __tf:apply__ - run ``terraform apply`` with all variables and configuration, and TF variables written to disk. You can specify
23
+ one or more optional [resource address](https://www.terraform.io/docs/internals/resource-addressing.html) targets to pass to
24
+ terraform with the ``-target`` flag as Rake task arguments, i.e. ``bundle exec rake tf:apply[aws_instance.foo[1]]`` or
25
+ ``bundle exec rake tf:apply[aws_instance.foo[1],aws_instance.bar[2]]``; see the
26
+ [apply documentation](https://www.terraform.io/docs/commands/apply.html) for more information. This also runs a plan first.
27
+ * __tf:refresh__ - run ``terraform refresh``
28
+ * __tf:destroy__ - run ``terraform destroy`` with all variables and configuration, and TF variables written to disk. You can specify
29
+ one or more optional [resource address](https://www.terraform.io/docs/internals/resource-addressing.html) targets to pass to
30
+ terraform with the ``-target`` flag as Rake task arguments, i.e. ``bundle exec rake tf:destroy[aws_instance.foo[1]]`` or
31
+ ``bundle exec rake tf:destroy[aws_instance.foo[1],aws_instance.bar[2]]``; see the
32
+ [destroy documentation](https://www.terraform.io/docs/commands/destroy.html) for more information.
33
+ * __tf:write_tf_vars__ - used as a prerequisite for other tasks; write Terraform variables to file on disk
34
+
35
+ ## Installation
36
+
37
+ __Note:__ tfwrapper only supports Ruby >= 2.0.0. The effort to maintain compatibility
38
+ with 1.9.3 is simply too high to justify.
39
+
40
+ Add to your ``Gemfile``:
41
+
42
+ ```ruby
43
+ gem 'tfwrapper', '~> 0.1.0'
44
+ ```
45
+
46
+ ### Supported Terraform Versions
47
+
48
+ tfwrapper only supports terraform 0.9+. It has been tested up to 0.9.2.
49
+
50
+ ## Usage
51
+
52
+ To use the Terraform rake tasks, require the module in your Rakefile and use the
53
+ ``install_tasks`` method to set up the tasks. ``install_tasks`` takes one mandatory parameter,
54
+ ``tf_dir`` specifying the relative path (from the Rakefile) to the Terraform configuration.
55
+
56
+ For a directory layout like:
57
+
58
+ ```
59
+ .
60
+ ├── bar.tf
61
+ ├── foo.tf
62
+ ├── main.tf
63
+ └── Rakefile
64
+ ```
65
+
66
+ The minimal ``Rakefile`` would be:
67
+
68
+ ```ruby
69
+ require 'tfwrapper/raketasks'
70
+
71
+ TFWrapper::RakeTasks.install_tasks('.')
72
+ ```
73
+
74
+ ``rake -T`` output:
75
+
76
+ ```
77
+ rake tf:apply[target] # Apply a terraform plan that will provision your resources; specify optional CSV targets
78
+ rake tf:destroy[target] # Destroy any live resources that are tracked by your state files; specify optional CSV targets
79
+ rake tf:init # Run terraform init with appropriate arguments
80
+ rake tf:plan[target] # Output the set plan to be executed by apply; specify optional CSV targets
81
+ rake tf:write_tf_vars # Write PWD/build.tfvars.json
82
+ ```
83
+
84
+ You can also point ``tf_dir`` to an arbitrary directory relative to the Rakefile, such as when your terraform
85
+ configurations are nested below the Rakefile:
86
+
87
+ ```
88
+ .
89
+ ├── infrastructure
90
+ │   └── terraform
91
+ │   ├── bar.tf
92
+ │   ├── foo.tf
93
+ │   └── main.tf
94
+ ├── lib
95
+ ├── Rakefile
96
+ └── spec
97
+ ```
98
+
99
+ Rakefile:
100
+
101
+ ```ruby
102
+ require 'tfwrapper/raketasks'
103
+
104
+ TFWrapper::RakeTasks.install_tasks('infrastructure/terraform')
105
+ ```
106
+
107
+ ### Environment Variables to Terraform Variables
108
+
109
+ If you wish to bind the values of environment variables to Terraform variables, you can specify a mapping
110
+ of Terraform variable name to environment variable name in the ``tf_vars_from_env`` option; these variables
111
+ will be automatically read from the environment and passed into Terraform with the appropriate names. The following
112
+ example sets the ``consul_address`` terraform variable to the value of the ``CONSUL_HOST`` environment variable
113
+ (defaulting it to ``consul.example.com:8500`` if it is not already set in the environment),
114
+ and likewise for the ``environment`` terraform variable from the ``ENVIRONMENT`` env var.
115
+
116
+ ```ruby
117
+ require 'tfwrapper/raketasks'
118
+ ENV['CONSUL_HOST'] ||= 'consul.example.com:8500'
119
+
120
+ TFWrapper::RakeTasks.install_tasks(
121
+ '.',
122
+ tf_vars_from_env: {
123
+ 'consul_address' => 'CONSUL_HOST',
124
+ 'environment' => 'ENVIRONMENT',
125
+ }
126
+ )
127
+ ```
128
+
129
+ ### Ruby Variables to Terraform Variables
130
+
131
+ If you wish to explicitly bind values from your Ruby code to terraform variables, you can do this with
132
+ the ``tf_extra_vars`` option. Variables specified in this way will override same-named variables populated
133
+ via ``tf_vars_from_env``. In the following example, the ``foobar`` terraform variable will have a value
134
+ of ``baz``, regardless of what the ``FOOBAR`` environment variable is set to, and the ``hostname``
135
+ terraform variable will be set to the hostname (``Socket.gethostname``) of the system Rake is running on:
136
+
137
+ ```ruby
138
+ require 'socket'
139
+ require 'tfwrapper/raketasks'
140
+
141
+ ENV['FOOBAR'] ||= 'not_baz'
142
+
143
+ TFWrapper::RakeTasks.install_tasks(
144
+ '.',
145
+ tf_vars_from_env: {
146
+ 'foobar' => 'FOOBAR'
147
+ },
148
+ tf_extra_vars: {
149
+ 'foobar' => 'baz',
150
+ 'hostname' => Socket.gethostname
151
+ }
152
+ )
153
+ ```
154
+
155
+ ### Namespace Prefixes for Multiple Configurations
156
+
157
+ If you need to work with multiple different Terraform configurations, this is possible
158
+ by adding a namespace prefix and calling ``install_tasks`` multiple times. The following example
159
+ will produce two sets of terraform Rake tasks; one with the default ``tf:`` namespace
160
+ that acts on the configurations under ``tf/foo``, and one with a ``bar_tf:`` namespace
161
+ that acts on the configurations under ``tf/bar``. You can use as many namespaces as
162
+ you want.
163
+
164
+ Directory tree:
165
+
166
+ ```
167
+ .
168
+ ├── Rakefile
169
+ └── tf
170
+ ├── bar
171
+ │   └── bar.tf
172
+ └── foo
173
+ └── foo.tf
174
+ ```
175
+
176
+ Rakefile:
177
+
178
+ ```ruby
179
+ require 'tfwrapper/raketasks'
180
+
181
+ # foo/ (default) terraform tasks
182
+ TFWrapper::RakeTasks.install_tasks('tf/foo')
183
+
184
+ # bar/ terraform tasks
185
+ TFWrapper::RakeTasks.install_tasks('tf/bar', namespace_prefix: 'bar')
186
+ ```
187
+
188
+ ``rake -T`` output:
189
+
190
+ ```
191
+ rake bar_tf:apply[target] # Apply a terraform plan that will provision your resources; specify optional CSV targets
192
+ rake bar_tf:destroy[target] # Destroy any live resources that are tracked by your state files; specify optional CSV targets
193
+ rake bar_tf:init # Run terraform init with appropriate arguments
194
+ rake bar_tf:plan[target] # Output the set plan to be executed by apply; specify optional CSV targets
195
+ rake bar_tf:write_tf_vars # Write PWD/bar_build.tfvars.json
196
+ rake tf:apply[target] # Apply a terraform plan that will provision your resources; specify optional CSV targets
197
+ rake tf:destroy[target] # Destroy any live resources that are tracked by your state files; specify optional CSV targets
198
+ rake tf:init # Run terraform init with appropriate arguments
199
+ rake tf:plan[target] # Output the set plan to be executed by apply; specify optional CSV targets
200
+ rake tf:write_tf_vars # Write PWD/build.tfvars.json
201
+ ```
202
+
203
+ ### Backend Configuration Options
204
+
205
+ ``install_tasks`` accepts a ``backend_config`` hash of options to pass as backend configuration
206
+ to ``terraform init`` via the ``-backend-config='key=value'`` command line argument. This can
207
+ be used when you need to pass some backend configuration in from the environment, such as a
208
+ specific remote state storage path, credentials, etc.
209
+
210
+ For a simple example, assume we aren't using [state environments](https://www.terraform.io/docs/state/environments.html)
211
+ but instead opt to use specific paths based on a ``ENVIRONMENT`` environment variable.
212
+
213
+ Our terraform configuration might include something like:
214
+
215
+ ```
216
+ terraform {
217
+ required_version = "> 0.9.0"
218
+ backend "consul" {
219
+ address = "consul.example.com:8500"
220
+ }
221
+ }
222
+
223
+ variable "environment" {}
224
+ ```
225
+
226
+ And the Rakefile would pass in the path to store state in Consul, as well as
227
+ passing the ``ENVIRONMENT`` env var into Terraform for use:
228
+
229
+ ```ruby
230
+ require 'tfwrapper/raketasks'
231
+
232
+ TFWrapper::RakeTasks.install_tasks(
233
+ '.',
234
+ tf_vars_from_env: {'environment' => 'ENVIRONMENT'},
235
+ backend_config: {'path' => "terraform/foo/#{ENVIRONMENT}"}
236
+ )
237
+ ```
238
+
239
+ ### Environment Variables to Consul
240
+
241
+ tfwrapper also includes functionality to push environment variables to Consul
242
+ (as a JSON object) after a successful apply. This is mainly useful when running
243
+ tfwrapper from within Jenkins or another job runner, where they can be used to
244
+ pre-populate user input fields on subsequent runs. This is configured via the
245
+ ``consul_url`` and ``consul_env_vars_prefix`` options:
246
+
247
+ Example Terraform snippet:
248
+
249
+ ```
250
+ variable "foo" {}
251
+ variable "bar" {}
252
+ ```
253
+
254
+ Rakefile:
255
+
256
+ ```ruby
257
+ require 'tfwrapper/raketasks'
258
+
259
+ TFWrapper::RakeTasks.install_tasks(
260
+ '.',
261
+ tf_vars_from_env: {'foo' => 'FOO', 'bar' => 'BAR'},
262
+ consul_url: 'http://consul.example.com:8500',
263
+ consul_env_vars_prefix: 'terraform/inputs/foo'
264
+ )
265
+ ```
266
+
267
+ After a successful terraform apply, e.g.:
268
+
269
+ ```
270
+ FOO=one BAR=two bundle exec rake tf:apply
271
+ ```
272
+
273
+ The key in Consul at ``terraform/inputs/foo`` will be set to a JSON hash of the
274
+ environment variables used via ``tf_vars_from_env`` and their values:
275
+
276
+ ```shell
277
+ $ consul kv get terraform/inputs/foo
278
+ {"FOO":"one", "BAR":"two"}
279
+ ```
280
+
281
+ ## Development
282
+
283
+ 1. ``bundle install --path vendor``
284
+ 2. ``bundle exec rake pre_commit`` to ensure unit tests are passing and style is valid before making your changes.
285
+ 3. ``bundle exec rake spec:acceptance`` to ensure acceptance tests are passing before making your changes.
286
+ 4. make your changes, and write unit tests for them. If you introduced user-visible (public API) changes, write acceptance tests for them. You can run ``bundle exec guard`` to continually run unit tests and rubocop when files change.
287
+ 5. ``bundle exec rake pre_commit`` to confirm your unit tests pass and your style is valid. You should confirm 100% coverage. If you wish, you can run ``bundle exec guard`` to dynamically run rspec, rubocop and YARD when relevant files change.
288
+ 6. ``bundle exec rake spec:acceptance`` to ensure acceptance tests are passing.
289
+ 7. Update ``ChangeLog.md`` for your changes.
290
+ 8. Run ``bundle exec rake yard:serve`` to generate documentation for your Gem and serve it live at [http://localhost:8808](http://localhost:8808), and ensure it looks correct.
291
+ 9. Open a pull request for your changes.
292
+ 10. When shipped, wait for CircleCI to test. Once shipped and tests pass, merge the PR.
293
+
294
+ When running inside CircleCI, rspec will place reports and artifacts under the right locations for CircleCI to archive them. When running outside of CircleCI, coverage reports will be written to ``coverage/`` and test reports (HTML and JUnit XML) will be written to ``results/``.
295
+
296
+ ### Acceptance Tests
297
+
298
+ This gem includes some rspec-based acceptance tests, runnable via ``bundle exec rake spec:acceptance``. These tests download
299
+ a specific version of Terraform and Consul, run a local Consul server (in ``-dev`` mode), and actually run ``terraform`` via
300
+ ``rake`` and confirm that Terraform both runs correctly and correctly updates state in Consul. The terraform configurations
301
+ and rakefiles used can be found in ``spec/acceptance``. The terraform configurations use only the
302
+ [consul](https://www.terraform.io/docs/providers/consul/index.html) provider, to remove any external dependencies other than
303
+ Consul (which is already used to test remote state).
304
+
305
+ Note that the acceptance tests depend on the GNU coreutils ``timeout`` command.
306
+
307
+ ## Release Checklist
308
+
309
+ 1. Ensure Circle tests are passing.
310
+ 2. Build docs locally (``bundle exec rake yard:serve``) and ensure they look correct.
311
+ 3. Ensure changelog entries exist for all changes since the last release.
312
+ 4. Bump the version in ``lib/tfwrapper/version.rb``
313
+ 5. Change the version specifier in the "Installation" section of this README, above, as appropriate.
314
+ 6. Commit those changes, open a PR for the release. Once shipped and Circle passes, merge and pull down locally.
315
+ 7. Deployment is done locally, with ``bundle exec rake release``.
316
+
317
+ ## License
318
+
319
+ The gem is available as open source under the terms of the
320
+ [MIT License](http://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ require 'bundler/setup'
6
+ require 'bundler/gem_tasks'
7
+ require 'rake/clean'
8
+ require 'yard'
9
+ require 'rspec/core/rake_task'
10
+ require 'rubocop/rake_task'
11
+
12
+ CLOBBER.include 'pkg'
13
+
14
+ desc 'Run RuboCop on the lib directory'
15
+ RuboCop::RakeTask.new(:rubocop) do |task|
16
+ task.fail_on_error = true
17
+ end
18
+
19
+ namespace :spec do
20
+ desc 'run ALL spec tests'
21
+ task all: %i[unit acceptance]
22
+
23
+ desc 'run unit tests'
24
+ RSpec::Core::RakeTask.new(:unit) do |t|
25
+ t.rspec_opts = ['--require', 'spec_helper']
26
+ t.pattern = 'spec/unit/*_spec.rb'
27
+ end
28
+
29
+ desc 'run acceptance tests'
30
+ RSpec::Core::RakeTask.new(:acceptance) do |t|
31
+ t.rspec_opts = ['--require', 'spec_helper']
32
+ t.pattern = 'spec/acceptance/*_spec.rb'
33
+ end
34
+ end
35
+
36
+ namespace :yard do
37
+ YARD::Rake::YardocTask.new do |t|
38
+ t.name = 'generate'
39
+ t.files = ['lib/**/*.rb'] # optional
40
+ t.options = ['--private', '--protected'] # optional
41
+ t.stats_options = ['--list-undoc'] # optional
42
+ end
43
+
44
+ desc 'serve YARD documentation on port 8808 (restart to regenerate)'
45
+ task serve: [:generate] do
46
+ puts 'Running YARD server on port 8808'
47
+ puts 'Use Ctrl+C to exit server.'
48
+ YARD::CLI::Server.run
49
+ end
50
+ end
51
+
52
+ desc 'Run specs and rubocop before pushing'
53
+ task pre_commit: %i[spec:unit rubocop]
54
+
55
+ desc 'Display the list of available rake tasks'
56
+ task :help do
57
+ system('rake -T')
58
+ end
59
+
60
+ task default: [:help]
data/circle.yml ADDED
@@ -0,0 +1,24 @@
1
+
2
+ dependencies:
3
+ cache_directories:
4
+ - "~/.rvm/gems"
5
+ pre:
6
+ - sudo add-apt-repository -y ppa:git-core/ppa && sudo apt-get update && sudo apt-get install git
7
+ override:
8
+ - 'bundle install'
9
+ - 'rvm 2.0.0-p598 exec bundle install'
10
+ - 'rvm 2.1.8 exec bundle install'
11
+ - 'rvm 2.2.5 exec bundle install'
12
+ - 'rvm 2.3.1 exec bundle install'
13
+
14
+ test:
15
+ override:
16
+ - 'bundle exec ruby --version'
17
+ - 'bundle exec rake spec:unit'
18
+ - 'bundle exec rake rubocop'
19
+ - 'rvm 2.0.0-p598 exec bundle exec rake spec:unit'
20
+ - 'rvm 2.1.8 exec bundle exec rake spec:unit'
21
+ - 'rvm 2.2.5 exec bundle exec rake spec:unit'
22
+ - 'rvm 2.3.1 exec bundle exec rake spec:unit'
23
+ - 'rvm 2.3.1 exec bundle exec rake spec:acceptance'
24
+ - 'bundle exec rake yard:generate'
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'open3'
4
+ require 'English'
5
+
6
+ # TFWrapper
7
+ module TFWrapper
8
+ # generic helper functions for TFWrapper
9
+ module Helpers
10
+ # Run a system command, print the command before running it. If it exits
11
+ # with a non-zero status, print the exit status and output and then
12
+ # `fail`.
13
+ #
14
+ # @param cmd [String] the command to run
15
+ def self.run_cmd(cmd)
16
+ puts "Running command: #{cmd}"
17
+ out = `#{cmd}`
18
+ status = $CHILD_STATUS.exitstatus
19
+ return if status.zero?
20
+ puts "Command exited #{status}:"
21
+ puts out
22
+ raise StandardError, "ERROR: Command failed: #{cmd}"
23
+ end
24
+
25
+ # popen2e wrapper to simultaneously stream command output and capture it.
26
+ #
27
+ # STDOUT and STDERR will be combined to the same stream, and returned as one
28
+ # string. This is because there doesn't seem to be a safe, cross-platform
29
+ # way to both capture and stream STDOUT and STDERR separately that isn't
30
+ # prone to deadlocking if large chunks of data are written to the pipes.
31
+ #
32
+ # @param cmd [String] command to run
33
+ # @param pwd [String] directory/path to run command in
34
+ # @return [Array] - out_err [String], exit code [Fixnum]
35
+ def self.run_cmd_stream_output(cmd, pwd)
36
+ old_sync = $stdout.sync
37
+ $stdout.sync = true
38
+ all_out_err = ''.dup
39
+ exit_status = nil
40
+ Open3.popen2e(cmd, chdir: pwd) do |stdin, stdout_and_err, wait_thread|
41
+ stdin.close_write
42
+ begin
43
+ while (line = stdout_and_err.gets)
44
+ puts line
45
+ all_out_err << line
46
+ end
47
+ rescue IOError => e
48
+ STDERR.puts "IOError: #{e}"
49
+ end
50
+ exit_status = wait_thread.value.exitstatus
51
+ end
52
+ # rubocop:disable Style/RedundantReturn
53
+ $stdout.sync = old_sync
54
+ return all_out_err, exit_status
55
+ # rubocop:enable Style/RedundantReturn
56
+ end
57
+
58
+ # Ensure that a given list of environment variables are present and
59
+ # non-empty. Raise StandardError if any aren't.
60
+ #
61
+ # @param required [Array] list of required environment variables
62
+ def self.check_env_vars(required)
63
+ missing = []
64
+ required.each do |name|
65
+ if !ENV.include?(name)
66
+ puts "ERROR: Environment variable '#{name}' must be set."
67
+ missing << name
68
+ elsif ENV[name].to_s.strip.empty?
69
+ puts "ERROR: Environment variable '#{name}' must not be empty."
70
+ missing << name
71
+ end
72
+ end
73
+ # rubocop:disable Style/GuardClause
74
+ unless missing.empty?
75
+ raise StandardError, 'Missing or empty environment variables: ' \
76
+ "#{missing}"
77
+ end
78
+ # rubocop:enable Style/GuardClause
79
+ end
80
+ end
81
+ end