elastic_beans 0.10.0.alpha1 → 0.10.0.alpha2

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
  SHA1:
3
- metadata.gz: 44f1c4f70c8a932819315f3d02623b75423ff299
4
- data.tar.gz: 270d9d55029d816b5f45f91b13d2ff3e89e6b456
3
+ metadata.gz: 9c681be8f1584e92ac3326f36602a6f006739fae
4
+ data.tar.gz: 2d7efd88e9401d2c8ff327f15992de92ba94323d
5
5
  SHA512:
6
- metadata.gz: c9808cfe16431ef5bd7ac8df11ac31e85331d36c0fefb89d24c6aa95bd91ca593762e09db378c3913a29bd0dd4d732cc4e0b831aaf39645684cbd123cc720acc
7
- data.tar.gz: e223d9b76c7b922dd3271958458e86a100eaf45842c47012b33de0d4b647fc405f68d009f56daa7cb9d37365dec7230181b93631240fb0bbf0de8a26daad345c
6
+ metadata.gz: 03076cb44db365dcf4d20fdfe45aad0a1d845b9ad346fdb8b6074be7073045c4f94fe411e637aafd965ddce9bf54dbd03cde18f1e675d89ce75fbde5be9e462d
7
+ data.tar.gz: fefcc5407eb3a0f5a19e317b85fb1f6c2aa0453d5ad1513648a5260fb3e01b9b55e17489641e2a9e0f63b8da6544f15f6825c16ba07bc52eab1aa2c1e77fc8bc
@@ -0,0 +1,20 @@
1
+ version: 2
2
+ jobs:
3
+ build:
4
+ docker:
5
+ - image: ruby:latest
6
+ working_directory: /elastic_beans
7
+ steps:
8
+ - checkout
9
+ - run:
10
+ name: Configure git
11
+ command: |
12
+ git config --global user.name "CircleCI"
13
+ git config --global user.email "ops-ro@onemedical.com"
14
+ - run: bundle install --jobs=4 --retry=3
15
+ - run:
16
+ command: bundle exec rake
17
+ environment:
18
+ SPEC_OPTS: --format progress --format RspecJunitFormatter -o tmp/test_results/rspec/junit.xml
19
+ - store_test_results:
20
+ path: tmp/test_results/
@@ -25,7 +25,7 @@ Gem::Specification.new do |spec|
25
25
  spec.add_dependency "ruby-progressbar", "~> 1.2"
26
26
  spec.add_dependency "rubyzip", "~> 1.2"
27
27
  spec.add_dependency "thor", "~> 0.19.0"
28
- spec.add_dependency "tty-table", "~> 0.7.0"
28
+ spec.add_dependency "tty-table", "~> 0.8.0"
29
29
 
30
30
  spec.add_development_dependency "bundler", "~> 1.12"
31
31
  spec.add_development_dependency "rake", "~> 10.0"
@@ -3,6 +3,7 @@ require "timeout"
3
3
  require "aws-sdk"
4
4
  require "elastic_beans/aws/cloudformation_stack"
5
5
  require "elastic_beans/error"
6
+ require "elastic_beans/error/access_denied"
6
7
 
7
8
  module ElasticBeans
8
9
  # An Elastic Beanstalk application which should exist.
@@ -42,7 +43,7 @@ module ElasticBeans
42
43
  response = elastic_beanstalk.describe_applications(application_names: [name])
43
44
  application = response.applications[0]
44
45
  unless application
45
- raise MissingApplicationError
46
+ raise MissingApplicationError.new(application: self)
46
47
  end
47
48
 
48
49
  templates = application.configuration_templates
@@ -61,7 +62,7 @@ module ElasticBeans
61
62
  # Returns the ElasticBeans::EnvVars for this application.
62
63
  def env_vars
63
64
  unless exists?
64
- raise MissingApplicationError
65
+ raise MissingApplicationError.new(application: self)
65
66
  end
66
67
 
67
68
  EnvVars.new(application: self, s3: s3)
@@ -96,6 +97,8 @@ module ElasticBeans
96
97
  raise MissingBucketError
97
98
  end
98
99
  @bucket_name = bucket.name
100
+ rescue ::Aws::S3::Errors::AccessDenied
101
+ raise AccessDeniedS3Error.new
99
102
  end
100
103
 
101
104
  # Enqueues a one-off Exec::Command to be run on the application's +exec+ environment.
