heroku_hatchet 3.1.1 → 4.0.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: 2363b4e6ad949febf29929396202ad62215d4b8442fab1a5701273dc6356e0e8
4
- data.tar.gz: 2834674840abffb9e1bdcf944629c6b00dc987fb17db61685a5b4e15f29bbd71
3
+ metadata.gz: cb7387bbf480ee1443a1985b8bfd3681e6126605786c0ee102be9a691cd37f01
4
+ data.tar.gz: 59876cc8324d6397434dbb03492a6d1231023c343aa6a70a61502cc5d8059fdc
5
5
  SHA512:
6
- metadata.gz: 0ba670133988a7297d8573c69c488bfdb4450cb5420778f372475a1523bd482cf40bd5fb1e4299e6118dd46fb3cb78cabed819099bdd56a0caa71c57ff6e8692
7
- data.tar.gz: 4bf38e97b2afd7524e1ff81cac1fa1b4fb0cb8dbcd4fe62e49039aacdf79706def80b2ee8e8fe4a079355db559471895a42deec37e7304a94d31f4cc2ca985ff
6
+ metadata.gz: 95998e8ab947245d1ebc799fd6bf54b377bffda5e4b63f608aa2663e55e278d71d307754a6d2a623e66e8ff07dcbd04d1b30f4d3ab666b5b1e9856b78f22e645
7
+ data.tar.gz: 7554ca9897c18aa4022526a5e9deba8f05475797f57b5635dc51658797c92390556ea12fcdc66bad6567cbf8a3fb3ab72ae1408d41345bba95fe0d904f2851df
data/CHANGELOG.md CHANGED
@@ -1,5 +1,10 @@
1
1
  ## HEAD
2
2
 
