shipit-engine 0.32.0 → 0.35.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.
Files changed (235) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +13 -2
  3. data/app/assets/images/magic-solid.svg +1 -0
  4. data/app/assets/javascripts/shipit/repositories_search.js.coffee +60 -0
  5. data/app/assets/javascripts/shipit/{search.js.coffee → stack_search.js.coffee} +0 -0
  6. data/app/assets/stylesheets/_pages/_deploy.scss +2 -3
  7. data/app/assets/stylesheets/_pages/_repositories.scss +148 -0
  8. data/app/assets/stylesheets/_pages/_stacks.scss +19 -0
  9. data/app/assets/stylesheets/shipit.scss +1 -0
  10. data/app/controllers/shipit/api/ccmenu_controller.rb +1 -1
  11. data/app/controllers/shipit/api/deploys_controller.rb +2 -0
  12. data/app/controllers/shipit/api/{pull_requests_controller.rb → merge_requests_controller.rb} +8 -8
  13. data/app/controllers/shipit/api/rollbacks_controller.rb +2 -1
  14. data/app/controllers/shipit/api/stacks_controller.rb +15 -1
  15. data/app/controllers/shipit/deploys_controller.rb +1 -1
  16. data/app/controllers/shipit/merge_requests_controller.rb +31 -0
  17. data/app/controllers/shipit/merge_status_controller.rb +15 -15
  18. data/app/controllers/shipit/repositories_controller.rb +74 -0
  19. data/app/controllers/shipit/stacks_controller.rb +2 -2
  20. data/app/controllers/shipit/tasks_controller.rb +2 -2
  21. data/app/controllers/shipit/webhooks_controller.rb +23 -4
  22. data/app/helpers/shipit/chunks_helper.rb +2 -2
  23. data/app/helpers/shipit/github_url_helper.rb +8 -0
  24. data/app/helpers/shipit/shipit_helper.rb +0 -1
  25. data/app/helpers/shipit/stacks_helper.rb +4 -0
  26. data/app/jobs/shipit/create_on_github_job.rb +1 -0
  27. data/app/jobs/shipit/deliver_hook_job.rb +1 -1
  28. data/app/jobs/shipit/destroy_repository_job.rb +24 -0
  29. data/app/jobs/shipit/destroy_stack_job.rb +2 -2
  30. data/app/jobs/shipit/github_sync_job.rb +13 -9
  31. data/app/jobs/shipit/perform_task_job.rb +4 -98
  32. data/app/jobs/shipit/process_merge_requests_job.rb +32 -0
  33. data/app/jobs/shipit/refresh_merge_request_job.rb +11 -0
  34. data/app/jobs/shipit/update_github_last_deployed_ref_job.rb +1 -1
  35. data/app/models/shipit/anonymous_user.rb +10 -2
  36. data/app/models/shipit/check_run.rb +38 -2
  37. data/app/models/shipit/command_line_user.rb +4 -0
  38. data/app/models/shipit/commit.rb +31 -20
  39. data/app/models/shipit/commit_checks.rb +14 -13
  40. data/app/models/shipit/commit_deployment.rb +3 -3
  41. data/app/models/shipit/commit_deployment_status.rb +3 -3
  42. data/app/models/shipit/deploy.rb +17 -11
  43. data/app/models/shipit/deploy_spec/file_system.rb +11 -5
  44. data/app/models/shipit/deploy_spec/lerna_discovery.rb +12 -4
  45. data/app/models/shipit/deploy_spec.rb +16 -4
  46. data/app/models/shipit/duration.rb +2 -0
  47. data/app/models/shipit/hook.rb +28 -2
  48. data/app/models/shipit/merge_request.rb +304 -0
  49. data/app/models/shipit/provisioning_handler/base.rb +30 -0
  50. data/app/models/shipit/provisioning_handler/unregistered_provisioning_handler.rb +35 -0
  51. data/app/models/shipit/provisioning_handler.rb +32 -0
  52. data/app/models/shipit/pull_request.rb +26 -265
  53. data/app/models/shipit/pull_request_assignment.rb +10 -0
  54. data/app/models/shipit/release_status.rb +1 -1
  55. data/app/models/shipit/repository.rb +63 -3
  56. data/app/models/shipit/review_stack.rb +130 -0
  57. data/app/models/shipit/review_stack_provisioning_queue.rb +39 -0
  58. data/app/models/shipit/rollback.rb +5 -0
  59. data/app/models/shipit/stack.rb +78 -30
  60. data/app/models/shipit/status/group.rb +1 -1
  61. data/app/models/shipit/task.rb +62 -9
  62. data/app/models/shipit/task_execution_strategy/base.rb +20 -0
  63. data/app/models/shipit/task_execution_strategy/default.rb +109 -0
  64. data/app/models/shipit/team.rb +4 -2
  65. data/app/models/shipit/user.rb +10 -1
  66. data/app/models/shipit/webhooks/handlers/pull_request/assigned_handler.rb +74 -0
  67. data/app/models/shipit/webhooks/handlers/pull_request/closed_handler.rb +68 -0
  68. data/app/models/shipit/webhooks/handlers/pull_request/edited_handler.rb +74 -0
  69. data/app/models/shipit/webhooks/handlers/pull_request/label_capturing_handler.rb +127 -0
  70. data/app/models/shipit/webhooks/handlers/pull_request/labeled_handler.rb +106 -0
  71. data/app/models/shipit/webhooks/handlers/pull_request/opened_handler.rb +83 -0
  72. data/app/models/shipit/webhooks/handlers/pull_request/reopened_handler.rb +88 -0
  73. data/app/models/shipit/webhooks/handlers/pull_request/review_stack_adapter.rb +103 -0
  74. data/app/models/shipit/webhooks/handlers/pull_request/unlabeled_handler.rb +107 -0
  75. data/app/models/shipit/webhooks/handlers/push_handler.rb +4 -1
  76. data/app/models/shipit/webhooks.rb +10 -0
  77. data/app/serializers/shipit/deploy_serializer.rb +6 -0
  78. data/app/serializers/shipit/merge_request_serializer.rb +21 -0
  79. data/app/serializers/shipit/pull_request_serializer.rb +5 -8
  80. data/app/serializers/shipit/review_stack_serializer.rb +7 -0
  81. data/app/serializers/shipit/stack_serializer.rb +7 -6
  82. data/app/serializers/shipit/tail_task_serializer.rb +10 -2
  83. data/app/serializers/shipit/task_serializer.rb +1 -1
  84. data/app/validators/subset_validator.rb +1 -1
  85. data/app/views/layouts/merge_status.html.erb +1 -1
  86. data/app/views/shipit/merge_requests/_merge_request.html.erb +29 -0
  87. data/app/views/shipit/{pull_requests → merge_requests}/index.html.erb +2 -2
  88. data/app/views/shipit/merge_requests/merge_requests/_pull_request.html.erb +29 -0
  89. data/app/views/shipit/merge_requests/merge_requests/index.html.erb +20 -0
  90. data/app/views/shipit/merge_status/_merge_queue_button.html.erb +3 -3
  91. data/app/views/shipit/merge_status/backlogged.html.erb +1 -1
  92. data/app/views/shipit/merge_status/failure.html.erb +1 -1
  93. data/app/views/shipit/merge_status/locked.html.erb +1 -1
  94. data/app/views/shipit/merge_status/success.html.erb +2 -2
  95. data/app/views/shipit/repositories/_header.html.erb +19 -0
  96. data/app/views/shipit/repositories/index.html.erb +31 -0
  97. data/app/views/shipit/repositories/new.html.erb +23 -0
  98. data/app/views/shipit/repositories/settings.html.erb +53 -0
  99. data/app/views/shipit/repositories/show.html.erb +30 -0
  100. data/app/views/shipit/stacks/_banners.html.erb +15 -1
  101. data/app/views/shipit/stacks/_header.html.erb +5 -2
  102. data/app/views/shipit/stacks/_stack.html.erb +8 -0
  103. data/app/views/shipit/stacks/index.html.erb +2 -1
  104. data/app/views/shipit/stacks/new.html.erb +1 -1
  105. data/app/views/shipit/stacks/settings.html.erb +5 -5
  106. data/app/views/shipit/stacks/show.html.erb +1 -1
  107. data/app/views/shipit/tasks/_task_output.html.erb +1 -1
  108. data/config/routes.rb +15 -5
  109. data/config/secrets.development.example.yml +24 -0
  110. data/config/secrets.development.shopify.yml +20 -9
  111. data/db/migrate/20200706145406_add_review_stacks.rb +12 -0
  112. data/db/migrate/20200804144639_rename_pull_request_to_merge_request.rb +7 -0
  113. data/db/migrate/20200804161512_rename_commits_pull_request_id_to_merge_request_id.rb +5 -0
  114. data/db/migrate/20200813134712_recreate_shipit_pull_requests.rb +22 -0
  115. data/db/migrate/20200813194056_create_pull_request_assignments.rb +8 -0
  116. data/db/migrate/20201001125502_add_provision_pr_stacks_flag_to_repositories.rb +7 -0
  117. data/db/migrate/20201008145809_add_retry_attempt_to_tasks.rb +5 -0
  118. data/db/migrate/20201008152744_add_max_retries_to_tasks.rb +5 -0
  119. data/db/migrate/20210325194053_remove_stacks_branch_default.rb +5 -0
  120. data/db/migrate/20210504200438_add_github_updated_at_to_check_runs.rb +5 -0
  121. data/db/migrate/20210823075617_change_check_runs_github_updated_at_default.rb +5 -0
  122. data/lib/shipit/command.rb +7 -6
  123. data/lib/shipit/commands.rb +18 -5
  124. data/lib/shipit/engine.rb +2 -0
  125. data/lib/shipit/flock.rb +8 -1
  126. data/lib/shipit/github_app.rb +8 -6
  127. data/lib/shipit/octokit_iterator.rb +3 -3
  128. data/lib/shipit/review_stack_commands.rb +8 -0
  129. data/lib/shipit/simple_message_verifier.rb +2 -2
  130. data/lib/shipit/stack_commands.rb +36 -7
  131. data/lib/shipit/task_commands.rb +8 -1
  132. data/lib/shipit/version.rb +1 -1
  133. data/lib/shipit.rb +50 -16
  134. data/lib/snippets/publish-lerna-independent-packages +35 -34
  135. data/lib/snippets/publish-lerna-independent-packages-legacy +39 -0
  136. data/lib/tasks/cron.rake +11 -2
  137. data/test/controllers/api/ccmenu_controller_test.rb +1 -1
  138. data/test/controllers/api/deploys_controller_test.rb +17 -0
  139. data/test/controllers/api/{pull_requests_controller_test.rb → merge_requests_controller_test.rb} +12 -12
  140. data/test/controllers/api/outputs_controller_test.rb +1 -0
  141. data/test/controllers/api/rollback_controller_test.rb +1 -1
  142. data/test/controllers/api/stacks_controller_test.rb +42 -8
  143. data/test/controllers/{pull_requests_controller_test.rb → merge_requests_controller_test.rb} +6 -6
  144. data/test/controllers/repositories_controller_test.rb +71 -0
  145. data/test/controllers/stacks_controller_test.rb +9 -1
  146. data/test/controllers/tasks_controller_test.rb +14 -2
  147. data/test/controllers/webhooks_controller_test.rb +27 -12
  148. data/test/dummy/app/assets/config/manifest.js +3 -0
  149. data/test/dummy/config/application.rb +7 -2
  150. data/test/dummy/config/database.yml +9 -0
  151. data/test/dummy/config/environments/development.rb +1 -4
  152. data/test/dummy/config/environments/test.rb +0 -5
  153. data/test/dummy/config/secrets_double_github_app.yml +79 -0
  154. data/test/dummy/db/schema.rb +56 -17
  155. data/test/dummy/db/seeds.rb +2 -1
  156. data/test/fixtures/payloads/check_suite_master.json +4 -32
  157. data/test/fixtures/payloads/invalid_pull_request.json +117 -0
  158. data/test/fixtures/payloads/provision_disabled_pull_request.json +454 -0
  159. data/test/fixtures/payloads/pull_request_assigned.json +480 -0
  160. data/test/fixtures/payloads/pull_request_closed.json +454 -0
  161. data/test/fixtures/payloads/pull_request_labeled.json +461 -0
  162. data/test/fixtures/payloads/pull_request_opened.json +454 -0
  163. data/test/fixtures/payloads/pull_request_reopened.json +454 -0
  164. data/test/fixtures/payloads/pull_request_unlabeled.json +454 -0
  165. data/test/fixtures/payloads/pull_request_with_no_repo.json +454 -0
  166. data/test/fixtures/payloads/push_master.json +1 -1
  167. data/test/fixtures/payloads/push_not_master.json +1 -1
  168. data/test/fixtures/shipit/commits.yml +17 -4
  169. data/test/fixtures/shipit/hooks.yml +1 -0
  170. data/test/fixtures/shipit/merge_requests.yml +141 -0
  171. data/test/fixtures/shipit/pull_request_assignments.yml +3 -0
  172. data/test/fixtures/shipit/pull_requests.yml +10 -131
  173. data/test/fixtures/shipit/repositories.yml +1 -0
  174. data/test/fixtures/shipit/stacks.yml +145 -0
  175. data/test/fixtures/shipit/statuses.yml +9 -0
  176. data/test/fixtures/shipit/tasks.yml +4 -1
  177. data/test/fixtures/shipit/users.yml +7 -0
  178. data/test/helpers/json_helper.rb +5 -1
  179. data/test/helpers/payloads_helper.rb +4 -0
  180. data/test/jobs/chunk_rollup_job_test.rb +15 -1
  181. data/test/jobs/destroy_repository_job_test.rb +27 -0
  182. data/test/jobs/github_sync_job_test.rb +2 -1
  183. data/test/jobs/perform_task_job_test.rb +8 -8
  184. data/test/jobs/{merge_pull_requests_job_test.rb → process_merge_requests_job_test.rb} +18 -18
  185. data/test/lib/shipit/deploy_commands_test.rb +16 -0
  186. data/test/lib/shipit/task_commands_test.rb +17 -0
  187. data/test/models/commit_deployment_status_test.rb +3 -3
  188. data/test/models/commits_test.rb +24 -13
  189. data/test/models/deploy_spec_test.rb +64 -24
  190. data/test/models/deploys_test.rb +188 -14
  191. data/test/models/hook_test.rb +30 -1
  192. data/test/models/{pull_request_test.rb → merge_request_test.rb} +49 -34
  193. data/test/models/pull_request_assignment_test.rb +16 -0
  194. data/test/models/shipit/check_run_test.rb +124 -5
  195. data/test/models/shipit/provisioning_handler/base_test.rb +33 -0
  196. data/test/models/shipit/provisioning_handler/unregistered_provisioning_handler_test.rb +49 -0
  197. data/test/models/shipit/provisioning_handler_test.rb +64 -0
  198. data/test/models/shipit/pull_request_test.rb +52 -0
  199. data/test/models/shipit/repository_test.rb +5 -1
  200. data/test/models/shipit/review_stack_provision_status_test.rb +77 -0
  201. data/test/models/shipit/review_stack_provisioning_queue_test.rb +63 -0
  202. data/test/models/shipit/review_stack_test.rb +91 -0
  203. data/test/models/{stacks_test.rb → shipit/stacks_test.rb} +52 -8
  204. data/test/models/shipit/webhooks/handlers/pull_request/assigned_handler_test.rb +45 -0
  205. data/test/models/shipit/webhooks/handlers/pull_request/closed_handler_test.rb +192 -0
  206. data/test/models/shipit/webhooks/handlers/pull_request/edited_handler_test.rb +47 -0
  207. data/test/models/shipit/webhooks/handlers/pull_request/label_capturing_handler_test.rb +209 -0
  208. data/test/models/shipit/webhooks/handlers/pull_request/labeled_handler_test.rb +332 -0
  209. data/test/models/shipit/webhooks/handlers/pull_request/opened_handler_test.rb +238 -0
  210. data/test/models/shipit/webhooks/handlers/pull_request/reopened_handler_test.rb +282 -0
  211. data/test/models/shipit/webhooks/handlers/pull_request/review_stack_adapter_test.rb +107 -0
  212. data/test/models/shipit/webhooks/handlers/pull_request/unlabeled_handler_test.rb +324 -0
  213. data/test/models/shipit/{wehbooks → webhooks}/handlers_test.rb +0 -0
  214. data/test/models/tasks_test.rb +66 -3
  215. data/test/serializers/shipit/pull_request_serializer_test.rb +29 -0
  216. data/test/test_helper.rb +15 -0
  217. data/test/unit/anonymous_user_serializer_test.rb +1 -1
  218. data/test/unit/command_test.rb +8 -3
  219. data/test/unit/commit_serializer_test.rb +1 -1
  220. data/test/unit/deploy_commands_test.rb +73 -17
  221. data/test/unit/deploy_serializer_test.rb +1 -1
  222. data/test/unit/github_app_test.rb +2 -3
  223. data/test/unit/github_apps_test.rb +416 -0
  224. data/test/unit/github_url_helper_test.rb +5 -0
  225. data/test/unit/shipit_deployment_checks_test.rb +77 -0
  226. data/test/unit/shipit_task_execution_strategy_test.rb +47 -0
  227. data/test/unit/shipit_test.rb +14 -0
  228. data/test/unit/user_serializer_test.rb +1 -1
  229. metadata +306 -188
  230. data/app/controllers/shipit/pull_requests_controller.rb +0 -31
  231. data/app/jobs/shipit/merge_pull_requests_job.rb +0 -32
  232. data/app/jobs/shipit/refresh_pull_request_job.rb +0 -11
  233. data/app/views/shipit/pull_requests/_pull_request.html.erb +0 -29
  234. data/test/fixtures/shipit/output_chunks.yml +0 -47
  235. data/test/models/output_chunk_test.rb +0 -21