@@ -112,45 +115,31 @@ module ElasticBeans
112
115
  end
113
116
  command.metadata[:bucket] = bucket_name
114
117
  command.metadata[:key] = "#{command_key_prefix}#{command.id}.json"
118
+ s3.put_object(
119
+ bucket: bucket_name,
120
+ key: command.metadata[:key],
121
+ body: command.to_json,
122
+ )
115
123
 
116
124
  sqs.send_message(
117
125
  queue_url: exec_queue_url,
118
126
  message_body: command.to_json,
119
127
  )
128
+ rescue ::Aws::S3::Errors::AccessDenied
129
+ raise AccessDeniedS3Error.new(bucket: bucket_name, key: command.metadata[:key])
120
130
  end
121
131
 
122
- # Fetches commands enqueued in the +exec_queue_url+.
123
- # Polls the queue for 5 seconds.
124
- #
125
- # If a large number of commands is enqueued they may not all be found.
132
+ # Fetches up to 100 previously-enqueued commands that are running or scheduled to run.
133
+ # Commands are deserialized from metadata files in a well-known location in S3.
134
+ # The metadata is created when the command is enqueued.
135
+ # The instances in the exec environment update the metadata when executing a command, and remove the metadata when they are done.
126
136
  #
127
- # Raises an error if the exec queue cannot be found.
137
+ # Raises an error if the application does not exist.
128
138
  def enqueued_commands
129
- messages = []
130
- Timeout.timeout(5) do
131
- loop do
132
- messages += sqs.receive_message(
133
- queue_url: exec_queue_url,
134
- max_number_of_messages: 10,
135
- visibility_timeout: 5,
136
- wait_time_seconds: 5,
137
- ).messages
138
- end
139
+ unless exists?
140
+ raise MissingApplicationError.new(application: self)
139
141
  end
140
- rescue Timeout::Error
141
- messages.map { |msg| Exec::Command.from_json(msg.body) }
142
- end
143
142
 
144
- def exec_queue_url
145
- stack.stack_output("ExecQueueUrl")
146
- end
147
-
148
- # Fetches commands running in the Environment::Exec environment.
149
- # Commands are deserialized from metadata files in a well-known location in S3.
150
- # The instances update the metadata when executing a command, and remove the metadata when they are done.
151
- #
152
- # Raises an error if the exec environment cannot be found.
153
- def running_commands
154
143
  # Ignoring truncation for simplicity; >100 commands will just have to suffer.
155
144
  objects = s3.list_objects_v2(
156
145
  bucket: bucket_name,
@@ -168,6 +157,36 @@ module ElasticBeans
168
157
  }
169
158
  end
170
159
 
160
+ # Fetches the +ExecQueueUrl+ Output from the application CloudFormation stack.
161
+ # The stack must have the same name as the application.
162
+ def exec_queue_url
163
+ stack.stack_output("ExecQueueUrl")
164
+ end
165
+
166
+ # Schedules the given ElasticBeans::Exec::Command or +id+ for termination.
167
+ # Removes the metadata for the command and relies on the SQSConsumer to terminate it.
168
+ #
169
+ # Raises an error if the application does not exist.
170
+ def kill_command(command_or_id)
171
+ unless exists?
172
+ raise MissingApplicationError.new(application: self)
173
+ end
174
+
175
+ if command_or_id.is_a?(ElasticBeans::Exec::Command)
176
+ command_id = command_or_id.id
177
+ else
178
+ command_id = command_or_id
179
+ end
180
+
181
+ key = "#{command_key_prefix}#{command_id}.json"
182
+ s3.delete_object(
183
+ bucket: bucket_name,
184
+ key: key,
185
+ )
186
+ rescue ::Aws::S3::Errors::AccessDenied
187
+ raise AccessDeniedS3Error.new(bucket: bucket_name, key: key)
188
+ end
189
+
171
190
  # Returns an ElasticBeans::ApplicationVersion for each version of the Elastic Beanstalk application.
172
191
  def versions
173
192
  response = elastic_beanstalk.describe_application_versions(application_name: name)
@@ -199,6 +218,7 @@ module ElasticBeans
199
218
 
200
219
  attr_reader :elastic_beanstalk, :s3, :stack
201
220
 
221
+ # Returns the S3 prefix under which command metadata is stored.
202
222
  def command_key_prefix
