shipit-engine 0.22.0 → 0.23.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +22 -2
  3. data/app/assets/javascripts/merge_status.coffee +83 -0
  4. data/app/assets/stylesheets/merge_status.scss +3 -0
  5. data/app/controllers/shipit/merge_status_controller.rb +131 -0
  6. data/app/helpers/shipit/merge_status_helper.rb +7 -0
  7. data/app/jobs/shipit/perform_task_job.rb +1 -3
  8. data/app/models/shipit/deploy.rb +4 -0
  9. data/app/models/shipit/deploy_spec.rb +5 -0
  10. data/app/models/shipit/deploy_spec/file_system.rb +1 -0
  11. data/app/models/shipit/hook.rb +1 -1
  12. data/app/models/shipit/pull_request.rb +1 -1
  13. data/app/models/shipit/stack.rb +4 -0
  14. data/app/models/shipit/task.rb +4 -0
  15. data/app/models/shipit/task_definition.rb +10 -0
  16. data/app/models/shipit/user.rb +1 -5
  17. data/app/serializers/shipit/task_serializer.rb +1 -0
  18. data/app/views/layouts/merge_status.html.erb +11 -0
  19. data/app/views/shipit/merge_status/_anchor.html.erb +6 -0
  20. data/app/views/shipit/merge_status/_commit_count_warning.html.erb +8 -0
  21. data/app/views/shipit/merge_status/_merge_queue_button.html.erb +16 -0
  22. data/app/views/shipit/merge_status/_warning_icon.html.erb +4 -0
  23. data/app/views/shipit/merge_status/backlogged.html.erb +21 -0
  24. data/app/views/shipit/merge_status/failure.html.erb +21 -0
  25. data/app/views/shipit/merge_status/locked.html.erb +21 -0
  26. data/app/views/shipit/merge_status/logged_out.erb +11 -0
  27. data/app/views/shipit/merge_status/success.html.erb +24 -0
  28. data/app/views/shipit/tasks/_task.html.erb +1 -1
  29. data/app/views/shipit/tasks/_task_output.html.erb +1 -1
  30. data/config/routes.rb +5 -0
  31. data/lib/shipit.rb +5 -3
  32. data/lib/shipit/engine.rb +2 -0
  33. data/lib/shipit/github_app.rb +8 -11
  34. data/lib/shipit/stack_commands.rb +0 -9
  35. data/lib/shipit/version.rb +1 -1
  36. data/lib/snippets/misconfigured-npm-publish-config +4 -4
  37. data/test/controllers/merge_status_controller_test.rb +37 -0
  38. data/test/dummy/db/test.sqlite3 +0 -0
  39. data/test/fixtures/shipit/tasks.yml +27 -0
  40. data/test/jobs/perform_task_job_test.rb +0 -1
  41. data/test/models/deploy_spec_test.rb +24 -0
  42. data/test/models/task_definitions_test.rb +2 -0
  43. data/test/models/tasks_test.rb +16 -0
  44. metadata +24 -7
  45. data/lib/shipit/octokit_bot_users_patch.rb +0 -25
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '09b8ffb2b4130e05d8da6bfbdc22080becca47dd92ee5a06b4113d3729578226'
4
- data.tar.gz: 2223bee54a1d2a084823763876a049668829af0725779b413f0ed6d665ed45d6
3
+ metadata.gz: fc62ac846a6e7816e9de50d219459166c6941f0b230174309ad76bd695ab338e
4
+ data.tar.gz: 9879387bc8a1a0a89e334bea062ae56bfd060881da2f4e2779bbfddcae3b1f0d
5
5
  SHA512:
