broadside 1.0.3 → 1.1.0.pre

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: 0536213915fa9c027fe33ff15b4e9bec02a07b15
4
- data.tar.gz: 9ae58ab78407da3477ebb1f2eee07264b7b7477a
3
+ metadata.gz: dd26f89e64ffb9a89fbeba5e5b51a72b4bd8588b
4
+ data.tar.gz: 3d1d2f828a45cb8968851e37ef5dbd9ed5d5e01d
5
5
  SHA512:
6
- metadata.gz: 374b5c4d34b93cc0c357d39dce660c4d617895e5183bfb5bb30e17977be45dbe0b31b5dee0c04046f8eb27faf5bba984466c9b8b6380b4c8f0188c2ef8ae7838
7
- data.tar.gz: 2a6fa73a8ce47272c3613d35eccfb04fe55677b294aebeeab99dc95dfe2c4cd03d328f416946db290b7617982e6b1435d911e1c287656e5706b14b4ffcb7a59a
6
+ metadata.gz: 6b4ddb6d9f87222b23fa9f626d96d0eb3ffd4f48e5b351bb71ea154e18f43f79eb80910629b0d0400b222b00b820f2beb802ea7baf1bcc49a4ce46fa5a1450fc
7
+ data.tar.gz: 993493358dca3151d56f3a8e7b200a804b7c16297dea2c1c0bb9e722d0c9a68bf3d8a65d659caae37d00ebeeed32ef75ce32a04b2ae01a51f28f023f04abe541
data/CHANGELOG.md CHANGED
@@ -1,3 +1,6 @@
1
+ # 1.1.0
2
+ - [#16](https://github.com/lumoslabs/broadside/pull/16): Add bootstrap command; add specs
3
+
1
4
  # 1.0.3
2
5
  - [#12](https://github.com/lumoslabs/broadside/issues/12): Fix isssue with not being to use ssh, bash, logtail commands without specifying instance index
3
6
 
data/README.md CHANGED
@@ -29,16 +29,36 @@ Broadside.configure do |config|
29
29
  scale: 15,
30
30
  command: ['bundle', 'exec', 'rake', 'resque:work'],
31
31
  env_file: '../.env.production'
32
- }
32
+ },
33
33
  staging_web: {
34
34
  scale: 1,
35
35
  command: ['bundle', 'exec', 'puma'],
36
36
  env_file: '../.env.staging'
37
- }
37
+ },
38
38
  staging_worker: {
39
39
  scale: 1,
40
40
  command: ['bundle', 'exec', 'rake', 'resque:work'],
41
41
  env_file: '../.env.staging'
42
+ },
43
+ # Example with a task_definition and service configuration which you use to bootstrap a service and
44
+ # initial task definition
45
+ game_save_as_json_blob_stream: {
46
+ scale: 1,
47
+ command: ['java', '-cp', '*:.', 'path.to.MyClass'],
48
+ env_file: '.env.production',
49
+ service_config: {
50
+ deployment_configuration: {
51
+ minimum_healthy_percent: 0.5,
52
+ }
53
+ },
54
+ task_definition_config: {
55
+ container_definitions: [
56
+ {
57
+ cpu: 1,
58
+ memory: 2000,
59
+ }
60
+ ]
61
+ }
42
62
  }
43
63
  }
44
64
  end
data/bin/broadside CHANGED
@@ -42,6 +42,11 @@ accept Fixnum do |val|
42
42
  val.to_i
43
43
  end
44
44
 
45
+ desc 'Bootstrap your service and task definition.'
46
+ command :bootstrap do |b|
47
+ add_shared_deploy_configs(b)
48
+ end
49
+
45
50
  desc 'Deploy your application.'
46
51
  command :deploy do |d|
47
52
  d.desc 'Deploys without running migrations'
data/broadside.gemspec CHANGED
@@ -17,10 +17,12 @@ Gem::Specification.new do |spec|
17
17
  spec.executables = ['broadside']
18
18
  spec.require_paths = ["lib"]
19
19
 
20
+ spec.add_dependency 'activesupport', '>= 3', '< 5'
20
21
  spec.add_dependency 'aws-sdk', '~> 2.3'
