shipit-engine 0.28.0 → 0.28.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bdb3736fb9999c0409f7b81081a52467f33a39ee419f2a40e14e6aca73866263
4
- data.tar.gz: f58bfcbbc8084bb18cf2234ed0a75658a5c6bc9e2b593bc8a2b90e5f89d030b5
3
+ metadata.gz: b1e854d10e7f525e0a9af5a02bfb432ae6cd091079a8adae14894fc2e42415f2
4
+ data.tar.gz: 250798a87f4662d2a13e01090a31f4fc3bf82df6b206468002ca5098c792d951
5
5
  SHA512:
6
- metadata.gz: 19ffafe44e93c6f02f277c5208160a605286557f5080cf3569355fcfa85b2a8583eace47a89c1ac223490ad157de451f0837343d5b818e891c9794b27ca20554
7
- data.tar.gz: 57be6895de1d5757a48b603cfb4796316f477b791feef7cfc876dc57b5226d869e65b2332e920e695e3edbba3bd99b39dc75e0e3ceeab2b6aee851eaeea15c2e
6
+ metadata.gz: 8872ae9ba8ed5dcbf9de6dca1d46d40f87d9b870a5927e4b31ab62f794713b9ec030f4b8e13cf344ab2fc588d501e6d35532f13019f70815247a11fdfac0e8c8
7
+ data.tar.gz: 146fc5d4fec1d577d5b49bbee57b3dc9d9f391522be6e6f8877dcf80b62438eafa908454439124843ba5034e96afaaae93632b3e61f8ef1211542d297d7a4666
@@ -142,8 +142,9 @@ pre {
142
142
  .less-important {
143
143
  color: $grey;
144
144
  margin-bottom: 0em;
145
- margin-top: 1em;
145
+ margin-top: 5em;
146
146
  p {
147
+ margin-top: 1.5rem;
147
148
  margin-bottom: 0.5em;
148
149
  }
149
150
  }
@@ -1,6 +1,6 @@
1
1
  module Shipit
2
2
  class FetchDeployedRevisionJob < BackgroundJob
3
- queue_as :default
3
+ queue_as :deploys
4
4
 
5
5
  def perform(stack)
6
6
  return if stack.active_task?
@@ -2,7 +2,7 @@ module Shipit
2
2
  class GithubSyncJob < BackgroundJob
3
3
  include BackgroundJob::Unique
4
4
 
5
- MAX_FETCHED_COMMITS = 10
5
+ MAX_FETCHED_COMMITS = 25
6
6
  queue_as :default
7
7
 
8
8
  self.timeout = 60
@@ -2,6 +2,8 @@ module Shipit
2
2
  class UpdateGithubLastDeployedRefJob < BackgroundJob
3
3
  queue_as :default
4
4
 
5
+ # We do not prefix 'refs/' because Octokit methods will do this automatically.
6
+ BRANCH_REF_PREFIX = 'heads'.freeze
5
7
  DEPLOY_PREFIX = 'shipit-deploy'.freeze
6
8
 
7
9
  def perform(stack)
@@ -20,7 +22,7 @@ module Shipit
20
22
  private
21
23
 
22
24
  def create_full_ref(stack_environment)
23
- [DEPLOY_PREFIX, stack_environment].join("/")
25
+ [BRANCH_REF_PREFIX, DEPLOY_PREFIX, stack_environment].join("/")
24
26
  end
25
27
 
26
28
  def create_ref(client:, repo_name:, ref:, sha:)
@@ -8,7 +8,7 @@ module Shipit
8
8
  end
9
9
 
10
10
  def refresh_status
11
- Rails.cache.write(CACHE_KEY, Shipit.github.api.github_status)
11
+ Rails.cache.write(CACHE_KEY, Shipit.github.api_status)
12
12
  rescue Faraday::Error, Octokit::ServerError
13
13
  end
14
14
  end
@@ -100,7 +100,7 @@ module Shipit
100
100
  assign_attributes(
101
101
  github_id: github_user.id,
102
102
  name: github_user.name || github_user.login, # Name is not mandatory on GitHub
103
- email: github_user.email,
103
+ email: appropriate_email_for(github_user),
104
104
  login: github_user.login,
105
105
  avatar_url: github_user.avatar_url,
106
106
  api_url: github_user.url,
@@ -123,5 +123,27 @@ module Shipit
123
123
  rescue Octokit::NotFound
124
124
  false
125
125
  end
126
+
127
+ def email_valid_and_preferred?(email_address)
128
+ org_domains = Shipit.preferred_org_emails
129
+ return true if org_domains.blank?
130
+ return false if email_address.blank?
131
+
132
+ org_domains.any? { |domain| email_address.end_with?("@#{domain}") }
133
+ end
134
+
135
+ def appropriate_email_for(github_user)
136
+ return github_user.email if email_valid_and_preferred?(github_user.email)
137
+
138
+ begin
139
+ github_api.emails
140
+ .sort_by { |e| e.primary ? 0 : 1 }
141
+ .map(&:email)
142
+ .find { |e| email_valid_and_preferred?(e) }
143
+ rescue Octokit::NotFound, Octokit::Forbidden
144
+ # If the user hasn't agreed to the necessary permission, we can't access their private emails.
145
+ nil
146
+ end
147
+ end
126
148
  end
127
149
  end
@@ -33,7 +33,7 @@
33
33
 
34
34
  <div id="layout-content">
35
35
  <% github_status = Shipit::GithubStatus.status
36
- unless github_status.nil? || github_status[:status] == 'good' %>
36
+ unless github_status.nil? || github_status[:status] == 'operational' %>
37
37
  <div class="banner github-status banner--orange hidden">
38
38
  <div class="banner__inner wrapper">
39
39
  <div class="banner__content">
@@ -9,18 +9,6 @@
9
9
  <%= render 'shipit/deploys/summary', commits: @deploy.commits %>
10
10
  </section>
11
11
 
12
- <% unless @deploy.commits_since.empty? %>
13
- <section class="less-important">
14
-
15
- <p>The following commits are <strong>not</strong> included in this deploy.
16
- Please ensure that none of these commits are needed for what
17
- <strong>is</strong> being deployed (for example, if they contain the revert
18
- of a broken change).</p>
19
-
20
- <%= render 'shipit/deploys/summary', commits: @deploy.commits_since %>
21
- </section>
22
- <% end %>
23
-
24
12
  <%= render_monitoring @stack %>
25
13
 
26
14
  <%= render_checks @commit %>
@@ -37,4 +25,21 @@
37
25
  <%= f.submit class: 'btn btn--primary btn--large trigger-deploy' %>
38
26
  </section>
39
27
  <% end %>
28
+
29
+ <% unless @deploy.commits_since.empty? %>
30
+ <section class="less-important">
31
+ <header class="section-header">
32
+ <h2>Commits not included in this deploy</h2>
33
+ </header>
34
+
35
+ <div>
36
+ <p>The following commits are <strong>not</strong> included in this deploy.
37
+ Please ensure that none of these commits are needed for what
38
+ <strong>is</strong> being deployed (for example, if they contain the revert
39
+ of a broken change).</p>
40
+
41
+ <%= render 'shipit/deploys/summary', commits: @deploy.commits_since %>
42
+ </div>
43
+ </section>
44
+ <% end %>
40
45
  </div>
data/lib/shipit.rb CHANGED
@@ -47,7 +47,7 @@ require 'shipit/deploy_commands'
47
47
  require 'shipit/rollback_commands'
48
48
  require 'shipit/environment_variables'
49
49
  require 'shipit/stat'
50
- require 'shipit/strip_cache_control'
50
+ require 'shipit/github_http_cache_middleware'
51
51
  require 'shipit/cast_value'
52
52
  require 'shipit/line_buffer'
53
53
 
@@ -60,7 +60,7 @@ module Shipit
60
60
  delegate :table_name_prefix, to: :secrets
61
61
 
62
62
  attr_accessor :disable_api_authentication, :timeout_exit_codes
63
- attr_writer :internal_hook_receivers, :task_logger
63
+ attr_writer :internal_hook_receivers, :task_logger, :preferred_org_emails
64
64
 
65
65
  self.timeout_exit_codes = [].freeze
66
66
 
@@ -106,22 +106,6 @@ module Shipit
106
106
  end
107
107
  end
108
108
 
109
- def new_faraday_stack
110
- Faraday::RackBuilder.new do |builder|
111
- builder.use(
112
- Faraday::HttpCache,
113
- shared_cache: false,
114
- store: Rails.cache,
115
- logger: Rails.logger,
116
- serializer: NullSerializer,
117
- )
118
- builder.use StripCacheControl
119
- builder.use Octokit::Response::RaiseError
120
- builder.adapter Faraday.default_adapter
121
- yield builder if block_given?
122
- end
123
- end
124
-
125
109
  def api_clients_secret
126
110
  secrets.api_clients_secret.presence || secrets.secret_key_base
127
111
  end
@@ -196,6 +180,10 @@ module Shipit
196
180
  @internal_hook_receivers ||= []
197
181
  end
198
182
 
183
+ def preferred_org_emails
184
+ @preferred_org_emails ||= []
185
+ end
186
+
199
187
  def task_logger
200
188
  @task_logger ||= Logger.new(nil)
201
189
  end
@@ -25,6 +25,7 @@ module Shipit
25
25
 
26
26
  DOMAIN = 'github.com'.freeze
27
27
  AuthenticationFailed = Class.new(StandardError)
28
+ API_STATUS_ID = 'brv1bkgrwx7q'.freeze
28
29
 
29
30
  attr_reader :oauth_teams, :domain, :bot_login
30
31
 
@@ -53,6 +54,13 @@ module Shipit
53
54
  client
54
55
  end
55
56
 
57
+ def api_status
58
+ conn = Faraday.new(url: 'https://www.githubstatus.com')
59
+ response = conn.get('/api/v2/components.json')
60
+ parsed = JSON.parse(response.body, symbolize_names: true)
61
+ parsed[:components].find { |c| c[:id] == API_STATUS_ID }
62
+ end
63
+
56
64
  def verify_webhook_signature(signature, message)
57
65
  return true unless webhook_secret
58
66
 
@@ -118,7 +126,7 @@ module Shipit
118
126
 
119
127
  def new_client(options = {})
120
128
  client = Octokit::Client.new(options.reverse_merge(api_endpoint: api_endpoint))
121
- client.middleware = Shipit.new_faraday_stack
129
+ client.middleware = faraday_stack
122
130
  client
123
131
  end
124
132
 
@@ -126,6 +134,21 @@ module Shipit
126
134
 
127
135
  attr_reader :webhook_secret, :oauth_id, :oauth_secret
128
136
 
137
+ def faraday_stack
138
+ @faraday_stack ||= Faraday::RackBuilder.new do |builder|
139
+ builder.use(
140
+ Faraday::HttpCache,
141
+ shared_cache: false,
142
+ store: Rails.cache,
143
+ logger: Rails.logger,
144
+ serializer: NullSerializer,
145
+ )
146
+ builder.use GitHubHTTPCacheMiddleware
147
+ builder.use Octokit::Response::RaiseError
148
+ builder.adapter Faraday.default_adapter
149
+ end
150
+ end
151
+
129
152
  def app_id
130
153
  @app_id ||= @config.fetch(:app_id)
131
154
  end
@@ -0,0 +1,56 @@
1
+ module Shipit
2
+ class GitHubHTTPCacheMiddleware < Faraday::Middleware
3
+ def call(request_env)
4
+ @app.call(request_env).on_complete do |response_env|
5
+ if headers = response_env[:response_headers]
6
+
7
+ # We're removing max-age and s-maxage because some endpoints,
8
+ # especially /<repo>/commits, returns a max-age=0. This means that
9
+ # if two commits are pushed within 1 minute of each others, we won't
10
+ # see the second one. So instead we still issue the request, but we
11
+ # revalidate it.
12
+ cache_control = parse(headers['cache-control'].to_s)
13
+ cache_control.delete('max-age')
14
+ cache_control.delete('s-maxage')
15
+ cache_control['no-cache'] = true
16
+ cache_control['must-revalidate'] = true
17
+ headers['cache-control'] = dump(cache_control)
18
+
19
+ # We're removing `Authorization` from the `Vary` header because
20
+ # Faraday::HttpCache has a very limited garbage collection support
21
+ # and this cause cache entries to grow indefinitely.
22
+ # See https://github.com/Shopify/shipit-engine/issues/935 for
23
+ # more details.
24
+ vary = parse(headers['vary'].to_s)
25
+ vary.delete('authorization')
26
+ headers['vary'] = dump(vary)
27
+ end
28
+ end
29
+ end
30
+
31
+ private
32
+
33
+ def dump(directives)
34
+ directives.map do |k, v|
35
+ if v == true
36
+ k
37
+ else
38
+ "#{k}=#{v}"
39
+ end
40
+ end.join(', ')
41
+ end
42
+
43
+ def parse(header)
44
+ directives = {}
45
+
46
+ header.delete(' ').split(',').each do |part|
47
+ next if part.empty?
48
+
49
+ name, value = part.split('=', 2)
50
+ directives[name.downcase] = (value || true) unless name.empty?
51
+ end
52
+
53
+ directives
54
+ end
55
+ end
56
+ end
@@ -1,3 +1,3 @@
1
1
  module Shipit
2
- VERSION = '0.28.0'.freeze
2
+ VERSION = '0.28.1'.freeze
3
3
  end
@@ -1,8 +1,11 @@
1
1
  require 'faker'
2
- require 'fakeweb'
2
+ require 'webmock'
3
+ include WebMock::API
4
+ WebMock.enable!
5
+ WebMock.allow_net_connect!
3
6
 
4
7
  # Sometimes on Travis the background job runs immediately so provide a response to fake hooks
5
- FakeWeb.register_uri(:post, %r{https://example\.com/}, status: %w(200 OK))
8
+ stub_request(:post, %r{https://example\.com/}).to_return(status: %w(200 OK))
6
9
 
7
10
  # Cheap hack to allow rake db:seed to work
8
11
  module Shipit
@@ -8,7 +8,7 @@ module Shipit
8
8
  end
9
9
 
10
10
  test "#perform delivers a delivery" do
11
- FakeWeb.register_uri(:post, @delivery.url, body: 'OK')
11
+ stub_request(:post, @delivery.url).to_return(body: 'OK')
12
12
  @job.perform(@delivery)
13
13
  assert_equal 'sent', @delivery.reload.status
14
14
  end
@@ -17,15 +17,15 @@ module Shipit
17
17
 
18
18
  test "#perform rejects unmergeable PRs and merge the others" do
19
19
  PullRequest.any_instance.stubs(:refresh!)
20
- FakeWeb.register_uri(:put, "#{@pending_pr.api_url}/merge", status: %w(200 OK), body: {
20
+ stub_request(:put, "#{@pending_pr.api_url}/merge").to_return(status: %w(200 OK), body: {
21
21
  sha: "6dcb09b5b57875f334f61aebed695e2e4193db5e",
22
22
  merged: true,
23
23
  message: "Pull Request successfully merged",
24
24
  }.to_json)
25
25
  branch_url = "https://api.github.com/repos/shopify/shipit-engine/git/refs/heads/feature-62"
26
- FakeWeb.register_uri(:delete, branch_url, status: %w(204 No content))
26
+ stub_request(:delete, branch_url).to_return(status: %w(204 No content))
27
27
  pulls_url = "https://api.github.com/repos/shopify/shipit-engine/pulls?base=feature-62"
28
- FakeWeb.register_uri(:get, pulls_url, status: %w(200 OK), body: '[]')
28
+ stub_request(:get, pulls_url).to_return(status: %w(200 OK), body: '[]')
29
29
 
30
30
  @job.perform(@stack)
31
31
 
@@ -35,7 +35,7 @@ module Shipit
35
35
 
36
36
  test "#perform rejects PRs if the merge attempt fails" do
37
37
  PullRequest.any_instance.stubs(:refresh!)
38
- FakeWeb.register_uri(:put, "#{@pending_pr.api_url}/merge", status: %w(405 Method not allowed), body: {
38
+ stub_request(:put, "#{@pending_pr.api_url}/merge").to_return(status: %w(405 Method not allowed), body: {
39
39
  message: "Pull Request is not mergeable",
40
40
  documentation_url: "https://developer.github.com/v3/pulls/#merge-a-pull-request-merge-button",
41
41
  }.to_json)
@@ -8,22 +8,23 @@ module Shipit
8
8
  @deploy = @stack.deploys.last
9
9
  @commit = @deploy.until_commit
10
10
  @api_client = Shipit.github.api
11
- @expected_ref_prefix = "shipit-deploy/#{@stack.environment}"
12
11
  @expected_name = @stack.github_repo_name
13
12
  @expected_sha = @commit.sha
14
13
 
15
- expected_ref = ["refs", @expected_ref_prefix].join('/')
16
- ref_url = "http://api.github.test.com/shopify/shipit-engine/git/#{expected_ref}"
14
+ expected_ref_suffix = "shipit-deploy/#{@stack.environment}"
15
+ @expected_ref = ["heads", expected_ref_suffix].join('/')
16
+
17
+ ref_url = "http://api.github.test.com/shopify/shipit-engine/git/#{@expected_ref}"
17
18
  commit_url = "https://api.github.test.com/repos/shopify/shipit-engine/git/commits/#{@commit.sha}"
18
19
  response_inner_obj = OpenStruct.new(sha: @commit.sha, type: "commit", url: commit_url)
19
- @response = OpenStruct.new(ref: expected_ref, node_id: "blah", url: ref_url, object: response_inner_obj)
20
+ @response = OpenStruct.new(ref: @expected_ref, node_id: "blah", url: ref_url, object: response_inner_obj)
20
21
  end
21
22
 
22
23
  test "#perform will create a ref when one is not present" do
23
24
  Octokit::UnprocessableEntity.any_instance.stubs(:build_error_message).returns("Reference does not exist")
24
25
 
25
- @api_client.expects(:update_ref).with(@expected_name, @expected_ref_prefix, @expected_sha).raises(Octokit::UnprocessableEntity)
26
- @api_client.expects(:create_ref).with(@expected_name, @expected_ref_prefix, @expected_sha).returns(@response)
26
+ @api_client.expects(:update_ref).with(@expected_name, @expected_ref, @expected_sha).raises(Octokit::UnprocessableEntity)
27
+ @api_client.expects(:create_ref).with(@expected_name, @expected_ref, @expected_sha).returns(@response)
27
28
 
28
29
  result = @job.perform(@stack)
29
30
 
@@ -38,7 +39,7 @@ module Shipit
38
39
  @commit.sha = new_sha
39
40
  @commit.save
40
41
 
41
- @api_client.expects(:update_ref).with(@expected_name, @expected_ref_prefix, new_sha).returns(@response)
42
+ @api_client.expects(:update_ref).with(@expected_name, @expected_ref, new_sha).returns(@response)
42
43
 
43
44
  result = @job.perform(@stack)
44
45
 
@@ -48,8 +49,8 @@ module Shipit
48
49
  test '#perform will raise an exception for non ref existence errors' do
49
50
  Octokit::UnprocessableEntity.any_instance.stubs(:build_error_message).returns("Some other error.")
50
51
 
51
- @api_client.expects(:update_ref).with(@expected_name, @expected_ref_prefix, @expected_sha).raises(Octokit::UnprocessableEntity)
52
- @api_client.expects(:create_ref).with(@expected_name, @expected_ref_prefix, @expected_sha).never
52
+ @api_client.expects(:update_ref).with(@expected_name, @expected_ref, @expected_sha).raises(Octokit::UnprocessableEntity)
53
+ @api_client.expects(:create_ref).with(@expected_name, @expected_ref, @expected_sha).never
53
54
 
54
55
  assert_raises Octokit::UnprocessableEntity do
55
56
  @job.perform(@stack)
@@ -72,7 +73,7 @@ module Shipit
72
73
  new_deploy.status = "faulty"
73
74
  new_deploy.save
74
75
 
75
- @api_client.expects(:update_ref).with(@expected_name, @expected_ref_prefix, new_sha).returns(@response)
76
+ @api_client.expects(:update_ref).with(@expected_name, @expected_ref, new_sha).returns(@response)
76
77
  result = @job.perform(@stack)
77
78
 
78
79
  assert_equal @response, result
@@ -81,7 +82,7 @@ module Shipit
81
82
  new_deploy.status = "success"
82
83
  new_deploy.save
83
84
 
84
- @api_client.expects(:update_ref).with(@expected_name, @expected_ref_prefix, new_commit.sha).returns(@response)
85
+ @api_client.expects(:update_ref).with(@expected_name, @expected_ref, new_commit.sha).returns(@response)
85
86
  @job.perform(@stack)
86
87
  end
87
88
  end
@@ -8,6 +8,12 @@ module Shipit
8
8
  @pr.message = "Merge pull request #31 from Shopify/improve-polling\n\nSeveral improvements to polling"
9
9
  @stack.reload
10
10
  @commit = shipit_commits(:first)
11
+
12
+ stub_request(:get, "https://api.github.com/user/emails").to_return(
13
+ status: %w(200 OK),
14
+ body: {}.to_json,
15
+ headers: {"Content-Type" => "application/json"},
16
+ )
11
17
  end
12
18
 
13
19
  test '.create_from_github handle unknown users' do
@@ -24,7 +24,7 @@ module Shipit
24
24
 
25
25
  test "#send! post the payload and update the status to `sent`" do
26
26
  headers = {'content-type' => 'text/plain', 'content-length' => '2'}
27
- FakeWeb.register_uri(:post, @delivery.url, headers.merge(body: 'OK'))
27
+ stub_request(:post, @delivery.url).to_return(headers: headers, body: 'OK')
28
28
 
29
29
  assert_equal 'scheduled', @delivery.status
30
30
  @delivery.send!
@@ -3,6 +3,7 @@ require 'test_helper'
3
3
  module Shipit
4
4
  class UsersTest < ActiveSupport::TestCase
5
5
  setup do
6
+ @previous_preferred_org_emails = Shipit.preferred_org_emails
6
7
  @user = shipit_users(:walrus)
7
8
  @github_user = stub(
8
9
  id: 42,
@@ -12,6 +13,8 @@ module Shipit
12
13
  avatar_url: 'https://avatars.githubusercontent.com/u/42?v=3',
13
14
  url: 'https://api.github.com/user/george',
14
15
  )
16
+ @org_domain = "shopify.com"
17
+ @emails_url = "https://api.github.com/user/emails"
15
18
  @minimal_github_user = stub(
16
19
  id: 43,
17
20
  name: nil,
@@ -23,6 +26,10 @@ module Shipit
23
26
  )
24
27
  end
25
28
 
29
+ teardown do
30
+ Shipit.preferred_org_emails = @previous_preferred_org_emails
31
+ end
32
+
26
33
  test "find_or_create_from_github persist a new user if he is unknown" do
27
34
  assert_difference 'User.count', 1 do
28
35
  fetch_user
@@ -58,10 +65,103 @@ module Shipit
58
65
  end
59
66
 
60
67
  test "find_or_create_from_github accepts minimal users without name nor email" do
68
+ Shipit.preferred_org_emails = [].freeze
61
69
  user = User.find_or_create_from_github(@minimal_github_user)
62
70
  assert_equal @minimal_github_user.login, user.login
63
71
  end
64
72
 
73
+ test "find_or_create_from_github selects any email when org email is unspecified" do
74
+ github_org_user = stub(
75
+ id: 42,
76
+ name: 'Jim Jones',
77
+ login: 'jim',
78
+ email: "jim@#{@org_domain}",
79
+ avatar_url: 'https://avatars.githubusercontent.com/u/42?v=3',
80
+ url: 'https://api.github.com/user/jim',
81
+ )
82
+
83
+ Shipit.preferred_org_emails = [].freeze
84
+ user = User.find_or_create_from_github(github_org_user)
85
+ assert_equal github_org_user.email, user.email
86
+ end
87
+
88
+ test "find_or_create_from_github selects org email for user" do
89
+ Shipit.preferred_org_emails = [@org_domain]
90
+ expected_email = "myuser@#{@org_domain}"
91
+
92
+ stub_request(:get, @emails_url).to_return(
93
+ status: %w(200 OK),
94
+ body: [{email: expected_email}].to_json,
95
+ headers: {"Content-Type" => "application/json"},
96
+ )
97
+
98
+ user = User.find_or_create_from_github(@github_user)
99
+ assert_equal expected_email, user.email
100
+ end
101
+
102
+ test "find_or_create_from_github selects private and primary org email for user when necessary" do
103
+ Shipit.preferred_org_emails = [@org_domain]
104
+ expected_email = "myuser@#{@org_domain}"
105
+ result_email_records = [
106
+ {
107
+ email: "notmyuser1@#{@org_domain}",
108
+ primary: false,
109
+ },
110
+ {
111
+ email: "notmyuser2@#{@org_domain}",
112
+ },
113
+ {
114
+ email: expected_email,
115
+ primary: true,
116
+ },
117
+ ]
118
+
119
+ stub_request(:get, @emails_url).to_return(
120
+ status: %w(200 OK),
121
+ body: result_email_records.to_json,
122
+ headers: {"Content-Type" => "application/json"},
123
+ )
124
+
125
+ user = User.find_or_create_from_github(@github_user)
126
+ assert_equal expected_email, user.email
127
+ end
128
+
129
+ test "find_or_create_from_github selects no email when org emails are provided but not found" do
130
+ Shipit.preferred_org_emails = [@org_domain]
131
+ result_email_records = [
132
+ {
133
+ email: "notmyuser1@not#{@org_domain}",
134
+ primary: false,
135
+ },
136
+ {
137
+ email: "notmyuser2@not#{@org_domain}",
138
+ },
139
+ ]
140
+
141
+ stub_request(:get, @emails_url).to_return(
142
+ status: %w(200 OK),
143
+ body: result_email_records.to_json,
144
+ headers: {"Content-Type" => "application/json"},
145
+ )
146
+
147
+ user = User.find_or_create_from_github(@github_user)
148
+ assert_nil user.email
149
+ end
150
+
151
+ test "find_or_create_from_github handles user 404" do
152
+ Shipit.preferred_org_emails = [@org_domain]
153
+ Octokit::Client.any_instance.expects(:emails).raises(Octokit::NotFound)
154
+ user = User.find_or_create_from_github(@minimal_github_user)
155
+ assert_nil user.email
156
+ end
157
+
158
+ test "find_or_create_from_github handles user 403" do
159
+ Shipit.preferred_org_emails = [@org_domain]
160
+ Octokit::Client.any_instance.expects(:emails).raises(Octokit::Forbidden)
161
+ user = User.find_or_create_from_github(@minimal_github_user)
162
+ assert_nil user.email
163
+ end
164
+
65
165
  test "#identifiers_for_ping returns a hash with the user's github_id, name, email and github_login" do
66
166
  user = shipit_users(:bob)
67
167
  expected_ouput = {github_id: user.github_id, name: user.name, email: user.email, github_login: user.login}
data/test/test_helper.rb CHANGED
@@ -3,8 +3,7 @@ ENV["RAILS_ENV"] ||= "test"
3
3
  require 'simplecov'
4
4
  SimpleCov.start 'rails'
5
5
 
6
- require 'fakeweb'
7
- FakeWeb.allow_net_connect = false
6
+ require 'webmock/minitest'
8
7
 
9
8
  require File.expand_path('../../test/dummy/config/environment.rb', __FILE__)
10
9
  ActiveRecord::Migrator.migrations_paths = [
@@ -13,6 +13,34 @@ module Shipit
13
13
  end
14
14
  end
15
15
 
16
+ test "#api_status" do
17
+ stub_request(:get, "https://www.githubstatus.com/api/v2/components.json").to_return(
18
+ status: 200,
19
+ body: %(
20
+ {
21
+ "page":{},
22
+ "components":[
23
+ {
24
+ "id":"brv1bkgrwx7q",
25
+ "name":"API Requests",
26
+ "status":"operational",
27
+ "created_at":"2017-01-31T20:01:46.621Z",
28
+ "updated_at":"2019-07-23T18:41:18.197Z",
29
+ "position":2,
30
+ "description":"Requests for GitHub APIs",
31
+ "showcase":false,
32
+ "group_id":null,
33
+ "page_id":"kctbh9vrtdwd",
34
+ "group":false,
35
+ "only_show_if_degraded":false
36
+ }
37
+ ]
38
+ }
39
+ ),
40
+ )
41
+ assert_equal "operational", app.api_status[:status]
42
+ end
43
+
16
44
  test "#domain defaults to github.com" do
17
45
  assert_equal 'github.com', @github.domain
18
46
  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.28.0
4
+ version: 0.28.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jean Boussier
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-07-19 00:00:00.000000000 Z
11
+ date: 2019-08-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: active_model_serializers
@@ -706,6 +706,7 @@ files:
706
706
  - lib/shipit/first_parent_commits_iterator.rb
707
707
  - lib/shipit/flock.rb
708
708
  - lib/shipit/github_app.rb
709
+ - lib/shipit/github_http_cache_middleware.rb
709
710
  - lib/shipit/line_buffer.rb
710
711
  - lib/shipit/null_serializer.rb
711
712
  - lib/shipit/octokit_check_runs.rb
@@ -715,7 +716,6 @@ files:
715
716
  - lib/shipit/simple_message_verifier.rb
716
717
  - lib/shipit/stack_commands.rb
717
718
  - lib/shipit/stat.rb
718
- - lib/shipit/strip_cache_control.rb
719
719
  - lib/shipit/task_commands.rb
720
720
  - lib/shipit/version.rb
721
721
  - lib/snippets/assert-egg-version-tag
@@ -908,155 +908,154 @@ required_rubygems_version: !ruby/object:Gem::Requirement
908
908
  - !ruby/object:Gem::Version
909
909
  version: '0'
910
910
  requirements: []
911
- rubyforge_project:
912
- rubygems_version: 2.7.6
911
+ rubygems_version: 3.0.3
913
912
  signing_key:
914
913
  specification_version: 4
915
914
  summary: Application deployment software
916
915
  test_files:
917
- - test/helpers/hooks_helper.rb
918
- - test/helpers/links_helper.rb
919
- - test/helpers/fixture_aliases_helper.rb
920
- - test/helpers/json_helper.rb
921
- - test/helpers/payloads_helper.rb
922
- - test/helpers/api_helper.rb
923
- - test/helpers/queries_helper.rb
924
- - test/models/membership_test.rb
925
- - test/models/rollbacks_test.rb
926
- - test/models/output_chunk_test.rb
927
- - test/models/pull_request_test.rb
928
- - test/models/team_test.rb
929
- - test/models/commit_deployment_status_test.rb
930
- - test/models/deploy_spec_test.rb
931
- - test/models/task_definitions_test.rb
932
- - test/models/stacks_test.rb
933
- - test/models/undeployed_commits_test.rb
934
- - test/models/shipit/check_run_test.rb
935
- - test/models/github_hook_test.rb
936
- - test/models/status/group_test.rb
937
- - test/models/status/missing_test.rb
938
- - test/models/api_client_test.rb
939
- - test/models/deploys_test.rb
940
- - test/models/hook_test.rb
941
- - test/models/commit_checks_test.rb
942
- - test/models/status_test.rb
943
- - test/models/users_test.rb
944
- - test/models/commit_deployment_test.rb
945
- - test/models/release_statuses_test.rb
946
- - test/models/duration_test.rb
947
- - test/models/tasks_test.rb
948
- - test/models/delivery_test.rb
949
- - test/models/commits_test.rb
950
- - test/fixtures/payloads/check_suite_master.json
951
- - test/fixtures/payloads/push_not_master.json
952
- - test/fixtures/payloads/status_master.json
953
- - test/fixtures/payloads/push_master.json
954
- - test/fixtures/timeout
955
- - test/fixtures/shipit/users.yml
956
- - test/fixtures/shipit/output_chunks.yml
957
- - test/fixtures/shipit/teams.yml
958
- - test/fixtures/shipit/github_hooks.yml
959
- - test/fixtures/shipit/hooks.yml
960
- - test/fixtures/shipit/commits.yml
961
- - test/fixtures/shipit/commit_deployments.yml
962
- - test/fixtures/shipit/statuses.yml
963
- - test/fixtures/shipit/stacks.yml
964
- - test/fixtures/shipit/pull_requests.yml
965
- - test/fixtures/shipit/api_clients.yml
966
- - test/fixtures/shipit/tasks.yml
967
- - test/fixtures/shipit/release_statuses.yml
968
- - test/fixtures/shipit/memberships.yml
969
- - test/fixtures/shipit/commit_deployment_statuses.yml
970
- - test/fixtures/shipit/deliveries.yml
971
- - test/fixtures/shipit/check_runs.yml
972
- - test/dummy/config/secrets.yml
973
- - test/dummy/config/boot.rb
974
- - test/dummy/config/database.postgresql.yml
975
- - test/dummy/config/database.mysql.yml
976
- - test/dummy/config/locales/en.yml
977
- - test/dummy/config/environments/production.rb
978
- - test/dummy/config/environments/test.rb
979
- - test/dummy/config/environments/development.rb
980
- - test/dummy/config/application.rb
981
- - test/dummy/config/routes.rb
982
- - test/dummy/config/initializers/0_load_development_secrets.rb
983
- - test/dummy/config/initializers/wrap_parameters.rb
984
- - test/dummy/config/initializers/session_store.rb
985
- - test/dummy/config/initializers/inflections.rb
986
- - test/dummy/config/initializers/cookies_serializer.rb
987
- - test/dummy/config/initializers/assets.rb
988
- - test/dummy/config/initializers/mime_types.rb
989
- - test/dummy/config/initializers/filter_parameter_logging.rb
990
- - test/dummy/config/initializers/backtrace_silencers.rb
991
- - test/dummy/config/environment.rb
992
- - test/dummy/config/database.yml
993
- - test/dummy/Rakefile
916
+ - test/dummy/public/favicon.ico
917
+ - test/dummy/public/500.html
918
+ - test/dummy/public/422.html
919
+ - test/dummy/public/404.html
920
+ - test/dummy/db/seeds.rb
921
+ - test/dummy/db/schema.rb
922
+ - test/dummy/bin/rake
994
923
  - test/dummy/bin/bundle
995
924
  - test/dummy/bin/rails
996
- - test/dummy/bin/rake
997
925
  - test/dummy/bin/setup
998
- - test/dummy/public/422.html
999
- - test/dummy/public/favicon.ico
1000
- - test/dummy/public/404.html
1001
- - test/dummy/public/500.html
1002
- - test/dummy/app/helpers/application_helper.rb
926
+ - test/dummy/app/views/layouts/application.html.erb
1003
927
  - test/dummy/app/assets/stylesheets/application.css
1004
928
  - test/dummy/app/assets/javascripts/application.js
1005
- - test/dummy/app/views/layouts/application.html.erb
1006
929
  - test/dummy/app/controllers/application_controller.rb
1007
- - test/dummy/db/seeds.rb
1008
- - test/dummy/db/schema.rb
930
+ - test/dummy/app/helpers/application_helper.rb
1009
931
  - test/dummy/config.ru
1010
- - test/controllers/deploys_controller_test.rb
932
+ - test/dummy/Rakefile
933
+ - test/dummy/config/application.rb
934
+ - test/dummy/config/database.yml
935
+ - test/dummy/config/locales/en.yml
936
+ - test/dummy/config/secrets.yml
937
+ - test/dummy/config/boot.rb
938
+ - test/dummy/config/database.mysql.yml
939
+ - test/dummy/config/initializers/filter_parameter_logging.rb
940
+ - test/dummy/config/initializers/session_store.rb
941
+ - test/dummy/config/initializers/backtrace_silencers.rb
942
+ - test/dummy/config/initializers/mime_types.rb
943
+ - test/dummy/config/initializers/cookies_serializer.rb
944
+ - test/dummy/config/initializers/0_load_development_secrets.rb
945
+ - test/dummy/config/initializers/assets.rb
946
+ - test/dummy/config/initializers/wrap_parameters.rb
947
+ - test/dummy/config/initializers/inflections.rb
948
+ - test/dummy/config/environment.rb
949
+ - test/dummy/config/routes.rb
950
+ - test/dummy/config/database.postgresql.yml
951
+ - test/dummy/config/environments/test.rb
952
+ - test/dummy/config/environments/development.rb
953
+ - test/dummy/config/environments/production.rb
954
+ - test/controllers/webhooks_controller_test.rb
955
+ - test/controllers/rollbacks_controller_test.rb
956
+ - test/controllers/github_authentication_controller_test.rb
957
+ - test/controllers/merge_status_controller_test.rb
958
+ - test/controllers/commit_checks_controller_test.rb
959
+ - test/controllers/ccmenu_controller_test.rb
1011
960
  - test/controllers/stacks_controller_test.rb
1012
- - test/controllers/status_controller_test.rb
1013
- - test/controllers/api/deploys_controller_test.rb
1014
- - test/controllers/api/locks_controller_test.rb
1015
- - test/controllers/api/stacks_controller_test.rb
1016
- - test/controllers/api/release_statuses_controller_test.rb
961
+ - test/controllers/deploys_controller_test.rb
962
+ - test/controllers/api/hooks_controller_test.rb
1017
963
  - test/controllers/api/ccmenu_controller_test.rb
964
+ - test/controllers/api/stacks_controller_test.rb
965
+ - test/controllers/api/base_controller_test.rb
966
+ - test/controllers/api/locks_controller_test.rb
967
+ - test/controllers/api/deploys_controller_test.rb
1018
968
  - test/controllers/api/commits_controller_test.rb
1019
- - test/controllers/api/outputs_controller_test.rb
1020
- - test/controllers/api/hooks_controller_test.rb
969
+ - test/controllers/api/release_statuses_controller_test.rb
1021
970
  - test/controllers/api/pull_requests_controller_test.rb
1022
971
  - test/controllers/api/tasks_controller_test.rb
1023
- - test/controllers/api/base_controller_test.rb
1024
- - test/controllers/commit_checks_controller_test.rb
1025
- - test/controllers/release_statuses_controller_test.rb
1026
- - test/controllers/webhooks_controller_test.rb
1027
- - test/controllers/ccmenu_controller_test.rb
1028
- - test/controllers/rollbacks_controller_test.rb
972
+ - test/controllers/api/outputs_controller_test.rb
973
+ - test/controllers/status_controller_test.rb
1029
974
  - test/controllers/commits_controller_test.rb
1030
- - test/controllers/github_authentication_controller_test.rb
975
+ - test/controllers/release_statuses_controller_test.rb
1031
976
  - test/controllers/pull_requests_controller_test.rb
1032
977
  - test/controllers/tasks_controller_test.rb
1033
- - test/controllers/merge_status_controller_test.rb
978
+ - test/unit/command_test.rb
979
+ - test/unit/commands_test.rb
980
+ - test/unit/line_buffer_test.rb
981
+ - test/unit/deploy_commands_test.rb
982
+ - test/unit/shipit_test.rb
983
+ - test/unit/rollback_commands_test.rb
984
+ - test/unit/csv_serializer_test.rb
985
+ - test/unit/variable_definition_test.rb
986
+ - test/unit/github_url_helper_test.rb
987
+ - test/unit/environment_variables_test.rb
988
+ - test/unit/github_app_test.rb
989
+ - test/models/release_statuses_test.rb
990
+ - test/models/deploys_test.rb
991
+ - test/models/undeployed_commits_test.rb
992
+ - test/models/team_test.rb
993
+ - test/models/rollbacks_test.rb
994
+ - test/models/commit_checks_test.rb
995
+ - test/models/github_hook_test.rb
996
+ - test/models/task_definitions_test.rb
997
+ - test/models/tasks_test.rb
998
+ - test/models/output_chunk_test.rb
999
+ - test/models/commit_deployment_status_test.rb
1000
+ - test/models/delivery_test.rb
1001
+ - test/models/users_test.rb
1002
+ - test/models/commit_deployment_test.rb
1003
+ - test/models/duration_test.rb
1004
+ - test/models/api_client_test.rb
1005
+ - test/models/shipit/check_run_test.rb
1006
+ - test/models/commits_test.rb
1007
+ - test/models/status/group_test.rb
1008
+ - test/models/status/missing_test.rb
1009
+ - test/models/deploy_spec_test.rb
1010
+ - test/models/stacks_test.rb
1011
+ - test/models/hook_test.rb
1012
+ - test/models/membership_test.rb
1013
+ - test/models/status_test.rb
1014
+ - test/models/pull_request_test.rb
1034
1015
  - test/test_command_integration.rb
1035
- - test/test_helper.rb
1036
- - test/jobs/destroy_stack_job_test.rb
1037
- - test/jobs/fetch_deployed_revision_job_test.rb
1038
- - test/jobs/fetch_commit_stats_job_test.rb
1016
+ - test/helpers/hooks_helper.rb
1017
+ - test/helpers/queries_helper.rb
1018
+ - test/helpers/json_helper.rb
1019
+ - test/helpers/fixture_aliases_helper.rb
1020
+ - test/helpers/payloads_helper.rb
1021
+ - test/helpers/links_helper.rb
1022
+ - test/helpers/api_helper.rb
1023
+ - test/jobs/emit_event_job_test.rb
1024
+ - test/jobs/unique_job_test.rb
1039
1025
  - test/jobs/merge_pull_requests_job_test.rb
1026
+ - test/jobs/deliver_hook_job_test.rb
1040
1027
  - test/jobs/update_github_last_deployed_ref_job_test.rb
1041
- - test/jobs/cache_deploy_spec_job_test.rb
1042
- - test/jobs/emit_event_job_test.rb
1028
+ - test/jobs/refresh_status_job_test.rb
1029
+ - test/jobs/fetch_deployed_revision_job_test.rb
1030
+ - test/jobs/purge_old_deliveries_job_test.rb
1043
1031
  - test/jobs/refresh_github_user_job_test.rb
1044
1032
  - test/jobs/chunk_rollup_job_test.rb
1045
1033
  - test/jobs/mark_deploy_healthy_job_test.rb
1046
- - test/jobs/refresh_status_job_test.rb
1047
- - test/jobs/purge_old_deliveries_job_test.rb
1048
- - test/jobs/deliver_hook_job_test.rb
1049
- - test/jobs/github_sync_job_test.rb
1034
+ - test/jobs/fetch_commit_stats_job_test.rb
1035
+ - test/jobs/cache_deploy_spec_job_test.rb
1050
1036
  - test/jobs/perform_task_job_test.rb
1051
- - test/jobs/unique_job_test.rb
1052
- - test/unit/environment_variables_test.rb
1053
- - test/unit/commands_test.rb
1054
- - test/unit/github_app_test.rb
1055
- - test/unit/rollback_commands_test.rb
1056
- - test/unit/command_test.rb
1057
- - test/unit/shipit_test.rb
1058
- - test/unit/line_buffer_test.rb
1059
- - test/unit/csv_serializer_test.rb
1060
- - test/unit/deploy_commands_test.rb
1061
- - test/unit/variable_definition_test.rb
1062
- - test/unit/github_url_helper_test.rb
1037
+ - test/jobs/github_sync_job_test.rb
1038
+ - test/jobs/destroy_stack_job_test.rb
1039
+ - test/fixtures/timeout
1040
+ - test/fixtures/shipit/check_runs.yml
1041
+ - test/fixtures/shipit/release_statuses.yml
1042
+ - test/fixtures/shipit/users.yml
1043
+ - test/fixtures/shipit/output_chunks.yml
1044
+ - test/fixtures/shipit/deliveries.yml
1045
+ - test/fixtures/shipit/hooks.yml
1046
+ - test/fixtures/shipit/github_hooks.yml
1047
+ - test/fixtures/shipit/statuses.yml
1048
+ - test/fixtures/shipit/memberships.yml
1049
+ - test/fixtures/shipit/teams.yml
1050
+ - test/fixtures/shipit/tasks.yml
1051
+ - test/fixtures/shipit/api_clients.yml
1052
+ - test/fixtures/shipit/stacks.yml
1053
+ - test/fixtures/shipit/commits.yml
1054
+ - test/fixtures/shipit/pull_requests.yml
1055
+ - test/fixtures/shipit/commit_deployments.yml
1056
+ - test/fixtures/shipit/commit_deployment_statuses.yml
1057
+ - test/fixtures/payloads/status_master.json
1058
+ - test/fixtures/payloads/push_master.json
1059
+ - test/fixtures/payloads/push_not_master.json
1060
+ - test/fixtures/payloads/check_suite_master.json
1061
+ - test/test_helper.rb
@@ -1,40 +0,0 @@
1
- module Shipit
2
- class StripCacheControl < Faraday::Middleware
3
- def call(request_env)
4
- @app.call(request_env).on_complete do |response_env|
5
- if headers = response_env[:response_headers]
6
- headers.delete('last-modified')
7
- directives = parse(headers['cache-control'].to_s)
8
- directives.delete('max-age')
9
- directives.delete('s-maxage')
10
- headers['cache-control'] = dump(directives)
11
- end
12
- end
13
- end
14
-
15
- private
16
-
17
- def dump(directives)
18
- directives.map do |k, v|
19
- if v == true
20
- k
21
- else
22
- "#{k}=#{v}"
23
- end
24
- end.join(', ')
25
- end
26
-
27
- def parse(header)
28
- directives = {}
29
-
30
- header.delete(' ').split(',').each do |part|
31
- next if part.empty?
32
-
33
- name, value = part.split('=', 2)
34
- directives[name.downcase] = (value || true) unless name.empty?
35
- end
36
-
37
- directives
38
- end
39
- end
40
- end