@@ -4,104 +4,10 @@ module Shipit
4
4
  queue_as :deploys
5
5
 
6
6
  def perform(task)
7
- @task = task
8
- @commands = Commands.for(@task)
9
- unless @task.pending?
10
- logger.error("Task ##{@task.id} already in `#{@task.status}` state. Aborting.")
11
- return
12
- end
13
- run
14
- ensure
15
- @commands.clear_working_directory
16
- end
17
-
18
- def run
19
- @task.ping
20
- @task.run!
21
- checkout_repository
22
- perform_task
23
- @task.write("\nCompleted successfully\n")
24
- @task.report_complete!
25
- rescue Command::TimedOut => error
26
- @task.write("\n#{error.message}\n")
27
- @task.report_timeout!(error)
28
- rescue Command::Error => error
29
- @task.write("\n#{error.message}\n")
30
- @task.report_failure!(error)
31
- rescue StandardError => error
32
- @task.report_error!(error)
33
- rescue Exception => error
34
- @task.report_error!(error)
35
- raise
36
- end
37
-
38
- def abort!(signal: 'TERM')
39
- pid = @task.pid
40
- if pid
41
- @task.write("$ kill #{pid}\n")
42
- Process.kill(signal, pid)
43
- else
44
- @task.write("Can't abort, no recorded pid, WTF?\n")
45
- end
46
- rescue SystemCallError => error
47
- @task.write("kill: (#{pid}) - #{error.message}\n")
48
- end
49
-
50
- def check_for_abort
51
- @task.should_abort? do |times_killed|
52
- if times_killed > 3
53
- abort!(signal: 'KILL')
54
- else
55
- abort!
56
- end
57
- end
58
- end
59
-
60
- def perform_task
61
- capture_all!(@commands.install_dependencies)
62
- capture_all!(@commands.perform)
63
- end
64
-
65
- def checkout_repository
66
- unless @commands.fetched?(@task.until_commit).tap(&:run).success?
67
- # acquire_git_cache_lock can take upto 15 seconds
68
- # to process. Try to make sure that the job isn't
69
- # marked dead while we attempt to acquire the lock.
70
- @task.ping
71
- @task.acquire_git_cache_lock do
72
- @task.ping
73
- unless @commands.fetched?(@task.until_commit).tap(&:run).success?
74
- capture!(@commands.fetch)
75
- end
76
- end
77
- end
78
- capture_all!(@commands.clone)
79
- capture!(@commands.checkout(@task.until_commit))
80
- end
81
-
82
- def capture_all!(commands)
83
- commands.map { |c| capture!(c) }
84
- end
85
-
86
- def capture!(command)
87
- command.start do
88
- @task.ping
89
- check_for_abort
90
- end
91
- @task.write("$ #{command}\npid: #{command.pid}\n")
92
- @task.pid = command.pid
93
- command.stream! do |line|
94
- @task.write(line)
95
- end
96
- @task.write("\n")
97
- command.success?
98
- end
99
-
100
- def capture(command)
101
- capture!(command)
102
- command.success?
103
- rescue Command::Error
104
- false
7
+ Shipit
8
+ .task_execution_strategy
9
+ .new(task)
10
+ .execute
105
11
  end