21
- spec.add_dependency 'rainbow', '~> 2.1'
22
- spec.add_dependency 'gli', '~> 2.13'
23
22
  spec.add_dependency 'dotenv', '>= 0.9.0'
23
+ spec.add_dependency 'gli', '~> 2.13'
24
+ spec.add_dependency 'rainbow', '~> 2.1'
25
+
24
26
  spec.add_development_dependency 'rspec'
25
27
  spec.add_development_dependency 'bundler', '~> 1.9'
26
28
  spec.add_development_dependency 'fakefs'
data/lib/broadside.rb CHANGED
@@ -4,10 +4,10 @@ require 'broadside/configuration'
4
4
  require 'broadside/configuration/struct'
5
5
  require 'broadside/configuration/aws'
6
6
  require 'broadside/configuration/base'
7
- require 'broadside/configuration/deploy'
8
- require 'broadside/configuration/ecs'
7
+ require 'broadside/configuration/deploy_config'
8
+ require 'broadside/configuration/ecs_config'
9
9
  require 'broadside/deploy'
10
- require 'broadside/deploy/ecs'
10
+ require 'broadside/deploy/ecs_deploy'
11
11
  require 'broadside/version'
12
12
 
13
13
  module Broadside
@@ -22,14 +22,18 @@ module Broadside
22
22
  :env_vars,
23
23
  :command,
24
24
  :instance,
25
- :predeploy_commands
25
+ :predeploy_commands,
26
+ :service_config,
27
+ :task_definition_config
26
28
  )
27
29
 
28
30
  TARGET_ATTRIBUTE_VALIDATIONS = {
29
31
  scale: ->(target_attribute) { validate_types([Fixnum], target_attribute) },
30
32
  env_file: ->(target_attribute) { validate_types([String], target_attribute) },
31
33
  command: ->(target_attribute) { validate_types([Array, NilClass], target_attribute) },
32
- predeploy_commands: ->(target_attribute) { validate_predeploy(target_attribute) }
34
+ predeploy_commands: ->(target_attribute) { validate_predeploy(target_attribute) },
35
+ service_config: ->(target_attribute) { validate_types([Hash, NilClass], target_attribute) },
36
+ task_definition_config: ->(target_attribute) { validate_types([Hash, NilClass], target_attribute) }
33
37
  }
34
38
 
35
39
  def initialize
@@ -45,6 +49,8 @@ module Broadside
45
49
  @command = nil
46
50
  @predeploy_commands = DEFAULT_PREDEPLOY_COMMANDS
47
51
  @instance = 0
52
+ @service_config = nil
53
+ @task_definition_config = nil
48
54
  end
49
55
 
50
56
  # Validates format of deploy targets
@@ -86,6 +92,8 @@ module Broadside
86
92
  @scale ||= @targets[@target][:scale]
87
93
  @command = @targets[@target][:command]
88
94
  @predeploy_commands = @targets[@target][:predeploy_commands] if @targets[@target][:predeploy_commands]
95
+ @service_config = @targets[@target][:service_config]
96
+ @task_definition_config = @targets[@target][:task_definition_config]
89
97
  end
90
98
 
91
99
  private
@@ -100,14 +108,12 @@ module Broadside
100
108
 
101
109
  def self.validate_predeploy(target_attribute)
102
110
  return nil if target_attribute.nil?
103
-
104
111
  return 'predeploy_commands must be an array' unless target_attribute.is_a?(Array)
105
112
 
106
- target_attribute.each do |command|
107
- return "predeploy_command '#{command}' must be an array" unless command.is_a?(Array)
113
+ messages = target_attribute.reject { |cmd| cmd.is_a?(Array) }.map do |command|
114
+ "predeploy_command '#{command}' must be an array" unless command.is_a?(Array)
108
115
  end
109
-
110
- nil
116
+ messages.empty? ? nil : messages.join(', ')
111
117
  end
112
118
  end
113
119
  end
@@ -92,7 +92,7 @@ module Broadside
92
92
  end
93
93
 
94
94
  def gen_ssh_cmd(ip, options = { tty: false })
95
- opts = @deploy_config.ssh
95
+ opts = @deploy_config.ssh || {}
96
96
  cmd = 'ssh -o StrictHostKeyChecking=no'