203
223
  @command_key_prefix ||= "#{name}/exec/command/"
204
224
  end
@@ -217,8 +237,12 @@ module ElasticBeans
217
237
  # :nodoc: all
218
238
  # @!visibility private
219
239
  class MissingApplicationError < ElasticBeans::Error
240
+ def initialize(application:)
241
+ @application = application
242
+ end
243
+
220
244
  def message
221
- "Application `#{@application_name}' does not exist. Please create the Elastic Beanstalk application using a CloudFormation stack."
245
+ "Application `#{@application.name}' does not exist. Please create the Elastic Beanstalk application using a CloudFormation stack."
222
246
  end
223
247
  end
224
248
 
@@ -1,5 +1,6 @@
1
1
  require "aws-sdk"
2
2
  require "elastic_beans/error"
3
+ require "elastic_beans/error/access_denied"
3
4
 
4
5
  module ElasticBeans
5
6
  # :nodoc: all
@@ -39,6 +40,8 @@ module ElasticBeans
39
40
  s
40
41
  rescue ::Aws::CloudFormation::Errors::ValidationError
41
42
  raise MissingStackError.new(stack_name: stack_name)
43
+ rescue ::Aws::CloudFormation::Errors::AccessDenied
44
+ raise AccessDeniedCloudFormationError.new(stack_name: stack_name)
42
45
  end
43
46
 
44
47
  class MissingStackError < ElasticBeans::Error
@@ -98,6 +98,21 @@ class ElasticBeans::CLI < Thor
98
98
  error(e)
99
99
  end
100
100
 
101
+ desc ElasticBeans::Command::Kill::USAGE, ElasticBeans::Command::Kill::DESC
102
+ long_desc ElasticBeans::Command::Kill::LONG_DESC
103
+ option :application, aliases: %w(-a), required: true, desc: APPLICATION_DESC
104
+ def kill(command_id)
105
+ @verbose = options[:verbose]
106
+ ElasticBeans::Command::Kill.new(
107
+ application: application(
108
+ name: options[:application],
109
+ ),
110
+ ui: ui,
111
+ ).run(command_id)
112
+ rescue StandardError => e
113
+ error(e)
114
+ end
115
+
101
116
  desc ElasticBeans::Command::Ps::USAGE, ElasticBeans::Command::Ps::DESC
102
117
  long_desc ElasticBeans::Command::Ps::LONG_DESC
103
118
  option :application, aliases: %w(-a), required: true, desc: APPLICATION_DESC
@@ -21,8 +21,9 @@ Requires AWS credentials to be set in the environment, i.e. AWS_ACCESS_KEY_ID an
21
21
  end
22
22
 
23
23
  def run(*command_parts)
24
- ui.info("Running `#{command_parts.join(" ")}' on #{application.name}...")
25
- application.enqueue_command(command(command_parts))
24
+ command = command(command_parts)
25
+ ui.info("Running `#{command.command_string}' on #{application.name}... (ID=#{command.id})")
26
+ application.enqueue_command(command)
26
27
  end
27
28
 
28
29
  private
@@ -0,0 +1,38 @@
1
+ require "aws-sdk"
2
+ require "elastic_beans/error/access_denied"
3
+
4
+ module ElasticBeans
5
+ module Command
6
+ # :nodoc: all
7
+ class Kill
8
+ USAGE = "kill COMMAND_ID"
9
+ DESC = "Kill a running command or cancel a scheduled command that was enqueued with `exec`"
10
+ LONG_DESC = <<-LONG_DESC
11
+ Kill a running command or cancel a scheduled command that was enqueued with `exec`.
12
+ You can find an enqueued command's ID by running `ps`.
13
+
14
+ Commands are run in an "exec" environment, separate from your webserver or worker environments.
15
+ When they are enqueued, metadata is created in S3 and removed when the command is complete.
16
+ Removing that metadata cancels the command.
17
+ The command is sent a SIGTERM, and then a SIGKILL if it has not yet died.
18
+
19
+ Requires AWS credentials to be set in the environment, i.e. AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY.
20
+ LONG_DESC
21
+
22
+ def initialize(application:, ui:)
23
+ @application = application
24
+ @ui = ui
25
+ end
26
+
27
+ def run(command_id)
28
+ ui.info("Scheduling command '#{command_id}' on #{application.name} for termination...")
29
+ application.kill_command(command_id)
30
+ ui.info("It may be a few moments before the command terminates.")
31
+ end
32
+
33
+ private
34
+
35
+ attr_reader :application, :ui
36
+ end
37
+ end
38
+ end
@@ -12,6 +12,7 @@ Requires AWS credentials to be set in the environment, i.e. AWS_ACCESS_KEY_ID an
12
12
  LONG_DESC