106
12
  end
107
13
  end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+ module Shipit
3
+ class ProcessMergeRequestsJob < BackgroundJob
4
+ include BackgroundJob::Unique
5
+ on_duplicate :drop
6
+
7
+ queue_as :default
8
+
9
+ def perform(stack)
10
+ merge_requests = stack.merge_requests.to_be_merged.to_a
11
+ merge_requests.each do |merge_request|
12
+ merge_request.refresh!
13
+ merge_request.reject_unless_mergeable!
14
+ merge_request.cancel! if merge_request.closed?
15
+ merge_request.revalidate! if merge_request.need_revalidation?
16
+ end
17
+
18
+ return false unless stack.allows_merges?
19
+
20
+ merge_requests.select(&:pending?).each do |merge_request|
21
+ merge_request.refresh!
22
+ next unless merge_request.all_status_checks_passed?
23
+ begin
24
+ merge_request.merge!
25
+ rescue MergeRequest::NotReady
26
+ ProcessMergeRequestsJob.set(wait: 10.seconds).perform_later(stack)
27
+ return false
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+ module Shipit
3
+ class RefreshMergeRequestJob < BackgroundJob
4
+ queue_as :default
5
+
6
+ def perform(merge_request)
7
+ merge_request.refresh!
8
+ ProcessMergeRequestsJob.perform_later(merge_request.stack)
9
+ end
10
+ end
11
+ 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
@@ -35,6 +35,10 @@ module Shipit
35
35
  Shipit.authentication_disabled?