97
97
  cmd << ' -t -t' if options[:tty]
98
98
  cmd << " -i #{opts[:keyfile]}" if opts[:keyfile]
@@ -1,3 +1,4 @@
1
+ require 'active_support/core_ext/hash'
1
2
  require 'aws-sdk'
2
3
  require 'open3'
3
4
  require 'pp'
@@ -6,15 +7,23 @@ require 'shellwords'
6
7
 
7
8
  module Broadside
8
9
  class EcsDeploy < Deploy
10
+
11
+ DEFAULT_DESIRED_COUNT = 0
12
+ DEFAULT_CONTAINER_DEFINITION = {
13
+ cpu: 1,
14
+ essential: true,
15
+ memory: 1000
16
+ }
17
+
9
18
  def initialize(opts)
10
19
  super(opts)
11
20
  config.ecs.verify(:cluster, :poll_frequency)
12
- check_service_existence
13
21
  end
14
22
 
15
23
  def deploy
16
24
  super do
17
- update_task
25
+ exception "Service #{family} does not exist!" unless service_exists?
26
+ update_task_revision
18
27
 
19
28
  begin
20
29
  update_service
@@ -22,17 +31,34 @@ module Broadside
22
31
  error 'Caught interrupt signal, rolling back...'
23
32
  rollback(1)
24
33
  error 'Deployment did not finish successfully.'
25
- abort
34
+ raise
26
35
  rescue StandardError => e
27
36
  error e.inspect, "\n", e.backtrace.join("\n")
28
37
  error 'Deploy failed! Rolling back...'
29
38
  rollback(1)
30
39
  error 'Deployment did not finish successfully.'
31
- abort
40
+ raise
32
41
  end
33
42
  end
34
43
  end
35
44
 
45
+ def bootstrap
46
+ unless get_latest_task_def_id
47
+ # Right now this creates a useless first revision and then update_task_revision will create a 2nd one
48
+ raise ArgumentError, "No first task definition and cannot create one" unless @deploy_config.task_definition_config
49
+
50
+ info "Creating an initial task definition for '#{family}' from the config..."
51
+ create_task_definition(family, @deploy_config.task_definition_config)
52
+ end
53
+
54
+ unless service_exists?
55
+ raise ArgumentError, "Service doesn't exist and cannot be created" unless @deploy_config.service_config
56
+
57
+ info "Service '#{family}' doesn't exist, creating..."
58
+ create_service(family, @deploy_config.service_config)
59
+ end
60
+ end
61
+
36
62
  def rollback(count = @deploy_config.rollback)
37
63
  super do
38
64
  begin
@@ -53,7 +79,7 @@ module Broadside
53
79
 
54
80
  def run
55
81
  super do
56
- update_task
82
+ update_task_revision
57
83
 
58
84
  begin
59
85
  run_command(@deploy_config.command)
@@ -66,7 +92,7 @@ module Broadside
66
92
  # runs before deploy commands using the latest task definition
67
93
  def run_predeploy
68
94
  super do
69
- update_task
95
+ update_task_revision
70
96
 
71
97
  begin
72
98
  @deploy_config.predeploy_commands.each do |command|
@@ -94,7 +120,7 @@ module Broadside
94
120
 
95
121
  def logtail
96
122
  super do
97
- ip = get_running_instance_ip_at_index!(@deploy_config.instance)
123
+ ip = get_running_instance_ips.fetch(@deploy_config.instance)
98
124
  debug "Tailing logs for running container at ip #{ip}..."
99
125
  search_pattern = Shellwords.shellescape(family)
100
126
  cmd = "docker logs -f --tail=10 `docker ps -n 1 --quiet --filter name=#{search_pattern}`"
@@ -105,7 +131,7 @@ module Broadside
105
131
 
106
132
  def ssh
107
133
  super do
108
- ip = get_running_instance_ip_at_index!(@deploy_config.instance)
134
+ ip = get_running_instance_ips.fetch(@deploy_config.instance)
109
135
  debug "Establishing an SSH connection to ip #{ip}..."
110
136
  exec gen_ssh_cmd(ip)
111
137
  end