3
+ ## 4.0.0
4
+
5
+ - Introduce API rate limiting (#46)
6
+ - Deprecate App#platform_api method (#46)
7
+
3
8
  ## 3.1.1
4
9
 
5
10
  - Better errors when no lockfile is found #43
data/bin/hatchet CHANGED
@@ -22,9 +22,11 @@ class HatchetCLI < Thor
22
22
  warn_dot_ignore!
23
23
  lock_hash = load_lockfile
24
24
  puts "Installing repos for hatchet"
25
+
26
+ missing_commit = false
25
27
  dirs.map do |directory, git_repo|
26
28
  Threaded.later do
27
- commit = lock_hash.fetch(directory) { raise "expected #{directory} to be locked but it is not, please run `hatchet lock` and commit the results"}
29
+ commit = lock_hash[directory]
28
30
  directory = File.expand_path(directory)
29
31
  if Dir[directory].present?
30
32
  puts "== pulling '#{git_repo}' into '#{directory}'\n"
@@ -33,9 +35,15 @@ class HatchetCLI < Thor
33
35
  puts "== cloning '#{git_repo}' into '#{directory}'\n"
34
36
  clone(directory, git_repo)
35
37
  end
36
- checkout_commit(directory, commit)
38
+ if commit
39
+ checkout_commit(directory, commit)
40
+ else
41
+ missing_commit = true
42
+ end
37
43
  end
38
44
  end.map(&:join)
45
+
46
+ self.lock if missing_commit
39
47
  end
40
48
 
41
49
  def load_lockfile
data/lib/hatchet.rb CHANGED
@@ -17,6 +17,7 @@ require 'hatchet/app'
17
17
  require 'hatchet/anvil_app'
18
18
  require 'hatchet/git_app'
19
19
  require 'hatchet/config'
20
+ require 'hatchet/api_rate_limit'
20
21
 
21
22
  module Hatchet
22
23
  RETRIES = Integer(ENV['HATCHET_RETRIES'] || 1)
@@ -0,0 +1,40 @@
1
+ # Wraps platform-api and adds API rate limits
2
+ #
3
+ # Instead of:
4
+ #
5
+ # platform_api.pipeline.create(name: @name)
6
+ #
7
+ # Use:
8
+ #
9
+ # api_rate_limit = ApiRateLimit.new(platform_api)
10
+ # api_rate_limit.call.pipeline.create(name: @name)
11
+ #
12
+ class ApiRateLimit
13
+ def initialize(platform_api)
14
+ @platform_api = platform_api
15
+ @capacity = 1
16
+ @called = 0
17
+ end
18
+
19
+
20
+ # Sleeps for progressively longer when api rate limit capacity
21
+ # is lower.
22
+ #
23
+ # Unfortunatley `@platform_api.rate_limit` is an extra API
24
+ # call, so by checking our limit, we also are using our limit 😬
25
+ # to partially mitigate this, only check capacity every 5
26
+ # api calls, or if the
27
+ def call
28
+ @called += 1
29
+
30
+ if @called > 5 || @capacity < 1000
31
+ @called = 0
32
+ @capacity = @platform_api.rate_limit.info["remaining"]
33
+ end
34
+
35
+ sleep_time = (60/@capacity) if @capacity > 0.1 # no divide by zero
36
+ sleep(sleep_time || 60)
37
+
38
+ return @platform_api
39
+ end
40
+ end
data/lib/hatchet/app.rb CHANGED
@@ -31,7 +31,7 @@ module Hatchet
31
31
  @labs = ([] << options[:labs]).flatten.compact
32
32
  @buildpacks = options[:buildpack] || options[:buildpacks] || options[:buildpack_url] || self.class.default_buildpack
33
33
  @buildpacks = Array(@buildpacks)
34
- @reaper = Reaper.new(platform_api: platform_api)
34
+ @reaper = Reaper.new(api_rate_limit: api_rate_limit)
35
35
  end
36
36
 
37
37
  def self.default_buildpack
@@ -54,13 +54,13 @@ module Hatchet
54
54
  def set_config(options = {})
55
55
  options.each do |key, value|
56
56
  # heroku.put_config_vars(name, key => value)
57
- platform_api.config_var.update(name, key => value)
57
+ api_rate_limit.call.config_var.update(name, key => value)
58
58
  end
59
59
  end
60
60
 
61
61
  def get_config
62
62
  # heroku.get_config_vars(name).body
63
- platform_api.config_var.info_for_app(name)
63
+ api_rate_limit.call.config_var.info_for_app(name)
64
64
  end
65
65
 
66
66
  def lab_is_installed?(lab)
@@ -69,7 +69,7 @@ module Hatchet
69
69
 
70
70
  def get_labs
71
71
  # heroku.get_features(name).body
72
- platform_api.app_feature.list(name)
72
+ api_rate_limit.call.app_feature.list(name)
73
73
  end
74
74
 
75
75
  def set_labs!
@@ -78,13 +78,13 @@ module Hatchet
78
78
 
79
79
  def set_lab(lab)
80
80
  # heroku.post_feature(lab, name)
81
- platform_api.app_feature.update(name, lab, enabled: true)
81
+ api_rate_limit.call.app_feature.update(name, lab, enabled: true)
82
82
  end
83
83
 
84
84
  def add_database(plan_name = 'heroku-postgresql:dev', match_val = "HEROKU_POSTGRESQL_[A-Z]+_URL")
85
85
  Hatchet::RETRIES.times.retry do
86
86
  # heroku.post_addon(name, plan_name)
87
- platform_api.addon.create(name, plan: plan_name )
87
+ api_rate_limit.call.addon.create(name, plan: plan_name )
88
88
  _, value = get_config.detect {|k, v| k.match(/#{match_val}/) }
89
89
  set_config('DATABASE_URL' => value)
90
90
  end
@@ -120,7 +120,7 @@ module Hatchet
120
120
 
121
121
  def deployed?
122
122
  # !heroku.get_ps(name).body.detect {|ps| ps["process"].include?("web") }.nil?
123
- platform_api.formation.list(name).detect {|ps| ps["type"] == "web"}
123
+ api_rate_limit.call.formation.list(name).detect {|ps| ps["type"] == "web"}
124
124
  end
125
125
 
126
126
  def create_app
@@ -129,7 +129,7 @@ module Hatchet
129
129
  # heroku.post_app({ name: name, stack: stack }.delete_if {|k,v| v.nil? })
130
130
  hash = { name: name, stack: stack }
131
131
  hash.delete_if { |k,v| v.nil? }
132
- platform_api.app.create(hash)
132
+ api_rate_limit.call.app.create(hash)
133
133
  rescue
134
134
  @reaper.cycle
135
135
  raise e
@@ -139,7 +139,7 @@ module Hatchet
139
139
 
140
140
  def update_stack(stack_name)
141
141
  @stack = stack_name
142
- platform_api.app.update(name, build_stack: @stack)
142
+ api_rate_limit.call.app.update(name, build_stack: @stack)
143
143
  end
144
144
 
145
145
  # creates a new heroku app via the API
@@ -150,7 +150,7 @@ module Hatchet
150
150
  set_labs!
151
151
  # heroku.put_config_vars(name, 'BUILDPACK_URL' => @buildpack)
152
152
  buildpack_list = @buildpacks.map {|pack| { buildpack: pack }}
153
- platform_api.buildpack_installation.update(name, updates: buildpack_list)
153
+ api_rate_limit.call.buildpack_installation.update(name, updates: buildpack_list)
154
154
  @app_is_setup = true
155
155
  self
156
156
  end
@@ -186,7 +186,7 @@ module Hatchet
186
186
  in_directory do
187
187
  self.setup!
188
188
  self.push_with_retry!
189
- block.call(self, platform_api, output) if block_given?
189
+ block.call(self, api_rate_limit.call, output) if block_given?
190
190
  end
191
191
  ensure
192
192
  self.teardown!
@@ -255,7 +255,7 @@ module Hatchet
255
255
  end
256
256
 
257
257
  def create_pipeline
258
- platform_api.pipeline.create(name: @name)
258
+ api_rate_limit.call.pipeline.create(name: @name)
259
259
  end
260
260
 
261
261
  def source_get_url
@@ -265,7 +265,7 @@ module Hatchet
265
265
 
266
266
  def create_source
267
267
  @create_source ||= begin
268
- result = platform_api.source.create
268
+ result = api_rate_limit.call.source.create
269
269
  @source_get_url = result["source_blob"]["get_url"]
270
270
  @source_put_url = result["source_blob"]["put_url"]
271
271
  @source_put_url
@@ -273,12 +273,18 @@ module Hatchet
273
273
  end
274
274
 
275
275
  def delete_pipeline(pipeline_id)
276
- platform_api.pipeline.delete(pipeline_id)
276
+ api_rate_limit.call.pipeline.delete(pipeline_id)
277
277
  end
278
278
 
279
279
  def platform_api
280
- # We have to not use a cache due to https://github.com/heroku/platform-api/issues/73
281
- @platform_api ||= PlatformAPI.connect_oauth(api_key, cache: Moneta.new(:Null))
280
+ puts "Deprecated: use `api_rate_limit.call` instead of platform_api"
281
+ api_rate_limit
282
+ return @platform_api
283
+ end
284
+
285
+ def api_rate_limit
286
+ @platform_api ||= PlatformAPI.connect_oauth(api_key, cache: Moneta.new(:Null))
287
+ @api_rate_limit ||= ApiRateLimit.new(@platform_api)
282
288
  end
283
289
 
284
290
  private
@@ -11,14 +11,14 @@ module Hatchet
11
11
  attr_accessor :apps
12
12
 
13
13
 
14
- def initialize(platform_api:, regex: DEFAULT_REGEX)
15
- @platform_api = platform_api
14
+ def initialize(api_rate_limit: , regex: DEFAULT_REGEX)
15
+ @api_rate_limit = api_rate_limit
16
16
  @regex = regex
17
17
  end
18
18
 
19
19
  # Ascending order, oldest is last
20
20
  def get_apps
21
- apps = @platform_api.app.list.sort_by { |app| DateTime.parse(app["created_at"]) }.reverse
21
+ apps = @api_rate_limit.call.app.list.sort_by { |app| DateTime.parse(app["created_at"]) }.reverse
22
22
  @app_count = apps.count
23
23
  @hatchet_apps = apps.select {|app| app["name"].match(@regex) }
24
24
  end
@@ -63,7 +63,7 @@ module Hatchet
63
63
  def destroy_by_id(name:, id:, details: "")
64
64
  @message = "Destroying #{name.inspect}: #{id}. #{details}"
65
65
  puts @message
66
- @platform_api.app.delete(id)
66
+ @api_rate_limit.call.app.delete(id)
67
67
  end
68
68
 
69
69
  private
@@ -1,3 +1,3 @@
1
1
  module Hatchet
2
- VERSION = "3.1.1"
2
+ VERSION = "4.0.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: heroku_hatchet
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.1.1
4
+ version: 4.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Richard Schneeman
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-04-03 00:00:00.000000000 Z
11
+ date: 2018-06-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: platform-api
@@ -199,6 +199,7 @@ files:
199
199
  - hatchet.lock
200
200
  - lib/hatchet.rb
201
201
  - lib/hatchet/anvil_app.rb
202
+ - lib/hatchet/api_rate_limit.rb
202
203
  - lib/hatchet/app.rb
203
204
  - lib/hatchet/config.rb
204
205
  - lib/hatchet/git_app.rb