6
- metadata.gz: 2a2bef860f0dc71622f450e4c52949680c7edca82c48462a48db34beb034b4b022e020228d160f5b86b7792d5938e0fdc09e6fb08e018c8a8e7f147bf22b60e7
7
- data.tar.gz: 7cf318e67131f2a0a4bfbd316a8b732a5c8cd57fa49428d1f38a25e978a2e1535d0c5c8ca5e67bb83b4ad3c8f7dd07390e43832ef06ba697a9a2c5671e2df2d6
6
+ metadata.gz: ee9308a0a602a3aed84a3d7e8a2b9d0d0acf9a8eabebc57a245139c78a0404782bd58f6bbd3bd16661fdef199861833d74ae841cbdb3a439f6567351b7f80ed7
7
+ data.tar.gz: 4ecf8b958d7080b98babff0249bd8db5cdabcfe7c5b920c822a6db52148db5c953e3f7260ec60bf1eeba604d8403f4f8260806a15a3698eb29bf315ca0b84717
data/README.md CHANGED
@@ -31,7 +31,6 @@ This guide aims to help you [set up](#installation-and-setup), [use](#using-ship
31
31
  **III. REFERENCE**
32
32
 
33
33
  * [Format and content of shipit.yml](#configuring-shipit)
34
- * [Format and content of secrets.yml](#configuring-secrets)
35
34
  * [Script parameters](#script-parameters)
36
35
  * [Configuring providers](#configuring-providers)
37
36
  * [Free samples](/examples/shipit.yml)
@@ -406,7 +405,7 @@ ci:
406
405
 
407
406
  <h3 id="merge-queue">Merge Queue</h3>
408
407
 
409
- The merge queue allow to register pull requests for them to be merged by Shipit once the stack is clear (no lock, no failing CI, no backlog). It can be enabled on a per stack basis via the settings page.
408
+ The merge queue allows developers to register pull requests which will be merged by Shipit once the stack is clear (no lock, no failing CI, no backlog). It can be enabled on a per stack basis via the settings page.
410
409
 
411
410
  It can be customized via several `shipit.yml` properties:
412
411
 
@@ -436,6 +435,14 @@ merge:
436
435
  - codeclimate
437
436
  ```
438
437
 
438
+ **<code>merge.method</code>** the [merge method](https://developer.github.com/v3/pulls/#merge-a-pull-request-merge-button) to use for this stack. If it's not set the default merge method will be used. Can be either `merge`, `squash` or `rebase`.
439
+
440
+ For example:
441
+ ```yml
442
+ merge:
443
+ method: squash
444
+ ```
445
+
439
446
  **<code>merge.max_divergence.commits</code>** the maximum number of commits a pull request can be behind its merge base, after which pull requests are rejected from the merge queue.
440
447
 
441
448
  For example:
@@ -496,6 +503,19 @@ tasks:
496
503
  default: 0
497
504
  ```
498
505
 
506
+ You can also make these variables appear in the task title:
507
+
508
+ ```yml
509
+ tasks:
510
+ failover:
511
+ action: "Failover a pod"
512
+ title: "Failover Pod %{POD_ID}"
513
+ steps:
514
+ - script/failover $POD_ID
515
+ variables:
516
+ - name: POD_ID
517
+ ```
518
+
499
519
  <h3 id="review-process">Review process</h3>
500
520
 
501
521
  You can display review elements, such as monitoring data or a pre-deployment checklist, on the deployment page in Shipit:
@@ -0,0 +1,83 @@
1
+ class MergeStatusPoller
2
+ POLL_INTERVAL = 3000
3
+
4
+ constructor: ->
5
+ @request = {abort: ->}
6
+ @previousLastModified = null
7
+ @timeoutId = null
8
+
9
+ start: ->
10
+ @timeoutId = setTimeout(@refreshPage, POLL_INTERVAL)
11
+ @
12
+
13
+ stop: ->
14
+ @request.abort()
15
+ clearTimeout(@timeoutId)
16
+ @
17
+
18
+ onPageChange: =>
19
+ window.parent.postMessage({event: 'hctw:height:change', height: document.body.clientHeight, service: 'shipit'}, '*')
20
+ window.parent.postMessage({event: 'hctw:stack:info', queue_enabled: @isMergeQueueEnabled(), status: @mergeStatus(), service: 'shipit'}, '*')
21
+
22
+ fetchPage: (url, callback) ->
23
+ request = @request = new XMLHttpRequest()
24
+ request.onreadystatechange = ->
25
+ if request.readyState == XMLHttpRequest.DONE
26
+ callback(request.status == 200 && request.responseText, request)
27
+ request.open('GET', url, true)
28
+ request.setRequestHeader('X-Requested-With', 'XMLHttpRequest')
29
+ request.send()
30
+
31
+ previousLastModified = null
32
+ refreshPage: =>
33
+ @fetchPage window.location.toString(), (html, response) =>
34
+ @updateDocument(html, response)
35
+ setTimeout(@refreshPage, POLL_INTERVAL)
36
+
37
+ updateDocument: (html, response) =>
38
+ lastModified = response.getResponseHeader('last-modified')
39
+ if !lastModified || lastModified != @previousLastModified
40
+ @previousLastModified = lastModified
41
+ if html && container = document.querySelector('[data-layout-content]')
42
+ container.innerHTML = html
43
+ @onPageChange()
44
+
45
+ isMergeQueueEnabled: =>
46
+ document.querySelector('.merge-status-container .js-details-container').hasAttribute('data-queue-enabled')
47
+
48
+ mergeStatus: =>
49
+ document.querySelector('.merge-status-container .js-details-container').getAttribute('data-merge-status') || 'unknown'
50
+
51
+ class AjaxAction
52
+ constructor: (@poller) ->
53
+ document.addEventListener('submit', @submit, false)
54
+
55
+ submit: (event) =>
56
+ return unless event.target.getAttribute('data-remote') == 'true'
57
+
58
+ event.preventDefault()
59
+
60
+ @poller.stop()
61
+ @disableButtons(event.target)
62
+ @submitFormAsynchronously event.target, (html, request) =>
63
+ @poller.updateDocument(html, request)
64
+ @poller.start()
65
+
66
+ submitFormAsynchronously: (form, callback) ->
67
+ request = new XMLHttpRequest()
68
+ request.onreadystatechange = ->
69
+ if request.readyState == XMLHttpRequest.DONE
70
+ callback(request.status == 200 && request.responseText, request)
71
+ request.open(form.method.toLocaleUpperCase(), form.action, true)
72
+ request.setRequestHeader('X-Requested-With', 'XMLHttpRequest')
73
+ request.send(new FormData(form))
74
+
75
+ disableButtons: (form) ->
76
+ for button in form.querySelectorAll('[data-disable-with]')
77
+ button.disabled = true
78
+ button.textContent = button.getAttribute('data-disable-with')
79
+
80
+ poller = new MergeStatusPoller
81
+ poller.onPageChange()
82
+ poller.start()
83
+ new AjaxAction(poller)
@@ -0,0 +1,3 @@
1
+ .merge-status-container {
2
+ max-width: 700px;
3
+ }
@@ -0,0 +1,131 @@
1
+ module Shipit
2
+ class MergeStatusController < ShipitController
3
+ skip_authentication only: %i(check show)
4
+
5
+ etag { cache_seed }
6
+ layout 'merge_status'
7
+
8
+ def show
9
+ response.headers['X-Frame-Options'] = 'ALLOWALL'
10
+ response.headers['Vary'] = 'X-Requested-With'
11
+
12
+ if stack
13
+ return render('logged_out') unless current_user.logged_in?
14
+ if stale?(last_modified: [stack.updated_at, pull_request.updated_at].max, template: false)
15
+ render stack_status, layout: !request.xhr?
16
+ end
17
+ else
18
+ render html: ''
19
+ end
20
+ end
21
+
22
+ def enqueue
23
+ PullRequest.request_merge!(stack, params[:number], current_user)
24
+ render stack_status, layout: !request.xhr?
25
+ end
26
+
27
+ def dequeue
28
+ if pull_request = stack.pull_requests.find_by_number(params[:number])
29
+ pull_request.cancel! if pull_request.waiting?
30
+ end
31
+ render stack_status, layout: !request.xhr?
32
+ end
33
+
34
+ def check
35
+ respond_to do |format|
36
+ format.html do
37
+ if stack_status == 'success'
38
+ render plain: 'ok'
39
+ else
40
+ render plain: stack_status, status: 503
41
+ end
42
+ end
43
+ format.json { render json: {stack_status: stack_status} }
44
+ end
45
+ end
46
+
47
+ private
48
+
49
+ def cache_seed
50
+ "#{request.xhr? ? 'partial' : 'full'}-#{Shipit.revision}"
51
+ end
52
+
53
+ def stack_status
54
+ @stack_status ||= stack.merge_status(backlog_leniency_factor: 1.0)
55
+ end
56
+
57
+ def stack
58
+ @stack ||= if params[:stack_id]
59
+ Stack.from_param!(params[:stack_id])
60
+ else
61
+ scope = Stack.order(id: :asc).where(
62
+ repo_owner: referrer_parser.repo_owner,
63
+ repo_name: referrer_parser.repo_name,
64
+ )
65
+ scope = if params[:branch]
66
+ scope.where(branch: params[:branch])
67
+ else
68
+ scope.where(environment: 'production')
69
+ end
70
+ scope.first
71
+ end
72
+ end
73
+
74
+ def referrer_parser
75
+ @referrer_parser ||= ReferrerParser.new(params[:referrer])
76
+ end
77
+
78
+ def pull_request
79
+ return @pull_request if defined?(@pull_request)
80
+ @pull_request = pull_request_number && stack.pull_requests.find_by_number(pull_request_number)
81
+ @pull_request ||= UnknownPullRequest.new
82
+ end
83
+
84
+ def pull_request_number
85
+ return @pull_request_number if defined?(@pull_request_number)
86
+ @pull_request_number = referrer_parser.pull_request_number
87
+ end
88
+
89
+ def queue_enabled?
90
+ stack.merge_queue_enabled? && pull_request_number
91
+ end
92
+
93
+ helper_method :pull_request_number
94
+ helper_method :pull_request
95
+ helper_method :queue_enabled?
96
+ helper_method :stack
97
+ helper_method :stack_status
98
+
99
+ # FIXME: for some reason if invoked in the view, those path helpers will link to /events?...
100
+ helper_method :enqueue_pull_request_path
101
+ helper_method :dequeue_pull_request_path
102
+
103
+ class ReferrerParser
104
+ URL_PATTERN = %r{\Ahttps://github\.com/([^/]+)/([^/]+)/pull/(\d+)}
105
+
106
+ attr_reader :repo_owner, :repo_name, :pull_request_number
107
+
108
+ def initialize(referrer)
109
+ if URL_PATTERN =~ referrer.to_s
110
+ @repo_owner = $1.downcase
111
+ @repo_name = $2.downcase
112
+ @pull_request_number = $3.to_i
113
+ else
114
+ raise ArgumentError, "Invalid referrer: #{referrer.inspect}"
115
+ end
116
+ end
117
+ end
118
+
119
+ class UnknownPullRequest
120
+ attr_reader :updated_at
121
+
122
+ def initialize
123
+ @updated_at = Time.at(0).utc
124
+ end
125
+
126
+ def waiting?
127
+ false
128
+ end
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,7 @@
1
+ module Shipit
2
+ module MergeStatusHelper
3
+ def too_many_commits?(commits)
4
+ commits > 4
5
+ end
6
+ end
7
+ end
@@ -63,9 +63,7 @@ module Shipit
63
63
 
64
64
  def checkout_repository
65
65
  @task.acquire_git_cache_lock do
66
- unless capture @commands.fetched?(@task.until_commit)
67
- capture! @commands.fetch
68
- end
66
+ capture! @commands.fetch
69
67
  end
70
68
  capture! @commands.clone
71
69
  capture! @commands.checkout(@task.until_commit)
@@ -79,6 +79,10 @@ module Shipit
79
79
  rollback
80
80
  end
81
81
 
82
+ def title
83
+ I18n.t("#{self.class.name.demodulize.underscore.pluralize}.description", sha: until_commit.short_sha)
84
+ end
85
+
82
86
  def rollback?
83
87
  false
84
88
  end
@@ -146,6 +146,11 @@ module Shipit
146
146
  Array.wrap(config('ci', 'blocking'))
147
147
  end
148
148
 
149
+ def pull_request_merge_method
150
+ method = config('merge', 'method')
151
+ method if %w(merge rebase squash).include?(method)
152
+ end
153
+
149
154
  def pull_request_required_statuses
150
155
  if config('merge', 'require') || config('merge', 'ignore')
151
156
  Array.wrap(config('merge', 'require'))
@@ -34,6 +34,7 @@ module Shipit
34
34
  'require' => pull_request_required_statuses,
35
35
  'ignore' => pull_request_ignored_statuses,
36
36
  'revalidate_after' => revalidate_pull_requests_after&.to_i,
37
+ 'method' => pull_request_merge_method,
37
38
  'max_divergence' => {
38
39
  'commits' => max_divergence_commits&.to_i,
39
40
  'age' => max_divergence_age&.to_i,
@@ -80,7 +80,7 @@ module Shipit
80
80
  end
81
81
 
82
82
  def purge_old_deliveries!(keep: DELIVERIES_LOG_SIZE)
83
- delivery_ids = deliveries.sent.order(id: :desc).offset(keep).pluck(:id)
83
+ delivery_ids = deliveries.sent.order(id: :desc).offset(keep).limit(50).pluck(:id)
84
84
  deliveries.where(id: delivery_ids).delete_all
85
85
  end
86
86
 
@@ -163,7 +163,7 @@ module Shipit
163
163
  merge_message,
164
164
  sha: head.sha,
165
165
  commit_message: 'Merged by Shipit',
166
- merge_method: 'merge',
166
+ merge_method: stack.merge_method,
167
167
  )
168
168
  begin
169
169
  if Shipit.github.api.pull_requests(stack.github_repo_name, base: branch).empty?
@@ -275,6 +275,10 @@ module Shipit
275
275
  merge_queue_enabled? && !locked? && merge_status == 'success'
276
276
  end
277
277
 
278
+ def merge_method
279
+ cached_deploy_spec&.pull_request_merge_method || Shipit.default_merge_method
280
+ end
281
+
278
282
  def repo_name=(name)
279
283
  super(name&.downcase)
280
284
  end
@@ -212,6 +212,10 @@ module Shipit
212
212
  false
213
213
  end
214
214
 
215
+ def title
216
+ definition.render_title(env)
217
+ end
218
+
215
219
  def author
216
220
  user || AnonymousUser.new
217
221
  end
@@ -26,6 +26,15 @@ module Shipit
26
26
  @variables = task_variables(config['variables'] || [])
27
27
  @checklist = config['checklist'] || []
28
28
  @allow_concurrency = config['allow_concurrency'] || false
29
+ @title = config['title']
30
+ end
31
+
32
+ def render_title(env)
33
+ if @title
34
+ @title % env.symbolize_keys
35
+ else
36
+ action
37
+ end
29
38
  end
30
39
 
31
40
  def allow_concurrency?
@@ -36,6 +45,7 @@ module Shipit
36
45
  {
37
46
  id: id,
38
47
  action: action,
48
+ title: @title,
39
49
  description: description,
40
50
  steps: steps,
41
51
  variables: variables.map(&:to_h),
@@ -46,11 +46,7 @@ module Shipit
46
46
  def github_api
47
47
  return Shipit.github.api unless github_access_token
48
48
 
49
- @github_api ||= begin
50
- client = Octokit::Client.new(access_token: github_access_token)
51
- client.middleware = Shipit.new_faraday_stack
52
- client
53
- end
49
+ @github_api ||= Shipit.github.new_client(access_token: github_access_token)
54
50
  end
55
51
 
56
52
  def identifiers_for_ping
@@ -13,6 +13,7 @@ module Shipit
13
13
  type
14
14
  status
15
15
  action
16
+ title
16
17
  description
17
18
  started_at
18
19
  ended_at
@@ -0,0 +1,11 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <%= stylesheet_link_tag *(params[:stylesheets] || []).select { |url| url.start_with?('https://assets-cdn.github.com/') } %>
5
+ <%= stylesheet_link_tag 'merge_status' %>
6
+ </head>
7
+ <body>
8
+ <div class="merge-status-container" data-layout-content><%= yield %></div>
9
+ <%= javascript_include_tag 'merge_status' %>
10
+ </body>
11
+ </html>
@@ -0,0 +1,6 @@
1
+ <svg style="fill: <%= color %>; stroke: <%= color %>;" viewBox="-584 580 33 40" enable-background="new -583 582.2 31.3 36.8">
2
+ <path d="M-553.7,605.9l-5.4-1.2l-0.9,3.8l3.2,0.7c-2.2,3.7-6.2,6-10.6,5.9l3.5-19.2c3.5-0.4,6.2-3.3,6.2-6.9
3
+ c0-3.8-3.1-6.9-6.9-6.9c-3.8,0-6.9,3.1-6.9,6.9c0,2.7,1.6,5,3.8,6.2l-3.5,19.2c-4.3-1.5-7.3-5.4-7.8-9.8l3.8,0.8l0.8-3.8l-5.1-1
4
+ l-3.1-0.6c-1.8,8.6,3.7,17,12.3,18.7c1.1,0.2,2.2,0.3,3.3,0.3c3.1,0,6-0.9,8.7-2.6c3.5-2.3,6-5.9,6.8-10L-553.7,605.9z M-564.6,586
5
+ c1.7,0,3,1.4,3,3c0,1.7-1.4,3-3,3c-1.7,0-3-1.4-3-3C-567.7,587.4-566.3,586-564.6,586z"/>
6
+ </svg>
@@ -0,0 +1,8 @@
1
+ <p class="status-heading text-red">
2
+ <%= render 'warning_icon' %>
3
+ Consider rebasing into a smaller number of commits containing atomic changes. Find out
4
+ <%= link_to 'why', 'https://docs.google.com/document/d/1lZlNo7ekugQDxug6Nc6pdY87VNobl3g2IQjY7R0YIIc',
5
+ target: '_blank',
6
+ rel: 'noopener'
7
+ %>.
8
+ </p>
@@ -0,0 +1,16 @@
1
+ <% classes = 'branch-action-btn float-right js-immediate-updates js-handle-pull-merging-errors' %>
2
+ <% if pull_request.try!(&:waiting?) %>
3
+ <%= form_tag dequeue_pull_request_path(stack, pull_request_number), method: 'delete', class: classes, data: {remote: true} do %>
4
+ <%= hidden_field_tag 'referrer', params[:referrer] %>
5
+ <button type="submit" data-disable-with="Removing from merge queue…" class="btn">
6
+ Remove from merge queue
7
+ </button>
8
+ <% end %>
9
+ <% else %>
10
+ <%= form_tag enqueue_pull_request_path(stack, pull_request_number), method: 'put', class: classes, data: {remote: true} do %>
11
+ <%= hidden_field_tag 'referrer', params[:referrer] %>
12
+ <button type="submit" data-disable-with="Adding to merge queue…" class="btn btn-primary">
13
+ Add to merge queue
14
+ </button>
15
+ <% end %>
16
+ <% end %>
@@ -0,0 +1,4 @@
1
+ <svg aria-hidden="true" class="octicon octicon-issue-opened" height="16" version="1.1" viewBox="0 0 14 16" width="14">
2
+ <path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7
3
+ 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z" />
4
+ </svg>
@@ -0,0 +1,21 @@
1
+ <div class="branch-action-item js-details-container" <% if queue_enabled? %>data-queue-enabled<% end %> data-merge-status="<%= stack_status %>">
2
+ <%= render 'merge_queue_button' if queue_enabled? %>
3
+ <div class="branch-action-item-icon completeness-indicator">
4
+ <%= render 'anchor', color: '#cea61b' %>
5
+ </div>
6
+ <h4 class="status-heading text-pending">
7
+ <% if pull_request.waiting? %>
8
+ Will be merged shortly after the backlog is shipped!
9
+ <% else %>
10
+ Please hold off merging!
11
+ <% if queue_enabled? %>
12
+ Add it to the merge queue instead.
13
+ <% end %>
14
+ <% end %>
15
+ </h4>
16
+ <span class="status-meta">
17
+ <%= link_to @stack.to_param, stack_url(@stack), target: '_blank', rel: 'noopener' %>
18
+ is <strong>backlogged</strong>
19
+ </span>
20
+ <%= render 'commit_count_warning' if too_many_commits?(params[:commits].to_i) %>
21
+ </div>
@@ -0,0 +1,21 @@
1
+ <div class="branch-action-item js-details-container" <% if queue_enabled? %>data-queue-enabled<% end %> data-merge-status="<%= stack_status %>">
2
+ <%= render 'merge_queue_button' if queue_enabled? %>
3
+ <div class="branch-action-item-icon completeness-indicator">
4
+ <%= render 'anchor', color: '#d73a49' %>
5
+ </div>
6
+ <h4 class="status-heading text-red">
7
+ <% if pull_request.waiting? %>
8
+ Will be merged shortly after the CI is fixed!
9
+ <% else %>
10
+ Please hold off merging!
11
+ <% if queue_enabled? %>
12
+ Add it to the merge queue instead.
13
+ <% end %>
14
+ <% end %>
15
+ </h4>
16
+ <span class="status-meta">
17
+ <%= link_to @stack.to_param, stack_url(@stack), target: '_blank', rel: 'noopener' %>
18
+ <strong>master branch is failing!</strong>
19
+ </span>
20
+ <%= render 'commit_count_warning' if too_many_commits?(params[:commits].to_i) %>
21
+ </div>
@@ -0,0 +1,21 @@
1
+ <div class="branch-action-item js-details-container" <% if queue_enabled? %>data-queue-enabled<% end %> data-merge-status="<%= stack_status %>">
2
+ <%= render 'merge_queue_button' if queue_enabled? %>
3
+ <div class="branch-action-item-icon completeness-indicator">
4
+ <%= render 'anchor', color: '#bd2c00' %>
5
+ </div>
6
+ <h4 class="status-heading text-red">
7
+ <% if pull_request.waiting? %>
8
+ Will be merged shortly after the lock is removed!
9
+ <% else %>
10
+ Please hold off merging!
11
+ <% if queue_enabled? %>
12
+ Add it to the merge queue instead.
13
+ <% end %>
14
+ <% end %>
15
+ </h4>
16
+ <span class="status-meta">
17
+ <%= link_to @stack.to_param, stack_url(@stack), target: '_blank', rel: 'noopener' %>
18
+ is <strong>locked</strong> because: <strong><%= auto_link(emojify(@stack.lock_reason), html: { target: '_blank' }) %></strong>
19
+ </span>
20
+ <%= render 'commit_count_warning' if too_many_commits?(params[:commits].to_i) %>
21
+ </div>
@@ -0,0 +1,11 @@
1
+ <div class="branch-action-item">
2
+ <div class="branch-action-item-icon completeness-indicator">
3
+ <%= render 'anchor', color: '#bd2c00' %>
4
+ </div>
5
+ <h4 class="status-heading text-red">
6
+ Please log in to <%= link_to 'Shipit', '/', target: '_blank', rel: 'noopener' %>
7
+ </h4>
8
+ <span class="status-meta">
9
+ Here Comes The Walrus is unable to check merge status.
10
+ </span>
11
+ </div>
@@ -0,0 +1,24 @@
1
+ <div class="branch-action-item js-details-container" <% if queue_enabled? %>data-queue-enabled<% end %> data-merge-status="<%= stack_status %>">
2
+ <%= render 'merge_queue_button' if queue_enabled? %>
3
+ <div class="branch-action-item-icon completeness-indicator">
4
+ <%= render 'anchor', color: '#2cbe4e' %>
5
+ </div>
6
+
7
+ <h4 class="status-heading">
8
+ <% if pull_request.waiting? %>
9
+ <% if pull_request.all_status_checks_passed? %>
10
+ Will be merged shortly!
11
+ <% else %>
12
+ Will be merged when required checks are passing.
13
+ <% end %>
14
+ <% else %>
15
+ Ready to ship!
16
+ <% end %>
17
+ </h4>
18
+
19
+ <span class="status-meta">
20
+ <%= link_to @stack.to_param, stack_url(@stack), target: '_blank', rel: 'noopener' %> is clear.
21
+ </span>
22
+
23
+ <%= render 'commit_count_warning' if too_many_commits?(params[:commits].to_i) %>
24
+ </div>
@@ -13,7 +13,7 @@
13
13
  <div class="commit-details">
14
14
  <span class="commit-title">
15
15
  <a href="<%= stack_task_path(@stack, task) %>">
16
- <%= task.definition.action %>
16
+ <%= task.title %>
17
17
  </a>
18
18
  </span>
19
19
  <p class="commit-meta">
@@ -8,7 +8,7 @@
8
8
  <div class="sidebar-plugins"></div>
9
9
  </div>
10
10
 
11
- <div class="deploy-main" data-task="<%= {repo: @stack.github_repo_name, description: task_description(task)}.to_json %>">
11
+ <div class="deploy-main" data-task="<%= {repo: @stack.github_repo_name, description: task.title}.to_json %>">
12
12
  <span class="deploy-tasks"></span>
13
13
  <div class="deploy-banner" data-status="<%= task.status %>">
14
14
  <div class="deploy-banner-status"></div>
data/config/routes.rb CHANGED
@@ -38,6 +38,11 @@ Shipit::Engine.routes.draw do
38
38
  get '/' => 'ccmenu_url#fetch'
39
39
  end
40
40
 
41
+ # Browser extension
42
+ get '/merge_status', action: :show, controller: :merge_status, as: :merge_status
43
+ put '/merge_status/*stack_id/pull/:number', action: :enqueue, controller: :merge_status, id: stack_id_format, as: :enqueue_pull_request
44
+ delete '/merge_status/*stack_id/pull/:number', action: :dequeue, controller: :merge_status, id: stack_id_format, as: :dequeue_pull_request
45
+
41
46
  # Humans
42
47
  resources :stacks, only: %i(new create index)
43
48
 
data/lib/shipit.rb CHANGED
@@ -26,8 +26,6 @@ require 'redis-objects'
26
26
  require 'redis-namespace'
27
27
 
28
28
  require 'octokit'
29
- require 'shipit/octokit_bot_users_patch'
30
-
31
29
  require 'faraday-http-cache'
32
30
 
33
31
  require 'shipit/version'
@@ -81,7 +79,7 @@ module Shipit
81
79
 
82
80
  def legacy_github_api
83
81
  if secrets&.github_api.present?
84
- @legacy_github_api ||= Octokit::Client.new(access_token: secrets.github_api['access_token'])
82
+ @legacy_github_api ||= github.new_client(access_token: secrets.github_api['access_token'])
85
83
  end
86
84
  end
87
85
 
@@ -121,6 +119,10 @@ module Shipit
121
119
  secrets.host.presence
122
120
  end
123
121
 
122
+ def default_merge_method
123
+ secrets.default_merge_method || 'merge'
124
+ end
125
+
124
126
  def enforce_publish_config
125
127
  secrets.enforce_publish_config.presence
126
128
  end
data/lib/shipit/engine.rb CHANGED
@@ -15,6 +15,8 @@ module Shipit
15
15
  task.js
16
16
  shipit.js
17
17
  shipit.css
18
+ merge_status.js
19
+ merge_status.css
18
20
  )
19
21
  app.config.assets.precompile << proc do |path|
20
22
  path =~ %r{\Aplugins/[\-\w]+\.(js|css)\Z}
@@ -22,7 +22,7 @@ module Shipit
22
22
  end
23
23
 
24
24
  def api
25
- @client = new_client if !defined?(@client) || @client.access_token != token
25
+ @client = new_client(access_token: token) if !defined?(@client) || @client.access_token != token
26
26
  @client
27
27
  end
28
28
 
@@ -40,7 +40,7 @@ module Shipit
40
40
  return unless private_key && app_id && installation_id
41
41
 
42
42
  Rails.cache.fetch('github:integration:token', expires_in: 50.minutes, race_condition_ttl: 10.minutes) do
43
- token = Octokit::Client.new(bearer_token: authentication_payload).create_app_installation_access_token(
43
+ token = new_client(bearer_token: authentication_payload).create_app_installation_access_token(
44
44
  installation_id,
45
45
  accept: 'application/vnd.github.machine-man-preview+json',
46
46
  ).token
@@ -84,6 +84,12 @@ module Shipit
84
84
  domain != DOMAIN
85
85
  end
86
86
 
87
+ def new_client(options = {})
88
+ client = Octokit::Client.new(options.reverse_merge(api_endpoint: api_endpoint))
89
+ client.middleware = Shipit.new_faraday_stack
90
+ client
91
+ end
92
+
87
93
  private
88
94
 
89
95
  attr_reader :webhook_secret, :oauth_id, :oauth_secret
@@ -100,15 +106,6 @@ module Shipit
100
106
  @private_key ||= @config.fetch(:private_key)
101
107
  end
102
108
 
103
- def new_client
104
- client = Octokit::Client.new(
105
- access_token: token,
106
- api_endpoint: api_endpoint,
107
- )
108
- client.middleware = Shipit.new_faraday_stack
109
- client
110
- end
111
-
112
109
  def authentication_payload
113
110
  payload = {
114
111
  iat: Time.now.to_i,
@@ -16,15 +16,6 @@ module Shipit
16
16
  end
17
17
  end
18
18
 
19
- def fetched?(commit)
20
- git_dir = File.join(@stack.git_path, '.git')
21
- if Dir.exist?(git_dir)
22
- git('rev-parse', '--quiet', '--verify', "#{commit.sha}^{commit}", env: env, chdir: @stack.git_path)
23
- else
24
- Command.new('test', '-d', git_dir, env: env, chdir: @stack.deploys_path)
25
- end
26
- end
27
-
28
19
  def fetch_deployed_revision
29
20
  with_temporary_working_directory(commit: @stack.commits.last) do |dir|
30
21
  spec = DeploySpec::FileSystem.new(dir, @stack.environment)
@@ -1,3 +1,3 @@
1
1
  module Shipit
2
- VERSION = '0.22.0'.freeze
2
+ VERSION = '0.23.0'.freeze
3
3
  end
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env bash
2
2
 
3
- echo -e "\033[1;31m Misconfigured package.json, please ensure the following has been met:\n \033[0m"
3
+ echo -e "\033[1;31m Issue(s) found in package.json. Ensure the following conditions are met and try again.\n \033[0m"
4
4
 
5
- echo -e "\033[1;31m * Please add a publishConfig with an access setting in your package.json. e.g.,\033[0m"
6
- echo -e "\n\033[1;31m\t\"publishConfig:\" {\n\t \"access\": \"<public|restricted>\" \n\t} \033[0m"
7
- echo -e "\n\033[1;31m * If your package is private, ensure your the package name is scoped (@organization/package) \033[0m"
5
+ echo -e "\033[1;31m * Set the appropriate access in publishConfig:\033[0m"
6
+ echo -e "\n\033[1;31m\t\"publishConfig\": {\n\t \"access\": \"<public|restricted>\" \n\t}\033[0m"
7
+ echo -e "\n\033[1;31m * If the package is private, its name must be scoped (@organization-scope/package)\033[0m"
8
8
  exit 1
@@ -0,0 +1,37 @@
1
+ require 'test_helper'
2
+
3
+ module Shipit
4
+ class MergeStatusControllerTest < ActionController::TestCase
5
+ setup do
6
+ request.env['HTTPS'] = 'on'
7
+ @request.host = URI(Shipit.host).host
8
+ session[:user_id] = shipit_users(:walrus).id
9
+ end
10
+
11
+ test "GET show" do
12
+ get :show, params: {referrer: 'https://github.com/Shopify/shipit-engine/pull/42', branch: 'master'}
13
+ assert_response :ok
14
+ assert_includes response.body, 'Ready to ship!'
15
+ end
16
+
17
+ test "GET show when there is no matching stacks" do
18
+ get :show, params: {referrer: 'https://github.com/Shopify/unknown-repo/pull/42', branch: 'master'}
19
+ assert_response :ok
20
+ assert_predicate response.body, :blank?
21
+ end
22
+
23
+ test "GET anonymous show returns a login message" do
24
+ session.delete(:user_id)
25
+ get :show, params: {referrer: 'https://github.com/Shopify/shipit-engine/pull/42', branch: 'master'}
26
+ assert_response :ok
27
+ assert_includes response.body.downcase, 'please log in'
28
+ end
29
+
30
+ test "GET anonymous show when there is no matching stack is blank" do
31
+ session.delete(:user_id)
32
+ get :show, params: {referrer: 'https://github.com/Shopify/unknown-repo/pull/42', branch: 'master'}
33
+ assert_response :ok
34
+ assert_predicate response.body, :blank?
35
+ end
36
+ end
37
+ end
Binary file
@@ -134,3 +134,30 @@ soc_deploy:
134
134
  created_at: <%= (60 - 1).minutes.ago.to_s(:db) %>
135
135
  started_at: <%= (60 - 1).minutes.ago.to_s(:db) %>
136
136
  ended_at: <%= (60 - 3).minutes.ago.to_s(:db) %>
137
+
138
+ shipit_rendered_failover:
139
+ id: 10
140
+ user: walrus
141
+ since_commit_id: 2 # second
142
+ until_commit_id: 2 # second
143
+ type: Shipit::Task
144
+ stack: shipit
145
+ status: success
146
+ definition: >
147
+ {
148
+ "id": "failover",
149
+ "action": "Failover a pod",
150
+ "title": "Failover pod %{POD_ID}",
151
+ "description": "Restart app and job servers",
152
+ "variables": [
153
+ {"name": "POD_ID", "title": "Id of the pod to failover"}
154
+ ],
155
+ "steps": [
156
+ "cap $ENVIRONMENT pod:failover"
157
+ ]
158
+ }
159
+ env:
160
+ POD_ID: "12"
161
+ created_at: <%= (60 - 3).minutes.ago.to_s(:db) %>
162
+ started_at: <%= (60 - 3).minutes.ago.to_s(:db) %>
163
+ ended_at: <%= (60 - 4).minutes.ago.to_s(:db) %>
@@ -14,7 +14,6 @@ module Shipit
14
14
  @commands = stub(:commands)
15
15
  Commands.expects(:for).with(@deploy).returns(@commands)
16
16
 
17
- @commands.expects(:fetched?).once.returns(false)
18
17
  @commands.expects(:fetch).once
19
18
  @commands.expects(:clone).once
20
19
  @commands.expects(:checkout).with(@deploy.until_commit).once
@@ -295,6 +295,7 @@ module Shipit
295
295
  'require' => [],
296
296
  'ignore' => [],
297
297
  'revalidate_after' => nil,
298
+ 'method' => nil,
298
299
  'max_divergence' => {
299
300
  'commits' => nil,
300
301
  'age' => nil,
@@ -442,6 +443,29 @@ module Shipit
442
443
  assert_equal %w(ci/circleci soc/compliance), @spec.required_statuses
443
444
  end
444
445
 
446
+ test "pull_request_merge_method defaults to `nil`" do
447
+ @spec.expects(:load_config).returns({})
448
+ assert_nil @spec.pull_request_merge_method
449
+ end
450
+
451
+ test "pull_request_merge_method returns `merge.method`" do
452
+ @spec.expects(:load_config).returns(
453
+ 'merge' => {
454
+ 'method' => 'squash',
455
+ },
456
+ )
457
+ assert_equal 'squash', @spec.pull_request_merge_method
458
+ end
459
+
460
+ test "pull_request_merge_method returns `nil` if `merge.method` is invalid" do
461
+ @spec.expects(:load_config).returns(
462
+ 'merge' => {
463
+ 'method' => 'squashing',
464
+ },
465
+ )
466
+ assert_nil @spec.pull_request_merge_method
467
+ end
468
+
445
469
  test "pull_request_ignored_statuses defaults to the union of ci.hide and ci.allow_failures" do
446
470
  @spec.expects(:load_config).returns(
447
471
  'ci' => {
@@ -6,6 +6,7 @@ module Shipit
6
6
  @definition = TaskDefinition.new(
7
7
  'restart',
8
8
  'action' => 'Restart application',
9
+ 'title' => 'Restart application %{FOO}',
9
10
  'description' => 'Restart app and job servers',
10
11
  'steps' => ['touch tmp/restart'],
11
12
  'allow_concurrency' => true,
@@ -36,6 +37,7 @@ module Shipit
36
37
  as_json = {
37
38
  id: 'restart',
38
39
  action: 'Restart application',
40
+ title: "Restart application %{FOO}",
39
41
  description: 'Restart app and job servers',
40
42
  steps: ['touch tmp/restart'],
41
43
  checklist: [],
@@ -0,0 +1,16 @@
1
+ require 'test_helper'
2
+
3
+ module Shipit
4
+ class TasksTest < ActiveSupport::TestCase
5
+ test "#title interpolates env" do
6
+ task = shipit_tasks(:shipit_rendered_failover)
7
+ assert_equal({'POD_ID' => '12'}, task.env)
8
+ assert_equal 'Failover pod 12', task.title
9
+ end
10
+
11
+ test "#title returns the task action if title is not defined" do
12
+ task = shipit_tasks(:shipit_restart)
13
+ assert_equal 'Restart application', task.title
14
+ end
15
+ end
16
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: shipit-engine
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.22.0
4
+ version: 0.23.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jean Boussier
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-04-26 00:00:00.000000000 Z
11
+ date: 2018-06-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: active_model_serializers
@@ -170,28 +170,28 @@ dependencies:
170
170
  requirements:
171
171
  - - "~>"
172
172
  - !ruby/object:Gem::Version
173
- version: 4.8.0
173
+ version: 4.9.0
174
174
  type: :runtime
175
175
  prerelease: false
176
176
  version_requirements: !ruby/object:Gem::Requirement
177
177
  requirements:
178
178
  - - "~>"
179
179
  - !ruby/object:Gem::Version
180
- version: 4.8.0
180
+ version: 4.9.0
181
181
  - !ruby/object:Gem::Dependency
182
182
  name: omniauth-github
183
183
  requirement: !ruby/object:Gem::Requirement
184
184
  requirements:
185
185
  - - "~>"
186
186
  - !ruby/object:Gem::Version
187
- version: 1.1.2
187
+ version: 1.3.0
188
188
  type: :runtime
189
189
  prerelease: false
190
190
  version_requirements: !ruby/object:Gem::Requirement
191
191
  requirements:
192
192
  - - "~>"
193
193
  - !ruby/object:Gem::Version
194
- version: 1.1.2
194
+ version: 1.3.0
195
195
  - !ruby/object:Gem::Dependency
196
196
  name: pubsubstub
197
197
  requirement: !ruby/object:Gem::Requirement
@@ -428,6 +428,7 @@ files:
428
428
  - app/assets/images/validation/invalid.png
429
429
  - app/assets/images/validation/required.png
430
430
  - app/assets/images/validation/valid.png
431
+ - app/assets/javascripts/merge_status.coffee
431
432
  - app/assets/javascripts/shipit.js.coffee
432
433
  - app/assets/javascripts/shipit/checklist.js.coffee
433
434
  - app/assets/javascripts/shipit/deploy.js.coffee
@@ -460,6 +461,7 @@ files:
460
461
  - app/assets/stylesheets/_structure/_layout.scss
461
462
  - app/assets/stylesheets/_structure/_main.scss
462
463
  - app/assets/stylesheets/_structure/_navigation.scss
464
+ - app/assets/stylesheets/merge_status.scss
463
465
  - app/assets/stylesheets/shipit.scss
464
466
  - app/assets/webfonts/CheckoutSymbols-Regular.eot
465
467
  - app/assets/webfonts/CheckoutSymbols-Regular.svg
@@ -485,6 +487,7 @@ files:
485
487
  - app/controllers/shipit/commits_controller.rb
486
488
  - app/controllers/shipit/deploys_controller.rb
487
489
  - app/controllers/shipit/github_authentication_controller.rb
490
+ - app/controllers/shipit/merge_status_controller.rb
488
491
  - app/controllers/shipit/pull_requests_controller.rb
489
492
  - app/controllers/shipit/rollbacks_controller.rb
490
493
  - app/controllers/shipit/shipit_controller.rb
@@ -495,6 +498,7 @@ files:
495
498
  - app/helpers/shipit/chunks_helper.rb
496
499
  - app/helpers/shipit/deploys_helper.rb
497
500
  - app/helpers/shipit/github_url_helper.rb
501
+ - app/helpers/shipit/merge_status_helper.rb
498
502
  - app/helpers/shipit/shipit_helper.rb
499
503
  - app/helpers/shipit/stacks_helper.rb
500
504
  - app/helpers/shipit/tasks_helper.rb
@@ -578,6 +582,7 @@ files:
578
582
  - app/serializers/shipit/user_serializer.rb
579
583
  - app/validators/ascii_only_validator.rb
580
584
  - app/validators/subset_validator.rb
585
+ - app/views/layouts/merge_status.html.erb
581
586
  - app/views/layouts/shipit.html.erb
582
587
  - app/views/shipit/_variables.html.erb
583
588
  - app/views/shipit/ccmenu/project.xml.builder
@@ -593,6 +598,15 @@ files:
593
598
  - app/views/shipit/deploys/rollback.html.erb
594
599
  - app/views/shipit/deploys/show.html.erb
595
600
  - app/views/shipit/github_authentication/failed.html.erb
601
+ - app/views/shipit/merge_status/_anchor.html.erb
602
+ - app/views/shipit/merge_status/_commit_count_warning.html.erb
603
+ - app/views/shipit/merge_status/_merge_queue_button.html.erb
604
+ - app/views/shipit/merge_status/_warning_icon.html.erb
605
+ - app/views/shipit/merge_status/backlogged.html.erb
606
+ - app/views/shipit/merge_status/failure.html.erb
607
+ - app/views/shipit/merge_status/locked.html.erb
608
+ - app/views/shipit/merge_status/logged_out.erb
609
+ - app/views/shipit/merge_status/success.html.erb
596
610
  - app/views/shipit/missing_settings.html.erb
597
611
  - app/views/shipit/pull_requests/_pull_request.html.erb
598
612
  - app/views/shipit/pull_requests/index.html.erb
@@ -676,7 +690,6 @@ files:
676
690
  - lib/shipit/first_parent_commits_iterator.rb
677
691
  - lib/shipit/github_app.rb
678
692
  - lib/shipit/null_serializer.rb
679
- - lib/shipit/octokit_bot_users_patch.rb
680
693
  - lib/shipit/octokit_iterator.rb
681
694
  - lib/shipit/paginator.rb
682
695
  - lib/shipit/rollback_commands.rb
@@ -717,6 +730,7 @@ files:
717
730
  - test/controllers/commits_controller_test.rb
718
731
  - test/controllers/deploys_controller_test.rb
719
732
  - test/controllers/github_authentication_controller_test.rb
733
+ - test/controllers/merge_status_controller_test.rb
720
734
  - test/controllers/pull_requests_controller_test.rb
721
735
  - test/controllers/rollbacks_controller_test.rb
722
736
  - test/controllers/stacks_controller_test.rb
@@ -839,6 +853,7 @@ files:
839
853
  - test/models/status/missing_test.rb
840
854
  - test/models/status_test.rb
841
855
  - test/models/task_definitions_test.rb
856
+ - test/models/tasks_test.rb
842
857
  - test/models/team_test.rb
843
858
  - test/models/undeployed_commits_test.rb
844
859
  - test/models/users_test.rb
@@ -960,6 +975,7 @@ test_files:
960
975
  - test/models/delivery_test.rb
961
976
  - test/models/commit_deployment_status_test.rb
962
977
  - test/models/api_client_test.rb
978
+ - test/models/tasks_test.rb
963
979
  - test/models/hook_test.rb
964
980
  - test/models/task_definitions_test.rb
965
981
  - test/models/status/group_test.rb
@@ -1012,6 +1028,7 @@ test_files:
1012
1028
  - test/controllers/stacks_controller_test.rb
1013
1029
  - test/controllers/commits_controller_test.rb
1014
1030
  - test/controllers/github_authentication_controller_test.rb
1031
+ - test/controllers/merge_status_controller_test.rb
1015
1032
  - test/controllers/ccmenu_controller_test.rb
1016
1033
  - test/controllers/commit_checks_controller_test.rb
1017
1034
  - test/controllers/pull_requests_controller_test.rb
@@ -1,25 +0,0 @@
1
- require 'octokit'
2
-
3
- # https://github.com/octokit/octokit.rb/pull/1006
4
- if Octokit::VERSION >= '5'
5
- raise 'This patch should be removed'
6
- else
7
- module Octokit
8
- module Connection
9
- protected
10
-
11
- def request(method, path, data, options = {})
12
- if data.is_a?(Hash)
13
- options[:query] = data.delete(:query) || {}
14
- options[:headers] = data.delete(:headers) || {}
15
- if accept = data.delete(:accept)
16
- options[:headers][:accept] = accept
17
- end
18
- end
19
-
20
- @last_response = response = agent.call(method, Addressable::URI.parse(path.to_s).normalize.to_s, data, options)
21
- response.data
22
- end
23
- end
24
- end
25
- end