@@ -113,7 +139,7 @@ module Broadside
113
139
 
114
140
  def bash
115
141
  super do
116
- ip = get_running_instance_ip_at_index!(@deploy_config.instance)
142
+ ip = get_running_instance_ips.fetch(@deploy_config.instance)
117
143
  debug "Running bash for running container at ip #{ip}..."
118
144
  search_pattern = Shellwords.shellescape(family)
119
145
  cmd = "docker exec -i -t `docker ps -n 1 --quiet --filter name=#{search_pattern}` bash"
@@ -124,49 +150,65 @@ module Broadside
124
150
 
125
151
  private
126
152
 
127
- def get_running_instance_ip_at_index(index)
128
- ips = get_running_instance_ips
129
- ips.size > index ? ips[index] : false
130
- end
131
-
132
- def get_running_instance_ip_at_index!(index)
133
- ip = get_running_instance_ip_at_index(index)
134
- return ip if ip
135
- exception 'Instance index greater than available instance count.'
136
- end
137
-
138
153
  # removes latest n task definitions
139
154
  def deregister_tasks(count)
140
- get_task_def_ids.last(count).each do |td_id|
155
+ get_task_definition_arns.last(count).each do |td_id|
141
156
  ecs_client.deregister_task_definition({task_definition: td_id})
142
157
  debug "Deregistered #{td_id}"
143
158
  end
144
159
  end
145
160
 
146
161
  # creates a new task revision using current directory's env vars and provided tag
147
- def update_task
148
- debug "Creating a new task definition..."
162
+ def update_task_revision
149
163
  new_task_def = create_new_task_revision
150
164
 
151
- container_def = new_task_def[:container_definitions].select { |c| c[:name] == family }.first
152
- container_def[:environment] = @deploy_config.env_vars
153
- container_def[:image] = image_tag
154
- container_def[:command] = @deploy_config.command
165
+ new_task_def[:container_definitions].select { |c| c[:name] == family }.first.tap do |container_def|
166
+ container_def[:environment] = @deploy_config.env_vars
167
+ container_def[:image] = image_tag
168
+ container_def[:command] = @deploy_config.command
169
+ end
155
170
 
171
+ debug "Creating a new task definition..."
156
172
  new_task_def_id = ecs_client.register_task_definition(new_task_def).task_definition.task_definition_arn
157
173
  debug "Successfully created #{new_task_def_id}"
158
174
  end
159
175
 
176
+ def create_service(name, options = {})
177
+ ecs_client.create_service(
178
+ {
179
+ cluster: config.ecs.cluster,
180
+ desired_count: DEFAULT_DESIRED_COUNT,
181
+ service_name: name,
182
+ task_definition: name
183
+ }.deep_merge(options)
184
+ )
185
+ end
186
+
187
+ def create_task_definition(name, options = {})
188
+ # Deep merge doesn't work with arrays, so build the hash and merge later
189
+ container_definitions = DEFAULT_CONTAINER_DEFINITION.merge(
190
+ name: name,
191
+ command: @deploy_config.command,
192
+ environment: @deploy_config.env_vars,
193
+ image: image_tag,
194
+ ).merge(options[:container_definitions].first || {})
195
+
196
+ ecs_client.register_task_definition(
197
+ { family: name }.deep_merge(options).merge(container_definitions: [container_definitions])
198
+ )
199
+ end
200
+
160
201
  # reloads the service using the latest task definition
161
202
  def update_service
162
203
  td = get_latest_task_def_id
163
204
  debug "Updating #{family} with scale=#{@deploy_config.scale} using task #{td}..."
164
- resp = ecs_client.update_service({
205
+ resp = ecs_client.update_service({
165
206
  cluster: config.ecs.cluster,
166
207
  service: family,
167
208
  task_definition: get_latest_task_def_id,
168
209
  desired_count: @deploy_config.scale
169
210
  })
211
+
170
212
  if resp.successful?
171
213
  begin
172
214
  ecs_client.wait_until(:services_stable, {cluster: config.ecs.cluster, services: [family]}) do |w|
@@ -208,6 +250,7 @@ module Broadside
208
250
  count: 1,
209
251
  started_by: "before_deploy:#{command_name}"[0...36]
210
252
  })
