shipit-engine 0.33.0 → 0.34.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (102) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +13 -2
  3. data/app/assets/stylesheets/_pages/_deploy.scss +0 -2
  4. data/app/controllers/shipit/api/ccmenu_controller.rb +1 -1
  5. data/app/controllers/shipit/api/deploys_controller.rb +2 -0
  6. data/app/controllers/shipit/api/rollbacks_controller.rb +2 -1
  7. data/app/controllers/shipit/api/stacks_controller.rb +1 -0
  8. data/app/controllers/shipit/deploys_controller.rb +1 -1
  9. data/app/controllers/shipit/stacks_controller.rb +2 -2
  10. data/app/controllers/shipit/tasks_controller.rb +2 -2
  11. data/app/controllers/shipit/webhooks_controller.rb +23 -4
  12. data/app/helpers/shipit/shipit_helper.rb +0 -1
  13. data/app/jobs/shipit/deliver_hook_job.rb +1 -1
  14. data/app/jobs/shipit/github_sync_job.rb +13 -9
  15. data/app/jobs/shipit/update_github_last_deployed_ref_job.rb +1 -1
  16. data/app/models/shipit/anonymous_user.rb +6 -2
  17. data/app/models/shipit/check_run.rb +36 -0
  18. data/app/models/shipit/commit.rb +20 -9
  19. data/app/models/shipit/commit_checks.rb +13 -13
  20. data/app/models/shipit/commit_deployment.rb +3 -3
  21. data/app/models/shipit/commit_deployment_status.rb +3 -3
  22. data/app/models/shipit/deploy.rb +16 -11
  23. data/app/models/shipit/deploy_spec/lerna_discovery.rb +12 -4
  24. data/app/models/shipit/duration.rb +2 -0
  25. data/app/models/shipit/hook.rb +26 -2
  26. data/app/models/shipit/merge_request.rb +9 -7
  27. data/app/models/shipit/pull_request.rb +1 -1
  28. data/app/models/shipit/release_status.rb +1 -1
  29. data/app/models/shipit/repository.rb +9 -3
  30. data/app/models/shipit/review_stack.rb +16 -2
  31. data/app/models/shipit/stack.rb +59 -25
  32. data/app/models/shipit/status/group.rb +1 -1
  33. data/app/models/shipit/task.rb +6 -2
  34. data/app/models/shipit/task_execution_strategy/default.rb +4 -5
  35. data/app/models/shipit/team.rb +4 -2
  36. data/app/models/shipit/user.rb +4 -0
  37. data/app/models/shipit/webhooks/handlers/pull_request/review_stack_adapter.rb +1 -1
  38. data/app/models/shipit/webhooks/handlers/push_handler.rb +4 -1
  39. data/app/serializers/shipit/merge_request_serializer.rb +1 -1
  40. data/app/validators/subset_validator.rb +1 -1
  41. data/app/views/layouts/merge_status.html.erb +1 -1
  42. data/app/views/shipit/stacks/_banners.html.erb +2 -1
  43. data/app/views/shipit/stacks/new.html.erb +1 -1
  44. data/config/secrets.development.example.yml +24 -0
  45. data/config/secrets.development.shopify.yml +20 -9
  46. data/db/migrate/20210325194053_remove_stacks_branch_default.rb +5 -0
  47. data/db/migrate/20210504200438_add_github_updated_at_to_check_runs.rb +5 -0
  48. data/lib/shipit.rb +39 -15
  49. data/lib/shipit/command.rb +7 -6
  50. data/lib/shipit/commands.rb +9 -2
  51. data/lib/shipit/engine.rb +2 -0
  52. data/lib/shipit/flock.rb +8 -1
  53. data/lib/shipit/github_app.rb +7 -5
  54. data/lib/shipit/octokit_iterator.rb +3 -3
  55. data/lib/shipit/simple_message_verifier.rb +2 -2
  56. data/lib/shipit/stack_commands.rb +28 -4
  57. data/lib/shipit/task_commands.rb +6 -0
  58. data/lib/shipit/version.rb +1 -1
  59. data/lib/snippets/publish-lerna-independent-packages +35 -34
  60. data/lib/snippets/publish-lerna-independent-packages-legacy +39 -0
  61. data/test/controllers/api/ccmenu_controller_test.rb +1 -1
  62. data/test/controllers/api/deploys_controller_test.rb +17 -0
  63. data/test/controllers/api/stacks_controller_test.rb +21 -7
  64. data/test/controllers/webhooks_controller_test.rb +26 -11
  65. data/test/dummy/app/assets/config/manifest.js +3 -0
  66. data/test/dummy/config/application.rb +1 -1
  67. data/test/dummy/config/database.yml +9 -0
  68. data/test/dummy/config/environments/development.rb +1 -1
  69. data/test/dummy/config/secrets_double_github_app.yml +79 -0
  70. data/test/dummy/db/schema.rb +5 -4
  71. data/test/dummy/db/seeds.rb +1 -0
  72. data/test/fixtures/payloads/check_suite_master.json +2 -30
  73. data/test/fixtures/payloads/push_master.json +1 -1
  74. data/test/fixtures/payloads/push_not_master.json +1 -1
  75. data/test/fixtures/shipit/commits.yml +2 -2
  76. data/test/fixtures/shipit/hooks.yml +1 -0
  77. data/test/fixtures/shipit/tasks.yml +1 -1
  78. data/test/helpers/json_helper.rb +5 -1
  79. data/test/jobs/github_sync_job_test.rb +2 -1
  80. data/test/models/commit_deployment_status_test.rb +3 -3
  81. data/test/models/commits_test.rb +2 -0
  82. data/test/models/deploy_spec_test.rb +7 -0
  83. data/test/models/deploys_test.rb +18 -0
  84. data/test/models/hook_test.rb +30 -1
  85. data/test/models/merge_request_test.rb +19 -4
  86. data/test/models/shipit/check_run_test.rb +124 -5
  87. data/test/models/shipit/review_stack_test.rb +38 -6
  88. data/test/models/shipit/stacks_test.rb +42 -4
  89. data/test/models/shipit/webhooks/handlers/pull_request/review_stack_adapter_test.rb +24 -0
  90. data/test/models/tasks_test.rb +22 -0
  91. data/test/test_helper.rb +15 -0
  92. data/test/unit/anonymous_user_serializer_test.rb +1 -1
  93. data/test/unit/command_test.rb +5 -0
  94. data/test/unit/commit_serializer_test.rb +1 -1
  95. data/test/unit/deploy_commands_test.rb +70 -14
  96. data/test/unit/deploy_serializer_test.rb +1 -1
  97. data/test/unit/github_app_test.rb +2 -3
  98. data/test/unit/github_apps_test.rb +416 -0
  99. data/test/unit/shipit_deployment_checks_test.rb +77 -0
  100. data/test/unit/shipit_test.rb +14 -0
  101. data/test/unit/user_serializer_test.rb +1 -1
  102. metadata +202 -191
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 47bb069ae71eaf994a57ee8dbe3a409adf62ede12fbb010b18ffb9056cee9e0e
4
- data.tar.gz: 2e8399c7f72ed1308de6b0be4715579bb6732f3759b22eb38e2e750bb84439de
3
+ metadata.gz: e3fd7ab372e13432986f4bd927df32b97c0d4b969193035d9b34fbb0ce80630d
4
+ data.tar.gz: 5ac2897e8354b9fbae1f37ab192f2eca26cd4160169295a0ac6706e0b023affe
5
5
  SHA512:
6
- metadata.gz: a0a8986aae58f932aca14da3213df881dabfa1017aa844bfe3f5a61afcabc2f09032eafe4342d8acdb7d4fc50cfe4ec9ad1f05dba9209757ef95cc6aa8c8a142
7
- data.tar.gz: 0722dfd987d98c176b4625e23921c5576b1a40e85ed6e4d18208c4a4eff4b8c45ba314055dee3255feb576748431be638e6eb97fda6935c6953b70bfe6f14048
6
+ metadata.gz: ba96ab58f4a67a0658f02bf7844c8a47bf65526bd4dc4d37560a4bab5a9606a12fde8204cbe4f8829c51578bbd815f99e73ca3e3b81559a9935f7c4e4c45da57
7
+ data.tar.gz: c20e5c8d2a9ff71c70e332760d46e1e9985624411828f39af00754de2dcf50beec0109b22fc48f8669811c2248f52781638a529f8bc5e5083dff41bc54d9266c
data/README.md CHANGED
@@ -12,7 +12,7 @@ Shipit is compatible with just about anything that you can deploy using a script
12
12
 
13
13
  This guide aims to help you [set up](#installation-and-setup), [use](#using-shipit), and [understand](#reference) Shipit.
14
14
 
15
- *Shipit requires a database (MySQL, PostgreSQL or SQLite3), redis, and Ruby 2.1 or superior.*
15
+ *Shipit requires a database (MySQL, PostgreSQL or SQLite3), redis, and Ruby 2.6 or superior.*
16
16
 
17
17
  * * *
18
18
  <h2 id="toc">Table of contents</h2>
@@ -270,7 +270,9 @@ deploy:
270
270
  ```
271
271
  <br>
272
272
 
273
- **<code>deploy.max_commits</code>** defines the maximum number of commits that should be shipped per deploys. Defaults to `8`.
273
+ **<code>deploy.max_commits</code>** defines the maximum number of commits that should be shipped per deploy. Defaults to `8` if no value is provided.
274
+
275
+ To disable this limit, you can use use an explicit null value: `max_commits: null`. Continuous Delivery will then deploy any number of commits.
274
276
 
275
277
  Human users will be warned that they are not respecting the recommendation, but allowed to continue.
276
278
  However continuous delivery will respect this limit. If there is no deployable commits in this range, a human intervention will be required.
@@ -292,6 +294,15 @@ deploy:
292
294
  interval: 5m
293
295
  ```
294
296
 
297
+ **<code>deploy.retries</code>** enables retries for a stack, and defines the maximum amount of times that Shipit will retry a deploy that finished with a `failed`, `error` or `timedout` status.
298
+
299
+ For example, this will retry a deploy twice if it fails.
300
+
301
+ ```yaml
302
+ deploy:
303
+ retries: 2
304
+ ```
305
+
295
306
  **<code>rollback.override</code>** contains an array of the shell commands required to rollback the application to a previous state. Shipit will try to infer it from the repository structure, but you can change the default inference. This key defaults to `disabled` unless Capistrano is detected.
296
307
 
297
308
  For example:
@@ -196,8 +196,6 @@
196
196
  width: 100%;
197
197
  overflow-y: auto;
198
198
  overflow-x: hidden;
199
- padding-right: 20px;
200
- padding-left: 15px;
201
199
  }