13
13
 
14
14
  COLUMNS = {
15
+ "COMMAND ID" => ->(command) { command.id },
15
16
  "INSTANCE" => ->(command) { command.instance_id || SCHEDULED_INSTANCE },
16
17
  "RUN TIME" => ->(command) {
17
18
  if command.start_time
@@ -34,23 +35,14 @@ Requires AWS credentials to be set in the environment, i.e. AWS_ACCESS_KEY_ID an
34
35
  end
35
36
 
36
37
  def run
37
- enqueued_commands = []
38
- running_commands = []
39
- ui.debug { "Fetching enqueued and running commands from #{application.name}..." }
40
- threads = [
41
- Thread.new do
42
- enqueued_commands = application.enqueued_commands
43
- end,
44
- Thread.new do
45
- running_commands = application.running_commands
46
- end,
47
- ]
48
- threads.each(&:join)
38
+ ui.debug { "Fetching enqueued commands from #{application.name}..." }
39
+ enqueued_commands = application.enqueued_commands
49
40
 
41
+ enqueued_commands, running_commands = enqueued_commands.partition { |cmd| cmd.start_time.nil? }
50
42
  running_commands.sort_by!(&:start_time)
51
43
  commands = running_commands + enqueued_commands
52
44
  if commands.any?
53
- ui.table(level: :info, columns: COLUMNS, rows: running_commands + enqueued_commands)
45
+ ui.table(level: :info, columns: COLUMNS, rows: commands)
54
46
  else
55
47
  ui.info("No commands enqueued or running")
56
48
  end
@@ -2,6 +2,7 @@ require "elastic_beans/command/configure"
2
2
  require "elastic_beans/command/create"
3
3
  require "elastic_beans/command/deploy"
4
4
  require "elastic_beans/command/exec"
5
+ require "elastic_beans/command/kill"
5
6
  require "elastic_beans/command/ps"
6
7
  require "elastic_beans/command/restart"
7
8
  require "elastic_beans/command/scale"
@@ -1,6 +1,7 @@
1
1
  require "json"
2
2
  require "aws-sdk"
3
3
  require "elastic_beans/error"
4
+ require "elastic_beans/error/access_denied"
4
5
 
5
6
  module ElasticBeans
6
7
  # Interfaces with environment variable storage for the Elastic Beanstalk application.
@@ -24,7 +25,7 @@ module ElasticBeans
24
25
  rescue ::Aws::S3::Errors::NotFound
25
26
  {}
26
27
  rescue ::Aws::S3::Errors::Forbidden
27
- raise CannotAccessConfigError.new(bucket_name: application.bucket_name, key: s3_key)
28
+ raise AccessDeniedS3Error.new(bucket: application.bucket_name, key: s3_key)
28
29
  end
29
30
 
30
31
  # Updates the environment variables stored in S3 by merging it with the given +env_hash+.
@@ -51,19 +52,5 @@ module ElasticBeans
51
52
  def env_script(env_hash)
52
53
  JSON.dump(env_hash)
53
54
  end
54
-
55
- # :nodoc: all
56
- # @!visibility private
57
- class CannotAccessConfigError < ElasticBeans::Error
58
- def initialize(bucket_name:, key:)
59
- @bucket_name = bucket_name
60
- @key = key
61
- end
62
-
63
- def message
64
- "Cannot access configuration stored in S3 with bucket `#{@bucket_name}' and key `#{@key}'." \
65
- " Please ask an administrator of your AWS account administrator to give you access."
66
- end
67
- end
68
55
  end
69
56
  end
@@ -0,0 +1,38 @@
1
+ require "elastic_beans/error"
2
+
3
+ # :nodoc: all
4
+ # @!visibility private
5
+ class AccessDeniedCloudFormationError < ElasticBeans::Error
6
+ def initialize(stack_name:)
7
+ @stack_name = stack_name
8
+ end
9
+
10
+ def message
11
+ <<-MESSAGE
12
+ Access to CloudFormation stack '#{@stack_name}' was denied.
13
+
14
+ Please check with your AWS administrator to give you full permission to access that stack in CloudFormation.
15
+ MESSAGE
16
+ end
17
+ end
18
+
19
+ # :nodoc: all
20
+ # @!visibility private
21
+ class AccessDeniedS3Error < ElasticBeans::Error
22
+ def initialize(bucket: nil, key: nil)
23
+ @bucket = bucket
24
+ @key = key
25
+ end
26
+
27
+ def message
28
+ msg = ""
29
+ if @bucket || @key
30
+ msg << "Access to bucket '#{@bucket}' key '#{@key}' was denied.\n"
31
+ else
32
+ msg << "Access to S3 was denied.\n"
33
+ end
34
+ msg + <<-MESSAGE
35
+ Please check with your AWS administrator to give you full permission to access elastic_beans resources in S3.
36
+ MESSAGE
37
+ end
38
+ end
@@ -6,6 +6,8 @@ require "time"
6
6
  # :nodoc: all
7
7
  # @!visibility private
8
8
  class SQSConsumer
9
+ LOOP_PERIOD = 1
10
+
9
11
  def initialize(instance_id:, logdir:, queue_url:, s3:, sqs:)
10
12
  @instance_id = instance_id
11
13
  @logdir = logdir
@@ -23,9 +25,15 @@ class SQSConsumer
23
25
  log("Starting message receive loop")
24
26
  loop do
25
27
  begin
26
- sleep 1
28
+ sleep(LOOP_PERIOD)
27
29
  if (message = receive_message)
28
30
  command = command_from_message(message)
31
+ unless metadata_exists?(command: command)
32
+ delete_message(message)
33
+ log_command("Skipping command ID=#{command['id']} `#{command['command']}' because it was killed")
34
+ next
35
+ end
36
+
29
37
  log_command("Executing command ID=#{command['id']} `#{command['command']}' on host #{`hostname`.chomp} pid #{command_pid}...")
30
38
  start_time = Time.now
31
39
  @command_pid = Process.spawn(
@@ -35,10 +43,38 @@ class SQSConsumer
35
43
  )
36
44
  delete_message(message)
37
45
  update_metadata(command: command, start_time: start_time)
46
+
47
+ # poll command metadata to see if it is still available, if it disappears then kill the process
48
+ killed_thread = Thread.new do
49
+ loop do
50
+ sleep 5
51
+
52
+ if !metadata_exists?(command: command)
53
+ if already_killed?
54
+ log_command(
55
+ "Sending KILL signal to command ID=#{command['id']} `#{command['command']}' on host #{`hostname`.chomp} pid #{command_pid}" \
56
+ " because it was killed and has not terminated yet"
57
+ )
58
+ Process.kill("KILL", command_pid)
59
+ break
60
+ else
61
+ log_command(
62
+ "Sending TERM signal to command ID=#{command['id']} `#{command['command']}' on host #{`hostname`.chomp} pid #{command_pid}" \
63
+ " because it was killed"
64
+ )
65
+ Process.kill("TERM", command_pid)
66
+ @killed = true
67
+ end
68
+ end
69
+ end
70
+ end
71
+
38
72
  _, status = Process.wait2(command_pid)
73
+ killed_thread.kill if killed_thread.alive?
39
74
  log_command("Command ID=#{command['id']} `#{command['command']}' exited on host #{`hostname`.chomp}: #{status}")
40
75
 
41
76
  @command_pid = nil
77
+ @killed = nil
42
78
  remove_metadata(command: command)
43
79
  end
44
80
  rescue StandardError => e
@@ -89,6 +125,10 @@ class SQSConsumer
89
125
  $stderr.puts e.backtrace.join("\n")
90
126
  end
91
127
 
128
+ def already_killed?
129
+ @killed
130
+ end
131
+
92
132
  def receive_message
93
133
  sqs.receive_message(
94
134
  queue_url: queue_url,
@@ -123,6 +163,21 @@ class SQSConsumer
123
163
  log("[update_metadata] #{e.class.name}: #{e.message}\n#{e.backtrace.join("\n")}")
124
164
  end
125
165
 
166
+ def metadata_exists?(command:)
167
+ metadata = command['metadata']
168
+ if metadata && metadata['bucket'] && metadata['key']
169
+ s3.head_object(
170
+ bucket: metadata['bucket'],
171
+ key: metadata['key'],
172
+ )
173
+ true
174
+ end
175
+ rescue ::Aws::S3::Errors::NotFound
176
+ false
177
+ rescue StandardError => e
178
+ log("[metadata_exists] #{e.class.name}: #{e.message}\n#{e.backtrace.join("\n")}")
179
+ end
180
+
126
181
  def remove_metadata(command:)
127
182
  metadata = command['metadata']
128
183
  if metadata && metadata['bucket'] && metadata['key']
@@ -1,3 +1,3 @@
1
1
  module ElasticBeans
2
- VERSION = "0.10.0.alpha1"
2
+ VERSION = "0.10.0.alpha2"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: elastic_beans
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.0.alpha1
4
+ version: 0.10.0.alpha2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Adam Stegman
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-04-20 00:00:00.000000000 Z
11
+ date: 2017-04-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aws-sdk
@@ -114,14 +114,14 @@ dependencies:
114
114
  requirements:
115
115
  - - "~>"
116
116
  - !ruby/object:Gem::Version
117
- version: 0.7.0
117
+ version: 0.8.0
118
118
  type: :runtime
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
121
  requirements:
122
122
  - - "~>"
123
123
  - !ruby/object:Gem::Version
124
- version: 0.7.0
124
+ version: 0.8.0
125
125
  - !ruby/object:Gem::Dependency
126
126
  name: bundler
127
127
  requirement: !ruby/object:Gem::Requirement
@@ -173,6 +173,7 @@ executables:
173
173
  extensions: []
174
174
  extra_rdoc_files: []
175
175
  files:
176
+ - ".circleci/config.yml"
176
177
  - ".gitignore"
177
178
  - ".rspec"
178
179
  - Gemfile
@@ -181,7 +182,6 @@ files:
181
182
  - Rakefile
182
183
  - bin/console
183
184
  - bin/setup
184
- - circle.yml
185
185
  - elastic_beans.gemspec
186
186
  - exe/beans
187
187
  - lib/elastic_beans.rb
@@ -196,6 +196,7 @@ files:
196
196
  - lib/elastic_beans/command/deploy.rb
197
197
  - lib/elastic_beans/command/exec.rb
198
198
  - lib/elastic_beans/command/get_env.rb
199
+ - lib/elastic_beans/command/kill.rb
199
200
  - lib/elastic_beans/command/ps.rb
200
201
  - lib/elastic_beans/command/restart.rb
201
202
  - lib/elastic_beans/command/scale.rb
@@ -219,6 +220,7 @@ files:
219
220
  - lib/elastic_beans/environment/webserver.rb
220
221
  - lib/elastic_beans/environment/worker.rb
221
222
  - lib/elastic_beans/error.rb
223
+ - lib/elastic_beans/error/access_denied.rb
222
224
  - lib/elastic_beans/error/environments_not_ready.rb
223
225
  - lib/elastic_beans/exec.rb
224
226
  - lib/elastic_beans/exec/command.rb
data/circle.yml DELETED
@@ -1,24 +0,0 @@
1
- ---
2
- machine:
3
- environment:
4
- RSPEC_OPTS: "-r rspec_junit_formatter --format progress --format RspecJunitFormatter -o $CIRCLE_TEST_REPORTS/rspec/junit.xml"
5
-
6
- dependencies:
7
- override:
8
- - |
9
- case $CIRCLE_NODE_INDEX in
10
- 0)
11
- rvm-exec 2.3.1 bash -c "bundle check --path=vendor/bundle_2.3 || bundle install --path=vendor/bundle_2.3 --jobs=4 --retry=3"
12
- ;;
13
- 1)
14
- rvm-exec 2.2.5 bash -c "bundle check --path=vendor/bundle_2.2 || bundle install --path=vendor/bundle_2.2 --jobs=4 --retry=3"
15
- ;;
16
- esac
17
- post:
18
- - git config --global user.name "CircleCI"
19
- - git config --global user.email "ops-ro@onemedical.com"
20
-
21
- test:
22
- override:
23
- - case $CIRCLE_NODE_INDEX in 0) rvm-exec 2.3.1 bash -c "bundle check --path=vendor/bundle_2.3 && bundle exec rake" ;; 1) rvm-exec 2.2.5 bash -c "bundle check --path=vendor/bundle_2.2 && bundle exec rake" ;; esac:
24
- parallel: true