253
+
211
254
  if resp.successful?
212
255
  task_id = resp.tasks[0].task_arn
213
256
  debug "Launched #{command_name} task #{task_id}"
@@ -221,7 +264,7 @@ module Broadside
221
264
  end
222
265
  debug 'Task finished running, getting logs...'
223
266
  info "#{command_name} task container logs:\n#{get_container_logs(task_id)}"
224
- if(code = get_task_exit_code(task_id)) == 0
267
+ if (code = get_task_exit_code(task_id)) == 0
225
268
  debug "#{command_name} task #{task_id} exited with status code 0"
226
269
  else
227
270
  exception "#{command_name} task #{task_id} exited with a non-zero status code #{code}!"
@@ -259,7 +302,7 @@ module Broadside
259
302
  def get_running_instance_ips(task_ids = nil)
260
303
  task_arns = nil
261
304
  if task_ids.nil?
262
- task_arns = get_tasks
305
+ task_arns = get_task_arns
263
306
  if task_arns.empty?
264
307
  exception "No running tasks found for '#{family}' on cluster '#{config.ecs.cluster}' !"
265
308
  end
@@ -277,44 +320,32 @@ module Broadside
277
320
  ec2_instance_ids = container_instances.map { |ci| ci.ec2_instance_id }
278
321
  reservations = ec2_client.describe_instances({instance_ids: ec2_instance_ids}).reservations
279
322
  instances = reservations.map { |r| r.instances }.flatten
280
- private_ips = instances.map { |i| i.private_ip_address }
281
- private_ips
323
+
324
+ instances.map { |i| i.private_ip_address }
282
325
  end
283
326
 
284
327
  def get_latest_task_def
285
328
  ecs_client.describe_task_definition({task_definition: get_latest_task_def_id}).task_definition.to_h
286
329
  end
287
330
 
288
- def get_tasks
289
- # used for pagination if > 100 tasks
290
- next_token = nil
291
- tasks = []
292
- loop do
293
- resp = ecs_client.list_tasks({cluster: config.ecs.cluster, family: family, next_token: next_token})
294
- next_token = resp.next_token
295
- tasks += resp.task_arns
296
- break if next_token.nil?
297
- end
331
+ def get_task_arns
332
+ all_results(:list_tasks, :task_arns, { cluster: config.ecs.cluster, family: family })
333
+ end
298
334
 
299
- tasks
335
+ def get_task_definition_arns
336
+ all_results(:list_task_definitions, :task_definition_arns, { family_prefix: family })
300
337
  end
301
338
 
302
- def get_task_def_ids
303
- # used for pagination if > 100 task_definition ids
304
- next_token = nil
305
- task_def_ids = []
306
- loop do
307
- resp = ecs_client.list_task_definitions({family_prefix: family, next_token: next_token})
308
- next_token = resp.next_token
309
- task_def_ids += resp.task_definition_arns
310
- break if next_token.nil?
311
- end
339
+ def list_task_definition_families
340
+ all_results(:list_task_definition_families, :families)
341
+ end
312
342
 
313
- task_def_ids
343
+ def list_services
344
+ all_results(:list_services, :service_arns, { cluster: config.ecs.cluster })
314
345
  end
315
346
 
316
347
  def get_latest_task_def_id
317
- get_task_def_ids.last
348
+ get_task_definition_arns.last
318
349
  end
319
350
 
320
351
  def create_new_task_revision
@@ -326,6 +357,11 @@ module Broadside
326
357
  task_def
327
358
  end
328
359
 
360
+ def service_exists?
361
+ services = ecs_client.describe_services({ cluster: config.ecs.cluster, services: [family] })
362
+ services.failures.empty? && !services.services.empty?
363
+ end
364
+
329
365
  def ecs_client
330
366
  @ecs_client ||= Aws::ECS::Client.new({
331
367
  region: config.aws.region,
@@ -340,11 +376,16 @@ module Broadside
340
376
  })
341
377
  end
342
378
 