202
200
 
203
201
  .commit-checks {
@@ -20,7 +20,7 @@ module Shipit
20
20
 
21
21
  def show
22
22
  latest_deploy = stack.deploys_and_rollbacks.last || NoDeploy.new
23
- render('shipit/ccmenu/project.xml.builder', formats: [:xml], locals: { stack: stack, deploy: latest_deploy })
23
+ render('shipit/ccmenu/project', formats: [:xml], locals: { stack: stack, deploy: latest_deploy })
24
24
  end
25
25
 
26
26
  private
@@ -11,11 +11,13 @@ module Shipit
11
11
  params do
12
12
  requires :sha, String, length: { in: 6..40 }
13
13
  accepts :force, Boolean, default: false
14
+ accepts :require_ci, Boolean, default: false
14
15
  accepts :env, Hash, default: {}
15
16
  end
16
17
  def create
17
18
  commit = stack.commits.by_sha(params.sha) || param_error!(:sha, 'Unknown revision')
18
19
  param_error!(:force, "Can't deploy a locked stack") if !params.force && stack.locked?
20
+ param_error!(:require_ci, "Commit is not deployable") if params.require_ci && !commit.deployable?
19
21
  deploy = stack.trigger_deploy(commit, current_user, env: params.env, force: params.force)
20
22
  render_resource(deploy, status: :accepted)
21
23
  end
@@ -8,6 +8,7 @@ module Shipit
8
8
  requires :sha, String, length: { in: 6..40 }
9
9
  accepts :force, Boolean, default: false
10
10
  accepts :env, Hash, default: {}
11
+ accepts :lock, Boolean, default: true
11
12
  end
12
13
  def create
13
14
  commit = stack.commits.by_sha(params.sha) || param_error!(:sha, 'Unknown revision')
@@ -23,7 +24,7 @@ module Shipit
23
24
  active_task.abort!(aborted_by: current_user, rollback_once_aborted_to: deploy)
24
25
  response = active_task
25
26
  else
26
- response = deploy.trigger_rollback(current_user, env: deploy_env, force: params.force)
27
+ response = deploy.trigger_rollback(current_user, env: deploy_env, force: params.force, lock: params.lock)
27
28
  end
28
29
 
29
30
  render_resource(response, status: :accepted)
@@ -40,6 +40,7 @@ module Shipit
40
40
  end
41
41
 
42
42
  params do
43
+ accepts :branch, String
43
44
  accepts :deploy_url, String
44
45
  accepts :ignore_ci, Boolean
45
46
  accepts :merge_queue_enabled, Boolean
@@ -55,7 +55,7 @@ module Shipit
55
55
  end
56
56
 
57
57
  def load_stack
58
- @stack ||= Stack.from_param!(params[:stack_id]).becomes(Stack)
58
+ @stack ||= Stack.from_param!(params[:stack_id])
59
59
  end
60
60
 
61
61
  def load_until_commit
@@ -154,7 +154,7 @@ module Shipit
154
154
  end
155
155
 
156
156
  def create_params
157
- params.require(:stack).permit(:environment, :branch, :deploy_url, :ignore_ci)
157
+ params.require(:stack).permit(:repo_owner, :repo_name, :environment, :branch, :deploy_url, :ignore_ci)
158
158
  end
159
159
 
160
160
  def update_params
@@ -180,7 +180,7 @@ module Shipit
180
180
  end
181
181
 
182
182
  def repository_params
183
- params.require(:stack).permit(:repo_owner, :repo_name)
183
+ params.require(:stack).permit(:repo_owner, :repo_name, :branch, :environment, :deploy_url, :ignore_ci)
184
184
  end
185
185
  end
186
186
  end
@@ -62,7 +62,7 @@ module Shipit
62
62
  def url_for_task
63
63
  base_task = @task.is_a?(Deploy) ? @task.becomes(Deploy) : @task
64
64
 
65
- url_for([base_task.stack.becomes(Stack), base_task])
65
+ url_for([base_task.stack, base_task])
66
66
  end
67
67
 
68
68
  def task
@@ -70,7 +70,7 @@ module Shipit
70
70
  end
71
71
 
72
72
  def stack
73
- @stack ||= Stack.from_param!(params[:stack_id]).becomes(Stack)
73
+ @stack ||= Stack.from_param!(params[:stack_id])
74
74
  end
75
75
 
76
76
  def task_params
@@ -2,7 +2,7 @@
2
2
  module Shipit
3
3
  class WebhooksController < ActionController::Base
4
4
  skip_before_action :verify_authenticity_token, raise: false
5
- before_action :check_if_ping, :verify_signature
5
+ before_action :check_if_ping, :drop_unhandled_event, :verify_signature
6
6
 
7
7
  respond_to :json
8
8
 
@@ -15,8 +15,26 @@ module Shipit
15
15
 
16
16
  private
17
17
 
18
+ def drop_unhandled_event
19
+ # Acknowledge, but do nothing
20
+ head(204) unless Shipit::Webhooks.for_event(event).present?
21
+ end
22
+
18
23
  def verify_signature
19
- head(422) unless Shipit.github.verify_webhook_signature(request.headers['X-Hub-Signature'], request.raw_post)
24
+ github_app = Shipit.github(organization: repository_owner)
25
+ verified = github_app.verify_webhook_signature(
26
+ request.headers['X-Hub-Signature'],
27
+ request.raw_post
28
+ )
29
+ head(422) unless verified
30
+
31
+ Rails.logger.info([
32
+ 'WebhookController#verify_signature',
33
+ "event=#{event}",
34
+ "repository_owner=#{repository_owner}",
35
+ "signature=#{request.headers['X-Hub-Signature']}",
36
+ "status=#{status}",
37
+ ].join(' '))
20
38
  end
21
39
 
22
40
  def check_if_ping
@@ -27,8 +45,9 @@ module Shipit
27
45
  request.headers.fetch('X-Github-Event')
28
46
  end
29
47
 
30
- def stack
31
- @stack ||= Stack.find(params[:stack_id])
48
+ def repository_owner
49
+ # Fallback to the organization sub-object if repository isn't included in the payload
50
+ params.dig('repository', 'owner', 'login') || params.dig('organization', 'login')
32
51
  end
33
52
  end
34
53
  end
@@ -43,7 +43,6 @@ module Shipit
43
43
  end
44
44
 
45
45
  def missing_github_app_message
46
- # TODO: Document how to create an app
47
46
  <<-MESSAGE.html_safe
48
47
  Shipit requires a GitHub App to authenticate users and perform API calls.
49
48
  MESSAGE
@@ -4,7 +4,7 @@ module Shipit
4
4
  queue_as :hooks
5
5
 
6
6
  def perform(delivery)
7
- delivery = Hook::DeliverySpec.new(delivery) if delivery.is_a?(Hash)
7
+ delivery = Hook::DeliverySpec.new(**delivery) if delivery.is_a?(Hash)
8
8
  delivery.send!
9
9
  end
10
10
  end
@@ -3,8 +3,11 @@ module Shipit
3
3
  class GithubSyncJob < BackgroundJob
4
4
  include BackgroundJob::Unique
5
5
 
6
+ attr_reader :stack
7
+
6
8
  MAX_FETCHED_COMMITS = 25
7
9
  queue_as :default
10
+ on_duplicate :drop
8
11
 
9
12
  self.timeout = 60
10
13
  self.lock_timeout = 20
@@ -13,26 +16,27 @@ module Shipit
13
16
  @stack = Stack.find(params[:stack_id])
14
17
 
15
18
  handle_github_errors do
16
- new_commits, shared_parent = fetch_missing_commits { @stack.github_commits }
19
+ new_commits, shared_parent = fetch_missing_commits { stack.github_commits }
17
20
 
18
- @stack.transaction do
21
+ stack.transaction do
19
22
  shared_parent&.detach_children!
20
23
  appended_commits = new_commits.map do |gh_commit|
21
24
  append_commit(gh_commit)
22
25
  end
23
- @stack.lock_reverted_commits! if appended_commits.any?(&:revert?)
26
+ stack.lock_reverted_commits! if appended_commits.any?(&:revert?)
24
27
  end
25
28
  end
26
- CacheDeploySpecJob.perform_later(@stack)
29
+ CacheDeploySpecJob.perform_later(stack)
27
30
  end
28
31
 
29
32
  def append_commit(gh_commit)
30
- @stack.commits.create_from_github!(gh_commit)
33
+ stack.commits.create_from_github!(gh_commit)
31
34
  end
32
35
 
33
36
  def fetch_missing_commits(&block)
34
37
  commits = []
35
- iterator = Shipit::FirstParentCommitsIterator.new(&block)
38
+ github_api = stack&.github_api
39
+ iterator = Shipit::FirstParentCommitsIterator.new(github_api: github_api, &block)
36
40
  iterator.each_with_index do |commit, index|
37
41
  break if index >= MAX_FETCHED_COMMITS
38
42
 
@@ -49,13 +53,13 @@ module Shipit
49
53
  def handle_github_errors
50
54
  yield
51
55
  rescue Octokit::NotFound
52
- @stack.mark_as_inaccessible!
56
+ stack.mark_as_inaccessible!
53
57
  else
54
- @stack.mark_as_accessible!
58
+ stack.mark_as_accessible!
55
59
  end
56
60
 
57
61
  def lookup_commit(sha)
58
- @stack.commits.find_by(sha: sha)
62
+ stack.commits.find_by(sha: sha)
59
63
  end
60
64
  end
61
65
  end
@@ -13,7 +13,7 @@ module Shipit
13
13
 
14
14
  environment = stack.environment
15
15
  stack_ref = create_full_ref(environment)
16
- client = Shipit.github.api
16
+ client = stack.github_api
17
17
 
18
18
  full_repo_name = stack.github_repo_name
19
19
 
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
  module Shipit
3
3
  class AnonymousUser
4
- def present?
5
- false
4
+ def blank?
5
+ true
6
6
  end
7
7
 
8
8
  def email
@@ -63,5 +63,9 @@ module Shipit
63
63
  def serializer_class
64
64
  AnonymousUserSerializer
65
65
  end
66
+
67
+ def marked_for_destruction?
68
+ true
69
+ end
66
70
  end
67
71
  end
@@ -5,6 +5,8 @@ module Shipit
5
5
  include DeferredTouch
6
6
  include Status::Common
7
7
 
8
+ CHECK_RUN_REFRESH_DELAY = 5.seconds
9
+
8
10
  belongs_to :stack, required: true
9
11
  belongs_to :commit, required: true
10
12
 
@@ -19,11 +21,30 @@ module Shipit
19
21
  create!(selector.merge(attributes))
20
22
  rescue ActiveRecord::RecordNotUnique
21
23
  record = find_by!(selector)
24
+
25
+ # Checkruns can jump between states and conclusions, and the github timestamps are low precision and unreliable.
26
+ # Since there's a conflict and the webhook seems older, enqueue a refresh.
27
+ # Persist the received data anyways, in case it is now the canonical data on GitHub despite the timestamp.
28
+ if attributes[:conclusion] != record.conclusion && record.newer_than_webhook?(attributes)
29
+ Rails.logger.warn(
30
+ "Conflicting stale checkrun received. Checkrun id: #{selector[:github_id]}, Details: #{attributes}"
31
+ )
32
+ RefreshCheckRunsJob.set(wait: CHECK_RUN_REFRESH_DELAY).perform_later(commit_id: record.commit_id)
33
+ end
34
+
22
35
  record.update!(attributes)
23
36
  record
24
37
  end
25
38
 
26
39
  def create_or_update_from_github!(stack_id, github_check_run)
40
+ checkrun_date = parse_newest_date(github_check_run)
41
+
42
+ unless checkrun_date
43
+ Rails.logger.warn("No valid timestamp found in checkrun data. Checkrun id: #{github_check_run.id}.")
44
+ RefreshCheckRunsJob.set(wait: CHECK_RUN_REFRESH_DELAY).perform_later(stack_id: stack_id)
45
+ return
46
+ end
47
+
27
48
  create_or_update_by!(
28
49
  selector: {
29
50
  github_id: github_check_run.id,
@@ -35,9 +56,20 @@ module Shipit
35
56
  title: github_check_run.output.title.to_s.truncate(1_000),
36
57
  details_url: github_check_run.details_url,
37
58
  html_url: github_check_run.html_url,
59
+ github_updated_at: checkrun_date,
38
60
  },
39
61
  )
40
62
  end
63
+
64
+ def parse_newest_date(github_check_run)
65
+ started_at = github_check_run.started_at
66
+ completed_at = github_check_run.completed_at
67
+
68
+ started_at_date = Time.parse(started_at.to_s) if started_at
69
+ completed_at_date = Time.parse(completed_at.to_s) if completed_at
70
+
71
+ [started_at_date, completed_at_date].compact.max
72
+ end
41
73
  end
42
74
 
43
75
  def state
@@ -71,6 +103,10 @@ module Shipit
71
103
  'shipit/statuses/status'
72
104
  end
73
105
 
106
+ def newer_than_webhook?(webhook_attributes)
107
+ github_updated_at && github_updated_at >= webhook_attributes[:github_updated_at]
108
+ end
109
+
74
110
  private
75
111
 
76
112
  def enable_ci_on_stack
@@ -8,7 +8,6 @@ module Shipit
8
8
  AmbiguousRevision = Class.new(StandardError)
9
9
 
10
10
  belongs_to :stack
11
- has_many :deploys
12
11
  has_many :statuses, -> { order(created_at: :desc) }, dependent: :destroy, inverse_of: :commit
13
12
  has_many :check_runs, -> { order(created_at: :desc) }, dependent: :destroy, inverse_of: :commit
14
13
  has_many :commit_deployments, dependent: :destroy
@@ -22,28 +21,40 @@ module Shipit
22
21
  after_create { stack.update_undeployed_commits_count }
23
22
 
24
23
  after_commit :schedule_refresh_statuses!, :schedule_refresh_check_runs!, :schedule_fetch_stats!,
25
- :schedule_continuous_delivery, on: :create
24
+ :schedule_continuous_delivery, on: :create
26
25
 
27
- belongs_to :author, class_name: 'User', inverse_of: :authored_commits
28
- belongs_to :committer, class_name: 'User', inverse_of: :commits
29
- belongs_to :lock_author, class_name: :User, optional: true, inverse_of: false
26
+ belongs_to :author, class_name: 'User', optional: true, inverse_of: :authored_commits
27
+ belongs_to :committer, class_name: 'User', optional: true, inverse_of: :commits
28
+ belongs_to :lock_author, class_name: 'User', optional: true, inverse_of: false
30
29
 
31
30
  def author
32
31
  super || AnonymousUser.new
33
32
  end
34
33
 
34
+ def author=(user)
35
+ super(user.presence)
36
+ end
37
+
35
38
  def committer
36
39
  super || AnonymousUser.new
37
40
  end
38
41
 
42
+ def committer=(user)
43
+ super(user.presence)
44
+ end
45
+
39
46
  def lock_author
40
47
  super || AnonymousUser.new
41
48
  end
42
49
 
50
+ def lock_author=(user)
51
+ super(user.presence)
52
+ end
53
+
43
54
  scope :reachable, -> { where(detached: false) }
44
55
 
45
56
  delegate :broadcast_update, :github_repo_name, :hidden_statuses, :required_statuses, :blocking_statuses,
46
- :soft_failing_statuses, to: :stack
57
+ :soft_failing_statuses, to: :stack
47
58
 
48
59
  def self.newer_than(commit)
49
60
  return all unless commit
@@ -144,7 +155,7 @@ module Shipit
144
155
 
145
156
  def refresh_statuses!
146
157
  github_statuses = stack.handle_github_redirections do
147
- Shipit.github.api.statuses(github_repo_name, sha, per_page: 100)
158
+ stack.github_api.statuses(github_repo_name, sha, per_page: 100)
148
159
  end
149
160
  github_statuses.each do |status|
150
161
  create_status_from_github!(status)
@@ -159,7 +170,7 @@ module Shipit
159
170
 
160
171
  def refresh_check_runs!
161
172
  response = stack.handle_github_redirections do
162
- Shipit.github.api.check_runs(github_repo_name, sha)
173
+ stack.github_api.check_runs(github_repo_name, sha)
163
174
  end
164
175
  response.check_runs.each do |check_run|
165
176
  create_or_update_check_run_from_github!(check_run)
@@ -261,7 +272,7 @@ module Shipit
261
272
  end
262
273
 
263
274
  def github_commit
264
- @github_commit ||= Shipit.github.api.commit(github_repo_name, sha)
275
+ @github_commit ||= stack.github_api.commit(github_repo_name, sha)
265
276
  end
266
277
 
267
278
  def schedule_fetch_stats!