elastic_beans 0.10.0.alpha1 → 0.10.0.alpha2

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
  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