36
36
  end
37
37
 
38
+ def repositories_contributed_to
39
+ []
40
+ end
41
+
38
42
  def stacks_contributed_to
39
43
  []
40
44
  end
@@ -59,5 +63,9 @@ module Shipit
59
63
  def serializer_class
60
64
  AnonymousUserSerializer
61
65
  end
66
+
67
+ def marked_for_destruction?
68
+ true
69
+ end
62
70
  end
63
71
  end
@@ -1,10 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
  module Shipit
3
3
  class CheckRun < ApplicationRecord
4
- CONCLUSIONS = %w(success failure neutral cancelled timed_out action_required stale).freeze
4
+ CONCLUSIONS = %w(success failure neutral cancelled timed_out action_required stale skipped).freeze
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,16 +56,27 @@ 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
44
76
  case conclusion
45
77
  when nil, 'action_required'
46
78
  'pending'
47
- when 'success', 'neutral'
79
+ when 'success', 'neutral', 'skipped'
48
80
  'success'
49
81
  when 'failure', 'cancelled', 'stale'
50
82
  'failure'
@@ -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
@@ -35,6 +35,10 @@ module Shipit
35
35
  Shipit.authentication_disabled?
36
36
  end
37
37
 
38
+ def repositories_contributed_to
39
+ []
40
+ end
41
+
38
42
  def stacks_contributed_to
