shipit-engine 0.31.0 → 0.35.0

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 (411) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +17 -4
  3. data/Rakefile +4 -2
  4. data/app/assets/images/magic-solid.svg +1 -0
  5. data/app/assets/javascripts/shipit/repositories_search.js.coffee +60 -0
  6. data/app/assets/javascripts/shipit/{search.js.coffee → stack_search.js.coffee} +0 -0
  7. data/app/assets/stylesheets/_pages/_deploy.scss +2 -3
  8. data/app/assets/stylesheets/_pages/_repositories.scss +148 -0
  9. data/app/assets/stylesheets/_pages/_stacks.scss +19 -3
  10. data/app/assets/stylesheets/merge_status.scss +0 -3
  11. data/app/assets/stylesheets/shipit.scss +1 -0
  12. data/app/controllers/concerns/shipit/active_model_serializers_patch.rb +1 -0
  13. data/app/controllers/concerns/shipit/api/cacheable.rb +1 -0
  14. data/app/controllers/concerns/shipit/api/paginable.rb +3 -2
  15. data/app/controllers/concerns/shipit/api/rendering.rb +5 -4
  16. data/app/controllers/concerns/shipit/authentication.rb +3 -2
  17. data/app/controllers/concerns/shipit/pagination.rb +2 -1
  18. data/app/controllers/shipit/api/base_controller.rb +11 -6
  19. data/app/controllers/shipit/api/ccmenu_controller.rb +2 -1
  20. data/app/controllers/shipit/api/commits_controller.rb +2 -1
  21. data/app/controllers/shipit/api/deploys_controller.rb +6 -3
  22. data/app/controllers/shipit/api/hooks_controller.rb +6 -5
  23. data/app/controllers/shipit/api/locks_controller.rb +5 -4
  24. data/app/controllers/shipit/api/merge_requests_controller.rb +37 -0
  25. data/app/controllers/shipit/api/outputs_controller.rb +2 -1
  26. data/app/controllers/shipit/api/release_statuses_controller.rb +3 -2
  27. data/app/controllers/shipit/api/rollbacks_controller.rb +34 -0
  28. data/app/controllers/shipit/api/stacks_controller.rb +32 -5
  29. data/app/controllers/shipit/api/tasks_controller.rb +6 -5
  30. data/app/controllers/shipit/api_clients_controller.rb +4 -3
  31. data/app/controllers/shipit/ccmenu_url_controller.rb +4 -3
  32. data/app/controllers/shipit/commit_checks_controller.rb +2 -1
  33. data/app/controllers/shipit/commits_controller.rb +2 -1
  34. data/app/controllers/shipit/deploys_controller.rb +4 -3
  35. data/app/controllers/shipit/github_authentication_controller.rb +4 -3
  36. data/app/controllers/shipit/merge_requests_controller.rb +31 -0
  37. data/app/controllers/shipit/merge_status_controller.rb +31 -30
  38. data/app/controllers/shipit/release_statuses_controller.rb +3 -2
  39. data/app/controllers/shipit/repositories_controller.rb +74 -0
  40. data/app/controllers/shipit/rollbacks_controller.rb +3 -2
  41. data/app/controllers/shipit/shipit_controller.rb +2 -1
  42. data/app/controllers/shipit/stacks_controller.rb +24 -9
  43. data/app/controllers/shipit/status_controller.rb +2 -1
  44. data/app/controllers/shipit/tasks_controller.rb +7 -6
  45. data/app/controllers/shipit/webhooks_controller.rb +26 -6
  46. data/app/helpers/shipit/chunks_helper.rb +3 -2
  47. data/app/helpers/shipit/deploys_helper.rb +4 -3
  48. data/app/helpers/shipit/github_url_helper.rb +9 -0
  49. data/app/helpers/shipit/merge_status_helper.rb +1 -0
  50. data/app/helpers/shipit/shipit_helper.rb +1 -1
  51. data/app/helpers/shipit/stacks_helper.rb +5 -0
  52. data/app/helpers/shipit/tasks_helper.rb +1 -0
  53. data/app/jobs/shipit/background_job/unique.rb +1 -0
  54. data/app/jobs/shipit/background_job.rb +4 -0
  55. data/app/jobs/shipit/cache_deploy_spec_job.rb +1 -0
  56. data/app/jobs/shipit/chunk_rollup_job.rb +4 -0
  57. data/app/jobs/shipit/clear_git_cache_job.rb +1 -0
  58. data/app/jobs/shipit/continuous_delivery_job.rb +2 -1
  59. data/app/jobs/shipit/create_on_github_job.rb +7 -1
  60. data/app/jobs/shipit/create_release_statuses_job.rb +1 -0
  61. data/app/jobs/shipit/deferred_touch_job.rb +4 -0
  62. data/app/jobs/shipit/deliver_hook_job.rb +2 -1
  63. data/app/jobs/shipit/destroy_job.rb +1 -0
  64. data/app/jobs/shipit/destroy_repository_job.rb +24 -0
  65. data/app/jobs/shipit/destroy_stack_job.rb +3 -2
  66. data/app/jobs/shipit/emit_event_job.rb +2 -1
  67. data/app/jobs/shipit/fetch_commit_stats_job.rb +1 -0
  68. data/app/jobs/shipit/fetch_deployed_revision_job.rb +1 -0
  69. data/app/jobs/shipit/github_sync_job.rb +15 -10
  70. data/app/jobs/shipit/mark_deploy_healthy_job.rb +1 -0
  71. data/app/jobs/shipit/perform_commit_checks_job.rb +1 -0
  72. data/app/jobs/shipit/perform_task_job.rb +5 -92
  73. data/app/jobs/shipit/process_merge_requests_job.rb +32 -0
  74. data/app/jobs/shipit/purge_old_deliveries_job.rb +1 -0
  75. data/app/jobs/shipit/reap_dead_tasks_job.rb +21 -0
  76. data/app/jobs/shipit/refresh_check_runs_job.rb +1 -0
  77. data/app/jobs/shipit/refresh_github_user_job.rb +1 -0
  78. data/app/jobs/shipit/refresh_merge_request_job.rb +11 -0
  79. data/app/jobs/shipit/refresh_statuses_job.rb +1 -0
  80. data/app/jobs/shipit/setup_github_hook_job.rb +1 -0
  81. data/app/jobs/shipit/update_estimated_deploy_duration_job.rb +1 -0
  82. data/app/jobs/shipit/update_github_last_deployed_ref_job.rb +5 -4
  83. data/app/models/concerns/shipit/deferred_touch.rb +4 -3
  84. data/app/models/shipit/anonymous_user.rb +15 -2
  85. data/app/models/shipit/api_client.rb +3 -2
  86. data/app/models/shipit/application_record.rb +2 -1
  87. data/app/models/shipit/check_run.rb +41 -4
  88. data/app/models/shipit/command_line_user.rb +5 -0
  89. data/app/models/shipit/commit.rb +42 -24
  90. data/app/models/shipit/commit_checks.rb +15 -13
  91. data/app/models/shipit/commit_deployment.rb +6 -5
  92. data/app/models/shipit/commit_deployment_status.rb +5 -4
  93. data/app/models/shipit/commit_message.rb +1 -0
  94. data/app/models/shipit/delivery.rb +4 -3
  95. data/app/models/shipit/deploy.rb +23 -28
  96. data/app/models/shipit/deploy_spec/bundler_discovery.rb +1 -0
  97. data/app/models/shipit/deploy_spec/capistrano_discovery.rb +1 -0
  98. data/app/models/shipit/deploy_spec/file_system.rb +20 -7
  99. data/app/models/shipit/deploy_spec/kubernetes_discovery.rb +1 -0
  100. data/app/models/shipit/deploy_spec/lerna_discovery.rb +13 -4
  101. data/app/models/shipit/deploy_spec/npm_discovery.rb +5 -4
  102. data/app/models/shipit/deploy_spec/pypi_discovery.rb +1 -0
  103. data/app/models/shipit/deploy_spec/rubygems_discovery.rb +1 -0
  104. data/app/models/shipit/deploy_spec.rb +38 -7
  105. data/app/models/shipit/deploy_stats.rb +2 -1
  106. data/app/models/shipit/duration.rb +5 -2
  107. data/app/models/shipit/ephemeral_commit_checks.rb +1 -0
  108. data/app/models/shipit/github_hook.rb +2 -1
  109. data/app/models/shipit/github_status.rb +2 -1
  110. data/app/models/shipit/hook.rb +34 -7
  111. data/app/models/shipit/membership.rb +3 -2
  112. data/app/models/shipit/merge_request.rb +304 -0
  113. data/app/models/shipit/output_chunk.rb +7 -2
  114. data/app/models/shipit/provisioning_handler/base.rb +30 -0
  115. data/app/models/shipit/provisioning_handler/unregistered_provisioning_handler.rb +35 -0
  116. data/app/models/shipit/provisioning_handler.rb +32 -0
  117. data/app/models/shipit/pull_request.rb +28 -266
  118. data/app/models/shipit/pull_request_assignment.rb +10 -0
  119. data/app/models/shipit/record.rb +18 -0
  120. data/app/models/shipit/release_status.rb +4 -3
  121. data/app/models/shipit/repository.rb +71 -6
  122. data/app/models/shipit/review_stack.rb +130 -0
  123. data/app/models/shipit/review_stack_provisioning_queue.rb +39 -0
  124. data/app/models/shipit/rollback.rb +6 -0
  125. data/app/models/shipit/stack.rb +127 -45
  126. data/app/models/shipit/status/common.rb +7 -6
  127. data/app/models/shipit/status/group.rb +2 -1
  128. data/app/models/shipit/status/missing.rb +2 -1
  129. data/app/models/shipit/status/unknown.rb +2 -1
  130. data/app/models/shipit/status.rb +3 -2
  131. data/app/models/shipit/task.rb +98 -12
  132. data/app/models/shipit/task_definition.rb +1 -0
  133. data/app/models/shipit/task_execution_strategy/base.rb +20 -0
  134. data/app/models/shipit/task_execution_strategy/default.rb +109 -0
  135. data/app/models/shipit/team.rb +6 -3
  136. data/app/models/shipit/undeployed_commit.rb +1 -0
  137. data/app/models/shipit/unlimited_api_client.rb +1 -0
  138. data/app/models/shipit/user.rb +19 -8
  139. data/app/models/shipit/variable_definition.rb +1 -0
  140. data/app/models/shipit/webhooks/handlers/check_suite_handler.rb +1 -0
  141. data/app/models/shipit/webhooks/handlers/handler.rb +1 -0
  142. data/app/models/shipit/webhooks/handlers/membership_handler.rb +1 -0
  143. data/app/models/shipit/webhooks/handlers/pull_request/assigned_handler.rb +74 -0
  144. data/app/models/shipit/webhooks/handlers/pull_request/closed_handler.rb +68 -0
  145. data/app/models/shipit/webhooks/handlers/pull_request/edited_handler.rb +74 -0
  146. data/app/models/shipit/webhooks/handlers/pull_request/label_capturing_handler.rb +127 -0
  147. data/app/models/shipit/webhooks/handlers/pull_request/labeled_handler.rb +106 -0
  148. data/app/models/shipit/webhooks/handlers/pull_request/opened_handler.rb +83 -0
  149. data/app/models/shipit/webhooks/handlers/pull_request/reopened_handler.rb +88 -0
  150. data/app/models/shipit/webhooks/handlers/pull_request/review_stack_adapter.rb +103 -0
  151. data/app/models/shipit/webhooks/handlers/pull_request/unlabeled_handler.rb +107 -0
  152. data/app/models/shipit/webhooks/handlers/push_handler.rb +5 -1
  153. data/app/models/shipit/webhooks/handlers/status_handler.rb +1 -0
  154. data/app/models/shipit/webhooks.rb +11 -0
  155. data/app/serializers/concerns/shipit/conditional_attributes.rb +1 -0
  156. data/app/serializers/shipit/anonymous_user_serializer.rb +1 -0
  157. data/app/serializers/shipit/command_line_user_serializer.rb +1 -0
  158. data/app/serializers/shipit/commit_serializer.rb +1 -0
  159. data/app/serializers/shipit/deploy_serializer.rb +8 -1
  160. data/app/serializers/shipit/hook_serializer.rb +1 -0
  161. data/app/serializers/shipit/merge_request_serializer.rb +21 -0
  162. data/app/serializers/shipit/pull_request_serializer.rb +6 -8
  163. data/app/serializers/shipit/review_stack_serializer.rb +7 -0
  164. data/app/serializers/shipit/rollback_serializer.rb +1 -0
  165. data/app/serializers/shipit/short_commit_serializer.rb +1 -0
  166. data/app/serializers/shipit/stack_serializer.rb +8 -6
  167. data/app/serializers/shipit/tail_task_serializer.rb +11 -2
  168. data/app/serializers/shipit/task_serializer.rb +2 -17
  169. data/app/serializers/shipit/user_serializer.rb +6 -1
  170. data/app/validators/ascii_only_validator.rb +1 -0
  171. data/app/validators/subset_validator.rb +2 -1
  172. data/app/views/layouts/merge_status.html.erb +1 -1
  173. data/app/views/layouts/shipit.html.erb +1 -1
  174. data/app/views/shipit/_variables.html.erb +1 -1
  175. data/app/views/shipit/ccmenu/project.xml.builder +2 -1
  176. data/app/views/shipit/deploys/show.html.erb +2 -2
  177. data/app/views/shipit/merge_requests/_merge_request.html.erb +29 -0
  178. data/app/views/shipit/{pull_requests → merge_requests}/index.html.erb +2 -2
  179. data/app/views/shipit/merge_requests/merge_requests/_pull_request.html.erb +29 -0
  180. data/app/views/shipit/merge_requests/merge_requests/index.html.erb +20 -0
  181. data/app/views/shipit/merge_status/_merge_queue_button.html.erb +3 -3
  182. data/app/views/shipit/merge_status/backlogged.html.erb +1 -1
  183. data/app/views/shipit/merge_status/failure.html.erb +1 -1
  184. data/app/views/shipit/merge_status/locked.html.erb +1 -1
  185. data/app/views/shipit/merge_status/success.html.erb +2 -2
  186. data/app/views/shipit/repositories/_header.html.erb +19 -0
  187. data/app/views/shipit/repositories/index.html.erb +31 -0
  188. data/app/views/shipit/repositories/new.html.erb +23 -0
  189. data/app/views/shipit/repositories/settings.html.erb +53 -0
  190. data/app/views/shipit/repositories/show.html.erb +30 -0
  191. data/app/views/shipit/stacks/_banners.html.erb +15 -1
  192. data/app/views/shipit/stacks/_header.html.erb +8 -2
  193. data/app/views/shipit/stacks/_stack.html.erb +8 -0
  194. data/app/views/shipit/stacks/all_tasks.html.erb +28 -0
  195. data/app/views/shipit/stacks/index.html.erb +3 -2
  196. data/app/views/shipit/stacks/new.html.erb +1 -1
  197. data/app/views/shipit/stacks/settings.html.erb +5 -5
  198. data/app/views/shipit/stacks/show.html.erb +1 -1
  199. data/app/views/shipit/tasks/_task_output.html.erb +1 -1
  200. data/app/views/shipit/tasks/show.html.erb +1 -1
  201. data/config/initializers/inflections.rb +2 -1
  202. data/config/locales/en.yml +3 -3
  203. data/config/routes.rb +25 -7
  204. data/config/secrets.development.example.yml +24 -0
  205. data/config/secrets.development.shopify.yml +20 -9
  206. data/db/migrate/20200226211925_add_index_to_tasks_status.rb +5 -0
  207. data/db/migrate/20200427135152_add_pull_request_head_sha_to_commit.rb +5 -0
  208. data/db/migrate/20200615181558_add_rollback_once_aborted_to.rb +5 -0
  209. data/db/migrate/20200706145406_add_review_stacks.rb +12 -0
  210. data/db/migrate/20200804144639_rename_pull_request_to_merge_request.rb +7 -0
  211. data/db/migrate/20200804161512_rename_commits_pull_request_id_to_merge_request_id.rb +5 -0
  212. data/db/migrate/20200813134712_recreate_shipit_pull_requests.rb +22 -0
  213. data/db/migrate/20200813194056_create_pull_request_assignments.rb +8 -0
  214. data/db/migrate/20201001125502_add_provision_pr_stacks_flag_to_repositories.rb +7 -0
  215. data/db/migrate/20201008145809_add_retry_attempt_to_tasks.rb +5 -0
  216. data/db/migrate/20201008152744_add_max_retries_to_tasks.rb +5 -0
  217. data/db/migrate/20210325194053_remove_stacks_branch_default.rb +5 -0
  218. data/db/migrate/20210504200438_add_github_updated_at_to_check_runs.rb +5 -0
  219. data/db/migrate/20210823075617_change_check_runs_github_updated_at_default.rb +5 -0
  220. data/lib/shipit/cast_value.rb +1 -0
  221. data/lib/shipit/command.rb +19 -17
  222. data/lib/shipit/commands.rb +23 -9
  223. data/lib/shipit/csv_serializer.rb +1 -0
  224. data/lib/shipit/deploy_commands.rb +1 -0
  225. data/lib/shipit/engine.rb +9 -2
  226. data/lib/shipit/environment_variables.rb +2 -1
  227. data/lib/shipit/first_parent_commits_iterator.rb +1 -0
  228. data/lib/shipit/flock.rb +9 -1
  229. data/lib/shipit/github_app.rb +15 -12
  230. data/lib/shipit/github_http_cache_middleware.rb +1 -0
  231. data/lib/shipit/null_serializer.rb +1 -0
  232. data/lib/shipit/octokit_check_runs.rb +3 -2
  233. data/lib/shipit/octokit_iterator.rb +4 -3
  234. data/lib/shipit/paginator.rb +3 -2
  235. data/lib/shipit/review_stack_commands.rb +8 -0
  236. data/lib/shipit/rollback_commands.rb +1 -0
  237. data/lib/shipit/same_site_cookie_middleware.rb +29 -0
  238. data/lib/shipit/simple_message_verifier.rb +3 -2
  239. data/lib/shipit/stack_commands.rb +39 -9
  240. data/lib/shipit/stat.rb +1 -0
  241. data/lib/shipit/task_commands.rb +9 -0
  242. data/lib/shipit/version.rb +2 -1
  243. data/lib/shipit.rb +61 -17
  244. data/lib/snippets/publish-lerna-independent-packages +35 -34
  245. data/lib/snippets/publish-lerna-independent-packages-legacy +39 -0
  246. data/lib/snippets/release-gem +5 -1
  247. data/lib/tasks/cron.rake +13 -2
  248. data/lib/tasks/dev.rake +3 -2
  249. data/lib/tasks/shipit.rake +15 -14
  250. data/lib/tasks/teams.rake +1 -0
  251. data/test/controllers/api/base_controller_test.rb +3 -2
  252. data/test/controllers/api/ccmenu_controller_test.rb +9 -8
  253. data/test/controllers/api/commits_controller_test.rb +3 -2
  254. data/test/controllers/api/deploys_controller_test.rb +32 -14
  255. data/test/controllers/api/hooks_controller_test.rb +8 -7
  256. data/test/controllers/api/locks_controller_test.rb +7 -6
  257. data/test/controllers/api/{pull_requests_controller_test.rb → merge_requests_controller_test.rb} +17 -16
  258. data/test/controllers/api/outputs_controller_test.rb +3 -1
  259. data/test/controllers/api/release_statuses_controller_test.rb +2 -1
  260. data/test/controllers/api/rollback_controller_test.rb +113 -0
  261. data/test/controllers/api/stacks_controller_test.rb +71 -16
  262. data/test/controllers/api/tasks_controller_test.rb +13 -12
  263. data/test/controllers/api_clients_controller_test.rb +5 -4
  264. data/test/controllers/ccmenu_controller_test.rb +4 -3
  265. data/test/controllers/commit_checks_controller_test.rb +4 -3
  266. data/test/controllers/commits_controller_test.rb +3 -2
  267. data/test/controllers/deploys_controller_test.rb +32 -21
  268. data/test/controllers/github_authentication_controller_test.rb +1 -0
  269. data/test/controllers/merge_requests_controller_test.rb +32 -0
  270. data/test/controllers/merge_status_controller_test.rb +7 -6
  271. data/test/controllers/release_statuses_controller_test.rb +3 -2
  272. data/test/controllers/repositories_controller_test.rb +71 -0
  273. data/test/controllers/rollbacks_controller_test.rb +9 -8
  274. data/test/controllers/stacks_controller_test.rb +41 -19
  275. data/test/controllers/status_controller_test.rb +1 -0
  276. data/test/controllers/tasks_controller_test.rb +32 -19
  277. data/test/controllers/webhooks_controller_test.rb +33 -17
  278. data/test/dummy/app/assets/config/manifest.js +3 -0
  279. data/test/dummy/config/application.rb +7 -2
  280. data/test/dummy/config/database.yml +9 -0
  281. data/test/dummy/config/environments/development.rb +3 -4
  282. data/test/dummy/config/environments/test.rb +2 -5
  283. data/test/dummy/config/secrets_double_github_app.yml +79 -0
  284. data/test/dummy/db/schema.rb +59 -17
  285. data/test/dummy/db/seeds.rb +2 -1
  286. data/test/fixtures/payloads/check_suite_master.json +4 -32
  287. data/test/fixtures/payloads/invalid_pull_request.json +117 -0
  288. data/test/fixtures/payloads/provision_disabled_pull_request.json +454 -0
  289. data/test/fixtures/payloads/pull_request_assigned.json +480 -0
  290. data/test/fixtures/payloads/pull_request_closed.json +454 -0
  291. data/test/fixtures/payloads/pull_request_labeled.json +461 -0
  292. data/test/fixtures/payloads/pull_request_opened.json +454 -0
  293. data/test/fixtures/payloads/pull_request_reopened.json +454 -0
  294. data/test/fixtures/payloads/pull_request_unlabeled.json +454 -0
  295. data/test/fixtures/payloads/pull_request_with_no_repo.json +454 -0
  296. data/test/fixtures/payloads/push_master.json +1 -1
  297. data/test/fixtures/payloads/push_not_master.json +1 -1
  298. data/test/fixtures/shipit/commits.yml +31 -3
  299. data/test/fixtures/shipit/hooks.yml +1 -0
  300. data/test/fixtures/shipit/merge_requests.yml +141 -0
  301. data/test/fixtures/shipit/pull_request_assignments.yml +3 -0
  302. data/test/fixtures/shipit/pull_requests.yml +10 -131
  303. data/test/fixtures/shipit/repositories.yml +5 -0
  304. data/test/fixtures/shipit/stacks.yml +235 -14
  305. data/test/fixtures/shipit/statuses.yml +9 -0
  306. data/test/fixtures/shipit/tasks.yml +4 -1
  307. data/test/fixtures/shipit/users.yml +7 -0
  308. data/test/fixtures/timeout +2 -1
  309. data/test/helpers/api_helper.rb +1 -0
  310. data/test/helpers/fixture_aliases_helper.rb +1 -0
  311. data/test/helpers/hooks_helper.rb +2 -1
  312. data/test/helpers/json_helper.rb +20 -12
  313. data/test/helpers/links_helper.rb +4 -3
  314. data/test/helpers/payloads_helper.rb +5 -0
  315. data/test/helpers/queries_helper.rb +3 -2
  316. data/test/jobs/cache_deploy_spec_job_test.rb +2 -1
  317. data/test/jobs/chunk_rollup_job_test.rb +16 -1
  318. data/test/jobs/deliver_hook_job_test.rb +1 -0
  319. data/test/jobs/destroy_repository_job_test.rb +27 -0
  320. data/test/jobs/destroy_stack_job_test.rb +1 -0
  321. data/test/jobs/emit_event_job_test.rb +2 -1
  322. data/test/jobs/fetch_commit_stats_job_test.rb +1 -0
  323. data/test/jobs/fetch_deployed_revision_job_test.rb +1 -0
  324. data/test/jobs/github_sync_job_test.rb +3 -1
  325. data/test/jobs/mark_deploy_healthy_job_test.rb +1 -0
  326. data/test/jobs/perform_task_job_test.rb +12 -11
  327. data/test/jobs/{merge_pull_requests_job_test.rb → process_merge_requests_job_test.rb} +19 -18
  328. data/test/jobs/purge_old_deliveries_job_test.rb +1 -0
  329. data/test/jobs/reap_dead_tasks_job_test.rb +68 -0
  330. data/test/jobs/refresh_github_user_job_test.rb +1 -0
  331. data/test/jobs/refresh_status_job_test.rb +1 -0
  332. data/test/jobs/unique_job_test.rb +1 -0
  333. data/test/jobs/update_github_last_deployed_ref_job_test.rb +1 -0
  334. data/test/lib/shipit/deploy_commands_test.rb +16 -0
  335. data/test/lib/shipit/task_commands_test.rb +17 -0
  336. data/test/middleware/same_site_cookie_middleware_test.rb +52 -0
  337. data/test/models/api_client_test.rb +1 -0
  338. data/test/models/commit_checks_test.rb +1 -0
  339. data/test/models/commit_deployment_status_test.rb +4 -3
  340. data/test/models/commit_deployment_test.rb +2 -1
  341. data/test/models/commits_test.rb +96 -19
  342. data/test/models/delivery_test.rb +2 -1
  343. data/test/models/deploy_spec_test.rb +110 -65
  344. data/test/models/deploy_stats_test.rb +1 -0
  345. data/test/models/deploys_test.rb +219 -36
  346. data/test/models/duration_test.rb +1 -0
  347. data/test/models/github_hook_test.rb +1 -0
  348. data/test/models/hook_test.rb +47 -10
  349. data/test/models/membership_test.rb +1 -0
  350. data/test/models/{pull_request_test.rb → merge_request_test.rb} +53 -37
  351. data/test/models/pull_request_assignment_test.rb +16 -0
  352. data/test/models/release_statuses_test.rb +1 -0
  353. data/test/models/rollbacks_test.rb +1 -0
  354. data/test/models/shipit/check_run_test.rb +125 -5
  355. data/test/models/shipit/provisioning_handler/base_test.rb +33 -0
  356. data/test/models/shipit/provisioning_handler/unregistered_provisioning_handler_test.rb +49 -0
  357. data/test/models/shipit/provisioning_handler_test.rb +64 -0
  358. data/test/models/shipit/pull_request_test.rb +52 -0
  359. data/test/models/shipit/repository_test.rb +6 -1
  360. data/test/models/shipit/review_stack_provision_status_test.rb +77 -0
  361. data/test/models/shipit/review_stack_provisioning_queue_test.rb +63 -0
  362. data/test/models/shipit/review_stack_test.rb +91 -0
  363. data/test/models/{stacks_test.rb → shipit/stacks_test.rb} +82 -16
  364. data/test/models/shipit/webhooks/handlers/pull_request/assigned_handler_test.rb +45 -0
  365. data/test/models/shipit/webhooks/handlers/pull_request/closed_handler_test.rb +192 -0
  366. data/test/models/shipit/webhooks/handlers/pull_request/edited_handler_test.rb +47 -0
  367. data/test/models/shipit/webhooks/handlers/pull_request/label_capturing_handler_test.rb +209 -0
  368. data/test/models/shipit/webhooks/handlers/pull_request/labeled_handler_test.rb +332 -0
  369. data/test/models/shipit/webhooks/handlers/pull_request/opened_handler_test.rb +238 -0
  370. data/test/models/shipit/webhooks/handlers/pull_request/reopened_handler_test.rb +282 -0
  371. data/test/models/shipit/webhooks/handlers/pull_request/review_stack_adapter_test.rb +107 -0
  372. data/test/models/shipit/webhooks/handlers/pull_request/unlabeled_handler_test.rb +324 -0
  373. data/test/models/shipit/{wehbooks → webhooks}/handlers_test.rb +1 -0
  374. data/test/models/status/group_test.rb +1 -0
  375. data/test/models/status/missing_test.rb +1 -0
  376. data/test/models/status_test.rb +1 -0
  377. data/test/models/task_definitions_test.rb +9 -8
  378. data/test/models/tasks_test.rb +81 -1
  379. data/test/models/team_test.rb +4 -2
  380. data/test/models/undeployed_commits_test.rb +1 -0
  381. data/test/models/users_test.rb +13 -5
  382. data/test/serializers/shipit/pull_request_serializer_test.rb +29 -0
  383. data/test/test_command_integration.rb +3 -2
  384. data/test/test_helper.rb +49 -31
  385. data/test/unit/anonymous_user_serializer_test.rb +14 -0
  386. data/test/unit/command_test.rb +16 -10
  387. data/test/unit/commands_test.rb +1 -0
  388. data/test/unit/commit_serializer_test.rb +16 -0
  389. data/test/unit/csv_serializer_test.rb +3 -2
  390. data/test/unit/deploy_commands_test.rb +77 -20
  391. data/test/unit/deploy_serializer_test.rb +17 -0
  392. data/test/unit/environment_variables_test.rb +5 -4
  393. data/test/unit/github_app_test.rb +3 -3
  394. data/test/unit/github_apps_test.rb +416 -0
  395. data/test/unit/github_url_helper_test.rb +6 -0
  396. data/test/unit/rollback_commands_test.rb +2 -1
  397. data/test/unit/shipit_deployment_checks_test.rb +77 -0
  398. data/test/unit/shipit_helper_test.rb +17 -0
  399. data/test/unit/shipit_task_execution_strategy_test.rb +47 -0
  400. data/test/unit/shipit_test.rb +15 -0
  401. data/test/unit/user_serializer_test.rb +14 -0
  402. data/test/unit/variable_definition_test.rb +1 -0
  403. metadata +325 -182
  404. data/app/controllers/shipit/api/pull_requests_controller.rb +0 -36
  405. data/app/controllers/shipit/pull_requests_controller.rb +0 -30
  406. data/app/jobs/shipit/merge_pull_requests_job.rb +0 -31
  407. data/app/jobs/shipit/refresh_pull_request_job.rb +0 -10
  408. data/app/views/shipit/pull_requests/_pull_request.html.erb +0 -29
  409. data/test/controllers/pull_requests_controller_test.rb +0 -31
  410. data/test/fixtures/shipit/output_chunks.yml +0 -47
  411. data/test/models/output_chunk_test.rb +0 -20
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+ module Shipit
3
+ class Record < ActiveRecord::Base
4
+ self.abstract_class = true
5
+
6
+ class << self
7
+ def serializer_class
8
+ if defined? @serializer_class
9
+ @serializer_class
10
+ else
11
+ @serializer_class = "#{name}Serializer".safe_constantize
12
+ end
13
+ end
14
+ end
15
+
16
+ delegate :serializer_class, to: :class
17
+ end
18
+ end
@@ -1,5 +1,6 @@
1
+ # frozen_string_literal: true
1
2
  module Shipit