343
- def check_service_existence
344
- resp = ecs_client.describe_services({cluster: config.ecs.cluster, services: [family]})
345
- unless resp.failures.empty?
346
- exception "Could not find ECS service '#{family}' in cluster '#{config.ecs.cluster}' !"
379
+ def all_results(method, key, args = {})
380
+ page = ecs_client.public_send(method, args)
381
+ results = page.send(key)
382
+
383
+ while page.next_token
384
+ page = ecs.send(method, args.merge(next_token: page.next_token))
385
+ results += page.send(key)
347
386
  end
387
+
388
+ results
348
389
  end
349
390
  end
350
391
  end
@@ -1,3 +1,3 @@
1
1
  module Broadside
2
- VERSION = '1.0.3'
2
+ VERSION = '1.1.0.pre'
3
3
  end
metadata CHANGED
@@ -1,15 +1,35 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: broadside
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.3
4
+ version: 1.1.0.pre
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matthew Leung
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-08-25 00:00:00.000000000 Z
11
+ date: 2016-10-01 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '3'
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '5'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: '3'
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '5'
13
33
  - !ruby/object:Gem::Dependency
14
34
  name: aws-sdk
15
35
  requirement: !ruby/object:Gem::Requirement
@@ -25,19 +45,19 @@ dependencies:
25
45
  - !ruby/object:Gem::Version
26
46
  version: '2.3'
27
47
  - !ruby/object:Gem::Dependency
28
- name: rainbow
48
+ name: dotenv
29
49
  requirement: !ruby/object:Gem::Requirement
30
50
  requirements:
31
- - - "~>"
51
+ - - ">="
32
52
  - !ruby/object:Gem::Version
33
- version: '2.1'
53
+ version: 0.9.0
34
54
  type: :runtime
35
55
  prerelease: false
36
56
  version_requirements: !ruby/object:Gem::Requirement
37
57
  requirements:
38
- - - "~>"
58
+ - - ">="
39
59
  - !ruby/object:Gem::Version
40
- version: '2.1'
60
+ version: 0.9.0
41
61
  - !ruby/object:Gem::Dependency
42
62
  name: gli
43
63
  requirement: !ruby/object:Gem::Requirement
@@ -53,19 +73,19 @@ dependencies:
53
73
  - !ruby/object:Gem::Version
54
74
  version: '2.13'
55
75
  - !ruby/object:Gem::Dependency
56
- name: dotenv
76
+ name: rainbow
57
77
  requirement: !ruby/object:Gem::Requirement
58
78
  requirements:
59
- - - ">="
79
+ - - "~>"
60
80
  - !ruby/object:Gem::Version
61
- version: 0.9.0
81
+ version: '2.1'
62
82
  type: :runtime
63
83
  prerelease: false
64
84
  version_requirements: !ruby/object:Gem::Requirement
65
85
  requirements:
66
- - - ">="
86
+ - - "~>"
67
87
  - !ruby/object:Gem::Version
68
- version: 0.9.0
88
+ version: '2.1'
69
89
  - !ruby/object:Gem::Dependency
70
90
  name: rspec
71
91
  requirement: !ruby/object:Gem::Requirement
@@ -131,11 +151,11 @@ files:
131
151
  - lib/broadside/configuration.rb
132
152
  - lib/broadside/configuration/aws.rb
133
153
  - lib/broadside/configuration/base.rb
134
- - lib/broadside/configuration/deploy.rb
135
- - lib/broadside/configuration/ecs.rb
154
+ - lib/broadside/configuration/deploy_config.rb
155
+ - lib/broadside/configuration/ecs_config.rb
136
156
  - lib/broadside/configuration/struct.rb
137
157
  - lib/broadside/deploy.rb
138
- - lib/broadside/deploy/ecs.rb
158
+ - lib/broadside/deploy/ecs_deploy.rb
139
159
  - lib/broadside/error.rb
140
160
  - lib/broadside/utils.rb
141
161
  - lib/broadside/version.rb
@@ -154,9 +174,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
154
174
  version: '0'
155
175
  required_rubygems_version: !ruby/object:Gem::Requirement
156
176
  requirements:
157
- - - ">="
177
+ - - ">"
158
178
  - !ruby/object:Gem::Version
159
- version: '0'
179
+ version: 1.3.1
160
180
  requirements: []
161
181
  rubyforge_project:
162
182
  rubygems_version: 2.2.3