39
43
  []
40
44
  end
@@ -8,42 +8,53 @@ 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
15
14
  has_many :release_statuses, dependent: :destroy
16
- belongs_to :pull_request, inverse_of: :merge_commit, optional: true
15
+ belongs_to :merge_request, inverse_of: :merge_commit, optional: true
17
16
 
18
17
  deferred_touch stack: :updated_at
19
18
 
20
- before_create :identify_pull_request
19
+ before_create :identify_merge_request
21
20
  after_commit { broadcast_update }
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
@@ -113,7 +124,7 @@ module Shipit
113
124
 
114
125
  def message=(message)
115
126
  limit = self.class.columns_hash['message'].limit
116
- if limit && message && message.size > limit
127
+ if limit && message && message.bytesize > limit
117
128
  message = message.truncate_bytes(limit)
118
129
  end
119
130
  super(message)
@@ -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!
@@ -287,13 +298,13 @@ module Shipit
287
298
  stack.deploys.unsuccessful.where(until_commit_id: id).any?
288
299
  end
289
300
 
290
- def identify_pull_request
301
+ def identify_merge_request
291
302
  return unless message_parser.pull_request?
292
- if pull_request = stack.pull_requests.find_by(number: message_parser.pull_request_number)
293
- self.pull_request = pull_request
294
- self.pull_request_number = pull_request.number
295
- self.pull_request_title = pull_request.title
296
- self.author = pull_request.merge_requested_by if pull_request.merge_requested_by
303
+ if merge_request = stack.merge_requests.find_by(number: message_parser.pull_request_number)
304
+ self.merge_request = merge_request
305
+ self.pull_request_number = merge_request.number
306
+ self.pull_request_title = merge_request.title
307
+ self.author = merge_request.merge_requested_by if merge_request.merge_requested_by
297
308
  end