2
- class ReleaseStatus < ActiveRecord::Base
3
+ class ReleaseStatus < Record
3
4
  MAX_DESCRIPTION_LENGTH = 140
4
5
  include DeferredTouch
5
6
 
@@ -13,7 +14,7 @@ module Shipit
13
14
  scope :to_be_created, -> { where(github_id: nil).order(id: :asc) }
14
15
 
15
16
  STATES = %w(pending success failure error).freeze
16
- validates :state, presence: true, inclusion: {in: STATES}
17
+ validates :state, presence: true, inclusion: { in: STATES }
17
18
 
18
19
  def create_status_on_github!
19
20
  return true if github_id?
@@ -24,7 +25,7 @@ module Shipit
24
25
  private
25
26
 
26
27
  def create_status_on_github
27
- Shipit.github.api.create_status(
28
+ stack.github_api.create_status(
28
29
  stack.github_repo_name,
29
30
  commit.sha,
30
31
  state,
@@ -1,4 +1,35 @@
1
+ # frozen_string_literal: true
1
2
  module Shipit
3
+ class NullRepository
4
+ def id
5
+ nil
6
+ end
7
+
8
+ def stacks
9
+ Shipit::Stack.none
10
+ end
11
+
12
+ def review_stacks
13
+ Shipit::ReviewStack.none
14
+ end
15
+
16
+ def review_stacks_enabled
17
+ false
18
+ end
19
+
20
+ def provisioning_behavior_allow_all?
21
+ false
22
+ end
23
+
24
+ def provisioning_behavior_allow_with_label?
25
+ false
26
+ end
27
+
28
+ def provisioning_behavior_prevent_with_label?
29
+ false
30
+ end
31
+ end
32
+
2
33
  class Repository < ApplicationRecord
3
34
  OWNER_MAX_SIZE = 39
4
35
  private_constant :OWNER_MAX_SIZE
@@ -6,13 +37,17 @@ module Shipit
6
37
  NAME_MAX_SIZE = 100
7
38
  private_constant :NAME_MAX_SIZE
8
39
 
9
- validates :name, uniqueness: {scope: %i(owner), case_sensitive: false,
10
- message: 'cannot be used more than once'}
40
+ validates :name, uniqueness: { scope: %i(owner), case_sensitive: false,
41
+ message: 'cannot be used more than once', }
11
42
  validates :owner, :name, presence: true, ascii_only: true
12
- validates :owner, format: {with: /\A[a-z0-9_\-\.]+\z/}, length: {maximum: OWNER_MAX_SIZE}
13
- validates :name, format: {with: /\A[a-z0-9_\-\.]+\z/}, length: {maximum: NAME_MAX_SIZE}
43
+ validates :owner, format: { with: /\A[a-z0-9_\-\.]+\z/ }, length: { maximum: OWNER_MAX_SIZE }
44
+ validates :name, format: { with: /\A[a-z0-9_\-\.]+\z/ }, length: { maximum: NAME_MAX_SIZE }
14
45
 
15
46
  has_many :stacks, dependent: :destroy
47
+ has_many :review_stacks, dependent: :destroy
48
+
49
+ PROVISIONING_BEHAVIORS = %w(allow_all allow_with_label prevent_with_label).freeze
50
+ enum provisioning_behavior: PROVISIONING_BEHAVIORS.zip(PROVISIONING_BEHAVIORS).to_h, _prefix: :provisioning_behavior
16
51
 
17
52
  def self.from_github_repo_name(github_repo_name)
18
53
  repo_owner, repo_name = github_repo_name.downcase.split('/')
@@ -27,12 +62,42 @@ module Shipit
27
62
  super(o&.downcase)
28
63
  end
29
64
 
65
+ def github_repo_name
66
+ [owner, name].join('/')
67
+ end
68
+
30
69
  def http_url
31
- Shipit.github.url("#{owner}/#{name}")
70
+ github_app.url(full_name)
71
+ end
72
+
73
+ def full_name
74
+ "#{owner}/#{name}"
32
75
  end
33
76
 
34
77
  def git_url
35
- "https://#{Shipit.github.domain}/#{owner}/#{name}.git"
78
+ "https://#{github_app.domain}/#{owner}/#{name}.git"
79
+ end
80
+
81
+ def schedule_for_destroy!
82
+ DestroyRepositoryJob.perform_later(self)
83
+ end
84
+
85
+ def to_param
86
+ github_repo_name
87
+ end
88
+
89
+ def self.from_param!(param)
90
+ repo_owner, repo_name = param.split('/')
91
+ where(
92
+ owner: repo_owner.downcase,
93
+ name: repo_name.downcase,
94
+ ).first!
95
+ end
96
+
97
+ protected
98
+
99
+ def github_app
100
+ Shipit.github(organization: owner)
36
101
  end
37
102
  end
38
103
  end
@@ -0,0 +1,130 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shipit
4
+ class ReviewStack < Shipit::Stack
5
+ def self.clear_stale_caches
6
+ Shipit::ReviewStack.where(
7
+ "archived_since > :earliest AND archived_since < :latest",
8
+ earliest: 1.day.ago,
9
+ latest: 1.hour.ago
10
+ ).find_each do |review_stack|
11
+ review_stack.clear_local_files
12
+ end
13
+ end
14
+
15
+ def self.delete_old_deployment_directories
16
+ Shipit::Deploy.not_active.where(
17
+ "created_at > :earliest AND updated_at < :latest",
18
+ earliest: 1.day.ago,
19
+ latest: 1.hour.ago
20
+ ).find_each do |deploy|
21
+ Shipit::Commands.for(deploy).clear_working_directory
22
+ end
23
+ end
24
+
25
+ def update_latest_deployed_ref
26
+ # noop: last deployed ref is useless for review stacks
27
+ end
28
+
29
+ model_name.class_eval do
30
+ def route_key
31
+ "stacks"
32
+ end
33
+
34
+ def singular_route_key
35
+ "stack"
36
+ end
37
+ end
38
+
39
+ has_one :pull_request, foreign_key: :stack_id
40
+
41
+ after_commit :emit_added_hooks, on: :create
42
+ after_commit :emit_updated_hooks, on: :update
43
+ after_commit :emit_removed_hooks, on: :destroy
44
+
45
+ state_machine :provision_status, initial: :deprovisioned do
46
+ state :provisioned
47
+ state :provisioning
48
+ state :deprovisioning
49
+ state :deprovisioned
50
+
51
+ event :provision do
52
+ transition deprovisioned: :provisioning
53
+ end
54
+
55
+ event :provision_success do
56
+ transition provisioning: :provisioned
57
+ end
58
+
59
+ event :provision_failure do
60
+ transition provisioning: :deprovisioned
61
+ end
62
+
63
+ event :deprovision do
64
+ transition provisioned: :deprovisioning
65
+ end
66
+
67
+ event :deprovision_success do
68
+ transition deprovisioning: :deprovisioned
69
+ end
70
+
71
+ event :deprovision_failure do
72
+ transition deprovisioning: :provisioned
73
+ end
74
+
75
+ after_transition deprovisioned: :provisioning do |stack, _|
76
+ stack.provisioner.up
77
+ end
78
+
79
+ after_transition provisioned: :deprovisioning do |stack, _|
80
+ stack.provisioner.down
81
+ end
82
+ end
83
+
84
+ def env
85
+ return super unless pull_request.present?
86
+
87
+ super
88
+ .merge(
89
+ pull_request
90
+ .labels
91
+ .each_with_object({}) { |label_name, labels| labels[label_name.upcase] = "true" }
92
+ )
93
+ end
94
+
95
+ def provisioner
96
+ provisioner_class.new(self)
97
+ end
98
+
99
+ def provisioner_class
100
+ ProvisioningHandler.fetch(provisioning_handler_name)
101
+ end
102
+
103
+ def enqueue_for_provisioning
104
+ return if awaiting_provision
105
+ update!(awaiting_provision: true)
106
+ end
107
+
108
+ def remove_from_provisioning_queue
109
+ return unless awaiting_provision
110
+ update!(awaiting_provision: false)
111
+ end
112
+
113
+ def to_partial_path
114
+ "shipit/stacks/stack"
115
+ end
116
+
117
+ def emit_added_hooks
118
+ Hook.emit(:review_stack, self, action: :added, review_stack: self)
119
+ end
120
+
121
+ def emit_updated_hooks
122
+ changed = !(previous_changes.keys - %w(updated_at)).empty?
123
+ Hook.emit(:review_stack, self, action: :updated, review_stack: self) if changed
124
+ end
125
+
126
+ def emit_removed_hooks
127
+ Hook.emit(:review_stack, self, action: :removed, review_stack: self)
128
+ end
129
+ end
130
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shipit
4
+ class ReviewStackProvisioningQueue
5
+ def self.work
6
+ new.work
7
+ end
8
+
9
+ def self.add(stack)
10
+ stack.enqueue_for_provisioning
11
+ end
12
+
13
+ def self.queued_stacks
14
+ new.queued_stacks
15
+ end
16
+
17
+ def work
18
+ queued_stacks.find_each(&method(:provision))
19
+ end
20
+
21
+ def queued_stacks
22
+ @queued_stacks ||= Shipit::ReviewStack
23
+ .with_provision_status(:deprovisioned)
24
+ .where(awaiting_provision: true)
25
+ end
26
+
27
+ private
28
+
29
+ def provision(stack)
30
+ if stack.provisioner.provision?
31
+ stack.provision
32
+ else
33
+ Rails.logger.info(
34
+ "Putting review ReviewStack<#{stack.id}> back into the provisioning queue - #provision? was falsey."
35
+ )
36
+ end
37
+ end
38
+ end
39
+ end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Shipit
2
3
  class Rollback < Deploy
3
4
  belongs_to :deploy, foreign_key: :parent_id, inverse_of: false
@@ -32,6 +33,10 @@ module Shipit
32
33
  'deploys/deploy'
33
34
  end
34
35
 
36
+ def report_complete!
37
+ complete!
38
+ end
39
+
35
40
  private
36
41
 
37
42
  def update_release_status
@@ -39,6 +44,7 @@ module Shipit
39
44
 
40
45
  # When we rollback to a certain revision, assume that all later deploys were faulty
41
46
  stack.deploys.newer_than(deploy.id).until(stack.last_completed_deploy.id).to_a.each do |deploy|
47
+ next if deploy.id == id
42
48
  deploy.report_faulty!(description: "A rollback of #{stack.to_param} was triggered")
43
49
  end
44
50
  end
@@ -1,7 +1,8 @@
1
+ # frozen_string_literal: true
1
2
  require 'fileutils'
2
3
 
3
4
  module Shipit
4
- class Stack < ActiveRecord::Base
5
+ class Stack < Record
5
6
  module NoDeployedCommit
6
7
  extend self
7
8
 
@@ -26,14 +27,14 @@ module Shipit
26
27
  REQUIRED_HOOKS = %i(push status).freeze
27
28
 
28
29
  has_many :commits, dependent: :destroy
29
- has_many :pull_requests, dependent: :destroy
30
+ has_many :merge_requests, dependent: :destroy
30
31
  has_many :tasks, dependent: :destroy
31
32
  has_many :deploys
32
33
  has_many :rollbacks
33
34
  has_many :deploys_and_rollbacks,
34
- -> { where(type: %w(Shipit::Deploy Shipit::Rollback)) },
35
- class_name: 'Task',
36
- inverse_of: :stack
35
+ -> { where(type: %w(Shipit::Deploy Shipit::Rollback)) },
36
+ class_name: 'Task',
37
+ inverse_of: :stack
37
38
  has_many :github_hooks, dependent: :destroy, class_name: 'Shipit::GithubHook::Repo'
38
39
  has_many :hooks, dependent: :destroy
39
40
  has_many :api_clients, dependent: :destroy
@@ -43,6 +44,11 @@ module Shipit
43
44
 
44
45
  scope :not_archived, -> { where(archived_since: nil) }
45
46
 
47
+ include DeferredTouch
48
+ deferred_touch repository: :updated_at
49
+
50
+ default_scope { preload(:repository) }
51
+
46
52
  def env
47
53
  {
48
54
  'ENVIRONMENT' => environment,
@@ -77,19 +83,36 @@ module Shipit
77
83
  after_commit :emit_merge_status_hooks, on: :update
78
84
  after_commit :sync_github, on: :create
79
85
  after_commit :schedule_merges_if_necessary, on: :update
86
+ after_commit :sync_github_if_necessary, on: :update
87
+
88
+ def sync_github_if_necessary
89
+ if (archived_since_previously_changed? && archived_since.nil?) || branch_previously_changed?
90
+ sync_github
91
+ end
92
+ end
80
93
 
81
94
  validates :repository, uniqueness: {
82
95
  scope: %i(environment), case_sensitive: false,
83
- message: 'cannot be used more than once with this environment. Check archived stacks.'
96
+ message: 'cannot be used more than once with this environment. Check archived stacks.',
84
97
  }
85
- validates :environment, format: {with: /\A[a-z0-9\-_\:]+\z/}, length: {maximum: ENVIRONMENT_MAX_SIZE}
86
- validates :deploy_url, format: {with: URI.regexp(%w(http https ssh))}, allow_blank: true
98
+ validates :environment, format: { with: /\A[a-z0-9\-_\:]+\z/ }, length: { maximum: ENVIRONMENT_MAX_SIZE }
99
+ validates :deploy_url, format: { with: URI.regexp(%w(http https ssh)) }, allow_blank: true
100
+ validates :branch, presence: true
87
101
 
88
- validates :lock_reason, length: {maximum: 4096}
102
+ validates :lock_reason, length: { maximum: 4096 }
89
103
 
90
104
  serialize :cached_deploy_spec, DeploySpec
91
- delegate :find_task_definition, :supports_rollback?, :release_status?, :release_status_delay,
92
- :release_status_context, :supports_fetch_deployed_revision?, to: :cached_deploy_spec, allow_nil: true
105
+ delegate(
106
+ :provisioning_handler_name,
107
+ :find_task_definition,
108
+ :release_status?,
109
+ :release_status_context,
110
+ :release_status_delay,
111
+ :supports_fetch_deployed_revision?,
112
+ :supports_rollback?,
113
+ to: :cached_deploy_spec,
114
+ allow_nil: true
115
+ )
93
116
 
94
117
  def self.refresh_deployed_revisions
95
118
  find_each.select(&:supports_fetch_deployed_revision?).each(&:async_refresh_deployed_revision)
@@ -136,13 +159,29 @@ module Shipit
136
159
  env: filter_deploy_envs(env&.to_h || {}),
137
160
  allow_concurrency: force,
138
161
  ignored_safeties: force || !until_commit.deployable?,
162
+ max_retries: retries_on_deploy,
139
163
  )
140
164
  end
141
165
 
142
166
  def trigger_deploy(*args, **kwargs)
167
+ if changed?
168
+ # If this is the first deploy since the spec changed it's possible the record will be dirty here, meaning we
169
+ # cant lock. In this one case persist the changes, otherwise log a warning and let the lock raise, so we
170
+ # can debug what's going on here. We don't expect anything other than the deploy spec to dirty the model
171
+ # instance, because of how that field is serialised.
172
+ if changes.keys == ['cached_deploy_spec']
173
+ save!
174
+ else
175
+ Rails.logger.warning("#{changes.keys} field(s) were unexpectedly modified on stack #{id} while deploying")
176
+ end
177
+ end
178
+
143
179
  run_now = kwargs.delete(:run_now)
144
- deploy = build_deploy(*args, **kwargs)
145
- deploy.save!
180
+ deploy = with_lock do
181
+ deploy = build_deploy(*args, **kwargs)
182
+ deploy.save!
183
+ deploy
184
+ end
146
185
  run_now ? deploy.run_now! : deploy.enqueue
147
186
  continuous_delivery_resumed!
148
187
  deploy
@@ -153,7 +192,7 @@ module Shipit
153
192
  end
154
193
 
155
194
  def continuous_delivery_delayed?
156
- continuous_delivery_delayed_since? && continuous_deployment? && checks?
195
+ continuous_delivery_delayed_since? && continuous_deployment? && (checks? || deployment_checks?)
157
196
  end
158
197
 
159
198
  def continuous_delivery_delayed!
@@ -161,15 +200,16 @@ module Shipit
161
200
  end
162
201
 
163
202
  def trigger_continuous_delivery
203
+ return if cached_deploy_spec.blank?
204
+
164
205
  commit = next_commit_to_deploy
165
206
 
166
- if !deployable? || deployed_too_recently? || commit.nil? || commit.deployed?
207
+ if should_resume_continuous_delivery?(commit)
167
208
  continuous_delivery_resumed!
168
209
  return
169
210
  end
170
211
 
171
- if commit.deploy_failed? || (checks? && !EphemeralCommitChecks.new(commit).run.success?) ||
172
- commit.recently_pushed?
212
+ if should_delay_continuous_delivery?(commit)
173
213
  continuous_delivery_delayed!
174
214
  return
175
215
  end
@@ -181,7 +221,7 @@ module Shipit
181
221
  end
182
222
 
183
223
  def schedule_merges
184
- MergePullRequestsJob.perform_later(self)
224
+ ProcessMergeRequestsJob.perform_later(self)
185
225
  end
186
226
 
187
227
  def next_commit_to_deploy
@@ -201,7 +241,7 @@ module Shipit
201
241
  def async_refresh_deployed_revision
202
242
  async_refresh_deployed_revision!
203
243
  rescue => error
204
- logger.warn "Failed to dispatch FetchDeployedRevisionJob: [#{error.class.name}] #{error.message}"
244
+ logger.warn("Failed to dispatch FetchDeployedRevisionJob: [#{error.class.name}] #{error.message}")
205
245
  end
206
246
 
207
247
  def async_refresh_deployed_revision!
@@ -269,8 +309,8 @@ module Shipit
269
309
  next if commits_to_lock.empty?
270
310
 
271
311
  affected_rows += commits
272
- .where(id: commits_to_lock.map(&:id).uniq)
273
- .lock_all(revert.author)
312
+ .where(id: commits_to_lock.map(&:id).uniq)
313
+ .lock_all(revert.author)
274
314
  end
275
315
 
276
316
  touch if affected_rows > 1
@@ -321,7 +361,7 @@ module Shipit
321
361
  end
322
362
 
323
363
  def deployable?
324
- !locked? && !active_task?
364
+ !locked? && !active_task? && !awaiting_provision? && deployment_checks_passed?
325
365
  end
326
366
 
327
367
  def allows_merges?
@@ -329,7 +369,7 @@ module Shipit
329
369
  end
330
370
 
331
371
  def merge_method
332
- cached_deploy_spec&.pull_request_merge_method || Shipit.default_merge_method
372
+ cached_deploy_spec&.merge_request_merge_method || Shipit.default_merge_method
333
373
  end
334
374
 
335
375
  delegate :name=, to: :repository, prefix: :repo
@@ -340,42 +380,51 @@ module Shipit
340
380
  delegate :git_url, to: :repository, prefix: :repo
341
381
 
342
382
  def base_path
343
- Rails.root.join('data', 'stacks', repo_owner, repo_name, environment)
383
+ @base_path ||= Rails.root.join('data', 'stacks', repo_owner, repo_name, environment)
344
384
  end
345
385
 
346
386
  def deploys_path
347
- File.join(base_path, "deploys")
387
+ @deploys_path ||= base_path.join("deploys")
348
388
  end
349
389
 
350
390
  def git_path
351
- File.join(base_path, "git")
391
+ @git_path ||= base_path.join("git")
352
392
  end
353
393
 
354
394
  def acquire_git_cache_lock(timeout: 15, &block)
355
- Flock.new(git_path.to_s + '.lock').lock(timeout: timeout, &block)
395
+ @git_cache_lock ||= Flock.new(git_path.to_s + '.lock')
396
+ @git_cache_lock.lock(timeout: timeout, &block)
356
397
  end
357
398
 
358
399
  def clear_git_cache!
359
400
  tmp_path = "#{git_path}-#{SecureRandom.hex}"
360
- return unless File.exist?(git_path)
401
+ return unless git_path.exist?
361
402
  acquire_git_cache_lock do
362
- File.rename(git_path, tmp_path)
403
+ git_path.rename(tmp_path)
363
404
  end
364
405
  FileUtils.rm_rf(tmp_path)
365
406
  end
366
407
 
367
408
  def github_repo_name
368
- [repo_owner, repo_name].join('/')
409
+ repository.github_repo_name
369
410
  end
370
411
 
371
412
  def github_commits
372
413
  handle_github_redirections do
373
- Shipit.github.api.commits(github_repo_name, sha: branch)
414
+ github_api.commits(github_repo_name, sha: branch)
374
415
  end
375
416
  rescue Octokit::Conflict
376
417
  [] # Repository is empty...
377
418
  end
378
419
 
420
+ def github_api
421
+ github_app.api
422
+ end
423
+
424
+ def github_app
425
+ Shipit.github(organization: repository.owner)
426
+ end
427
+
379
428
  def handle_github_redirections
380
429
  # https://developer.github.com/v3/#http-redirects
381
430
  resource = yield
@@ -388,9 +437,9 @@ module Shipit
388
437
  end
389
438
 
390
439
  def refresh_repository!
391
- resource = Shipit.github.api.repo(github_repo_name)
440
+ resource = github_api.repo(github_repo_name)
392
441
  if resource.try(:message) == 'Moved Permanently'
393
- resource = Shipit.github.api.get(resource.url)
442
+ resource = github_api.get(resource.url)
394
443
  end
395
444
  repository.update!(owner: resource.owner.login, name: resource.name)
396
445
  end
@@ -409,7 +458,7 @@ module Shipit
409
458
  end
410
459
 
411
460
  def lock(reason, user)
412
- params = {lock_reason: reason, lock_author: user}
461
+ params = { lock_reason: reason, lock_author: user }
413
462
  update!(params)
414
463
  end
415
464
 
@@ -455,8 +504,9 @@ module Shipit
455
504
  end
456
505
 
457
506
  delegate :plugins, :task_definitions, :hidden_statuses, :required_statuses, :soft_failing_statuses,
458
- :blocking_statuses, :deploy_variables, :filter_task_envs, :filter_deploy_envs,
459
- :maximum_commits_per_deploy, :pause_between_deploys, to: :cached_deploy_spec
507
+ :blocking_statuses, :deploy_variables, :filter_task_envs, :filter_deploy_envs,
508
+ :maximum_commits_per_deploy, :pause_between_deploys, :retries_on_deploy, :retries_on_rollback,
509
+ to: :cached_deploy_spec
460
510
 
461
511
  def monitoring?
462
512
  monitoring.present?
@@ -481,13 +531,15 @@ module Shipit
481
531
  end
482
532
 
483
533
  def update_latest_deployed_ref
484
- UpdateGithubLastDeployedRefJob.perform_later(self)
534
+ if Shipit.update_latest_deployed_ref
535
+ UpdateGithubLastDeployedRefJob.perform_later(self)
536
+ end
485
537
  end
486
538
 
487
539
  def broadcast_update
488
540
  Pubsubstub.publish(
489
541
  "stack.#{id}",
490
- {id: id, updated_at: updated_at}.to_json,
542
+ { id: id, updated_at: updated_at }.to_json,
491
543
  name: 'update',
492
544
  )
493
545
  end
@@ -546,19 +598,31 @@ module Shipit
546
598
  links_spec.transform_values { |url| context.interpolate(url) }
547
599
  end
548
600
 
601
+ def clear_local_files
602
+ FileUtils.rm_rf(base_path.to_s)
603
+ end
604
+
605
+ def deployment_checks_passed?
606
+ return true unless deployment_checks?
607
+
608
+ Shipit.deployment_checks.call(self)
609
+ end
610
+
549
611
  private
550
612
 
551
613
  def clear_cache
552
614
  remove_instance_variable(:@active_task) if defined?(@active_task)
553
615
  end
554
616
 
555
- def clear_local_files
556
- FileUtils.rm_rf(base_path.to_s)
557
- end
558
-
559
617
  def update_defaults
560
618
  self.environment = 'production' if environment.blank?
561
- self.branch = 'master' if branch.blank?
619
+ self.branch = default_branch_name if branch.blank?
620
+ end
621
+
622
+ def default_branch_name
623
+ Shipit.github.api.repo(github_repo_name).default_branch
624
+ rescue Octokit::NotFound, Octokit::InvalidRepository
625
+ nil
562
626
  end
563
627
 
564
628
  def set_locked_since
@@ -572,7 +636,7 @@ module Shipit
572
636
  end
573
637
 
574
638
  def schedule_merges_if_necessary
575
- if previous_changes.include?('lock_reason') && previous_changes['lock_reason'].last.blank?
639
+ if lock_reason_previously_changed? && lock_reason.blank?
576
640
  schedule_merges
577
641
  end
578
642
  end
@@ -581,7 +645,7 @@ module Shipit
581
645
  return unless previous_changes.include?('lock_reason')
582
646
 
583
647
  lock_details = if previous_changes['lock_reason'].last.blank?
584
- {from: previous_changes['locked_since'].first, until: Time.zone.now}
648
+ { from: previous_changes['locked_since'].first, until: Time.zone.now }
585
649
  end
586
650
 
587
651
  Hook.emit(:lock, self, locked: locked?, lock_details: lock_details, stack: self)
@@ -607,5 +671,23 @@ module Shipit
607
671
  def ci_enabled_cache_key
608
672
  "stacks:#{id}:ci_enabled"
609
673
  end
674
+
675
+ def should_resume_continuous_delivery?(commit)
676
+ (deployment_checks_passed? && !deployable?) ||
677
+ deployed_too_recently? ||
678
+ commit.nil? ||
679
+ commit.deployed?
680
+ end
681
+
682
+ def should_delay_continuous_delivery?(commit)
683
+ commit.deploy_failed? ||
684
+ (checks? && !EphemeralCommitChecks.new(commit).run.success?) ||
685
+ !deployment_checks_passed? ||
686
+ commit.recently_pushed?
687
+ end
688
+
689
+ def deployment_checks?
690
+ Shipit.deployment_checks.present?
691
+ end
610
692
  end
611
693
  end