298
309
 
299
310
  self.pull_request_number = message_parser.pull_request_number unless self[:pull_request_number]
@@ -301,8 +312,8 @@ module Shipit
301
312
  end
302
313
 
303
314
  def deploy_requested_at
304
- if pull_request&.merged?
305
- pull_request.merge_requested_at
315
+ if merge_request&.merged?
316
+ merge_request.merge_requested_at
306
317
  else
307
318
  created_at
308
319
  end
@@ -6,17 +6,18 @@ module Shipit
6
6
 
7
7
  def initialize(commit)
8
8
  @commit = commit
9
+ super(commit)
9
10
  end
10
11
 
11
12
  def synchronize(&block)
12
- @lock ||= Redis::Lock.new('lock', redis, expiration: 1, timeout: 2)
13
+ @lock ||= Redis::Lock.new(key('lock'), Shipit.redis, expiration: 1, timeout: 2)
13
14
  @lock.lock(&block)
14
15
  end
15
16
 
16
17
  def schedule
17
- return false if redis.get('status').present?
18
+ return false if Shipit.redis.get(key('status')).present?
18
19
  synchronize do
19
- return false if redis.get('status').present?
20
+ return false if Shipit.redis.get(key('status')).present?
20
21
 
21
22
  initialize_redis_state
22
23
  end
@@ -25,34 +26,34 @@ module Shipit
25
26
  end
26
27
 
27
28
  def initialize_redis_state
28
- redis.pipelined do
29
- redis.set('output', '', ex: OUTPUT_TTL)
30
- redis.set('status', 'scheduled', ex: OUTPUT_TTL)
31
- end
29
+ Shipit.redis.set(key('status'), 'scheduled', ex: OUTPUT_TTL)
32
30
  @status = 'scheduled'
33
31
  end
34
32
 
35
33
  def status
36
- @status ||= redis.get('status')
34
+ @status ||= Shipit.redis.get(key('status'))
37
35
  end
38
36
 
39
37
  def status=(status)
40
- redis.set('status', status)
38
+ Shipit.redis.set(key('status'), status)
41
39
  @status = status
42
40
  end
43
41
 
44
42
  def output(since: 0)
45
- redis.getrange('output', since, -1)
43
+ Shipit.redis.getrange(key('output'), since, -1)
46
44
  end
47
45
 
48
46
  def write(output)
49
- redis.append('output', output)
47
+ Shipit.redis.pipelined do
48
+ Shipit.redis.append(key('output'), output)
49
+ Shipit.redis.expire(key('output'), OUTPUT_TTL)
50
+ end
50
51
  end
51
52
 
52
53
  private
53
54
 
54
- def redis
55
- @redis ||= Shipit.redis("commit:#{commit.id}:checks")
55
+ def key(key)
56
+ "commit:#{commit.id}:checks:#{key}"
56
57
  end
57
58
  end
58
59
  end