shipit-engine 0.28.1 → 0.33.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 (410) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +41 -2
  3. data/Rakefile +4 -2
  4. data/app/assets/images/archive-solid.svg +1 -0
  5. data/app/assets/images/magic-solid.svg +1 -0
  6. data/app/assets/javascripts/shipit/repositories_search.js.coffee +60 -0
  7. data/app/assets/javascripts/shipit/{search.js.coffee → stack_search.js.coffee} +0 -0
  8. data/app/assets/stylesheets/_pages/_repositories.scss +148 -0
  9. data/app/assets/stylesheets/_pages/_stacks.scss +95 -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 +13 -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 +4 -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 +33 -0
  28. data/app/controllers/shipit/api/stacks_controller.rb +50 -5
  29. data/app/controllers/shipit/api/tasks_controller.rb +6 -5
  30. data/app/controllers/shipit/api_clients_controller.rb +50 -0
  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 +5 -4
  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 +33 -28
  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 +78 -14
  43. data/app/controllers/shipit/status_controller.rb +2 -1
  44. data/app/controllers/shipit/tasks_controller.rb +9 -8
  45. data/app/controllers/shipit/webhooks_controller.rb +5 -132
  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 -0
  51. data/app/helpers/shipit/stacks_helper.rb +9 -0
  52. data/app/helpers/shipit/tasks_helper.rb +1 -0
  53. data/app/jobs/shipit/background_job.rb +4 -0
  54. data/app/jobs/shipit/background_job/unique.rb +4 -1
  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 +3 -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 +1 -0
  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 +5 -4
  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 +2 -1
  70. data/app/jobs/shipit/{mark_deploy_healty_job.rb → 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 -90
  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 +4 -3
  83. data/app/models/concerns/shipit/deferred_touch.rb +4 -3
  84. data/app/models/shipit/anonymous_user.rb +9 -0
  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 +5 -4
  88. data/app/models/shipit/command_line_user.rb +5 -0
  89. data/app/models/shipit/commit.rb +41 -22
  90. data/app/models/shipit/commit_checks.rb +2 -0
  91. data/app/models/shipit/commit_deployment.rb +17 -12
  92. data/app/models/shipit/commit_deployment_status.rb +8 -3
  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 +41 -10
  96. data/app/models/shipit/deploy_spec.rb +38 -7
  97. data/app/models/shipit/deploy_spec/bundler_discovery.rb +2 -1
  98. data/app/models/shipit/deploy_spec/capistrano_discovery.rb +1 -0
  99. data/app/models/shipit/deploy_spec/file_system.rb +20 -7
  100. data/app/models/shipit/deploy_spec/kubernetes_discovery.rb +1 -0
  101. data/app/models/shipit/deploy_spec/lerna_discovery.rb +1 -0
  102. data/app/models/shipit/deploy_spec/npm_discovery.rb +5 -4
  103. data/app/models/shipit/deploy_spec/pypi_discovery.rb +1 -0
  104. data/app/models/shipit/deploy_spec/rubygems_discovery.rb +1 -0
  105. data/app/models/shipit/deploy_stats.rb +58 -0
  106. data/app/models/shipit/duration.rb +3 -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 +8 -5
  111. data/app/models/shipit/membership.rb +3 -2
  112. data/app/models/shipit/merge_request.rb +302 -0
  113. data/app/models/shipit/output_chunk.rb +7 -2
  114. data/app/models/shipit/provisioning_handler.rb +32 -0
  115. data/app/models/shipit/provisioning_handler/base.rb +30 -0
  116. data/app/models/shipit/provisioning_handler/unregistered_provisioning_handler.rb +35 -0
  117. data/app/models/shipit/pull_request.rb +27 -260
  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 +3 -2
  121. data/app/models/shipit/repository.rb +97 -0
  122. data/app/models/shipit/review_stack.rb +116 -0
  123. data/app/models/shipit/review_stack_provisioning_queue.rb +39 -0
  124. data/app/models/shipit/rollback.rb +1 -0
  125. data/app/models/shipit/stack.rb +130 -57
  126. data/app/models/shipit/status.rb +3 -2
  127. data/app/models/shipit/status/common.rb +7 -6
  128. data/app/models/shipit/status/group.rb +1 -0
  129. data/app/models/shipit/status/missing.rb +2 -1
  130. data/app/models/shipit/status/unknown.rb +2 -1
  131. data/app/models/shipit/task.rb +118 -14
  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 +110 -0
  135. data/app/models/shipit/team.rb +2 -1
  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 +15 -8
  139. data/app/models/shipit/variable_definition.rb +1 -0
  140. data/app/models/shipit/webhooks.rb +43 -0
  141. data/app/models/shipit/webhooks/handlers/check_suite_handler.rb +20 -0
  142. data/app/models/shipit/webhooks/handlers/handler.rb +41 -0
  143. data/app/models/shipit/webhooks/handlers/membership_handler.rb +46 -0
  144. data/app/models/shipit/webhooks/handlers/pull_request/assigned_handler.rb +74 -0
  145. data/app/models/shipit/webhooks/handlers/pull_request/closed_handler.rb +68 -0
  146. data/app/models/shipit/webhooks/handlers/pull_request/edited_handler.rb +74 -0
  147. data/app/models/shipit/webhooks/handlers/pull_request/label_capturing_handler.rb +127 -0
  148. data/app/models/shipit/webhooks/handlers/pull_request/labeled_handler.rb +106 -0
  149. data/app/models/shipit/webhooks/handlers/pull_request/opened_handler.rb +83 -0
  150. data/app/models/shipit/webhooks/handlers/pull_request/reopened_handler.rb +88 -0
  151. data/app/models/shipit/webhooks/handlers/pull_request/review_stack_adapter.rb +103 -0
  152. data/app/models/shipit/webhooks/handlers/pull_request/unlabeled_handler.rb +107 -0
  153. data/app/models/shipit/webhooks/handlers/push_handler.rb +21 -0
  154. data/app/models/shipit/webhooks/handlers/status_handler.rb +27 -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 +12 -5
  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 +4 -3
  171. data/app/validators/subset_validator.rb +1 -0
  172. data/app/views/layouts/_head.html.erb +0 -0
  173. data/app/views/layouts/shipit.html.erb +5 -3
  174. data/app/views/shipit/_variables.html.erb +1 -1
  175. data/app/views/shipit/api_clients/index.html.erb +36 -0
  176. data/app/views/shipit/api_clients/new.html.erb +33 -0
  177. data/app/views/shipit/api_clients/show.html.erb +35 -0
  178. data/app/views/shipit/ccmenu/project.xml.builder +2 -1
  179. data/app/views/shipit/deploys/show.html.erb +2 -2
  180. data/app/views/shipit/merge_requests/_merge_request.html.erb +29 -0
  181. data/app/views/shipit/{pull_requests → merge_requests}/index.html.erb +2 -2
  182. data/app/views/shipit/merge_requests/merge_requests/_pull_request.html.erb +29 -0
  183. data/app/views/shipit/merge_requests/merge_requests/index.html.erb +20 -0
  184. data/app/views/shipit/merge_status/_merge_queue_button.html.erb +3 -3
  185. data/app/views/shipit/merge_status/backlogged.html.erb +1 -1
  186. data/app/views/shipit/merge_status/failure.html.erb +1 -1
  187. data/app/views/shipit/merge_status/locked.html.erb +1 -1
  188. data/app/views/shipit/merge_status/logged_out.erb +1 -1
  189. data/app/views/shipit/merge_status/success.html.erb +2 -2
  190. data/app/views/shipit/repositories/_header.html.erb +19 -0
  191. data/app/views/shipit/repositories/index.html.erb +31 -0
  192. data/app/views/shipit/repositories/new.html.erb +23 -0
  193. data/app/views/shipit/repositories/settings.html.erb +53 -0
  194. data/app/views/shipit/repositories/show.html.erb +30 -0
  195. data/app/views/shipit/stacks/_banners.html.erb +13 -0
  196. data/app/views/shipit/stacks/_header.html.erb +30 -12
  197. data/app/views/shipit/stacks/_links.html.erb +1 -0
  198. data/app/views/shipit/stacks/_stack.html.erb +8 -0
  199. data/app/views/shipit/stacks/all_tasks.html.erb +28 -0
  200. data/app/views/shipit/stacks/index.html.erb +9 -3
  201. data/app/views/shipit/stacks/settings.html.erb +22 -3
  202. data/app/views/shipit/stacks/show.html.erb +1 -1
  203. data/app/views/shipit/stacks/statistics.html.erb +82 -0
  204. data/app/views/shipit/tasks/_task_output.html.erb +1 -1
  205. data/app/views/shipit/tasks/show.html.erb +1 -1
  206. data/config/initializers/inflections.rb +2 -1
  207. data/config/locales/en.yml +18 -5
  208. data/config/routes.rb +29 -7
  209. data/db/migrate/20191209231045_create_shipit_repositories.rb +12 -0
  210. data/db/migrate/20191209231307_add_repository_reference_to_stacks.rb +15 -0
  211. data/db/migrate/20191216162728_backfill_repository_data.rb +22 -0
  212. data/db/migrate/20191216163010_remove_repository_information_from_stacks.rb +20 -0
  213. data/db/migrate/20191219205202_add_archived_since_to_stacks.rb +6 -0
  214. data/db/migrate/20200102175621_optional_task_commits.rb +6 -0
  215. data/db/migrate/20200109132519_add_sha_to_commit_deployments.rb +5 -0
  216. data/db/migrate/20200226211925_add_index_to_tasks_status.rb +5 -0
  217. data/db/migrate/20200427135152_add_pull_request_head_sha_to_commit.rb +5 -0
  218. data/db/migrate/20200615181558_add_rollback_once_aborted_to.rb +5 -0
  219. data/db/migrate/20200706145406_add_review_stacks.rb +12 -0
  220. data/db/migrate/20200804144639_rename_pull_request_to_merge_request.rb +7 -0
  221. data/db/migrate/20200804161512_rename_commits_pull_request_id_to_merge_request_id.rb +5 -0
  222. data/db/migrate/20200813134712_recreate_shipit_pull_requests.rb +22 -0
  223. data/db/migrate/20200813194056_create_pull_request_assignments.rb +8 -0
  224. data/db/migrate/20201001125502_add_provision_pr_stacks_flag_to_repositories.rb +7 -0
  225. data/db/migrate/20201008145809_add_retry_attempt_to_tasks.rb +5 -0
  226. data/db/migrate/20201008152744_add_max_retries_to_tasks.rb +5 -0
  227. data/lib/shipit.rb +23 -3
  228. data/lib/shipit/cast_value.rb +1 -0
  229. data/lib/shipit/command.rb +14 -18
  230. data/lib/shipit/commands.rb +5 -4
  231. data/lib/shipit/csv_serializer.rb +1 -0
  232. data/lib/shipit/deploy_commands.rb +1 -0
  233. data/lib/shipit/engine.rb +11 -2
  234. data/lib/shipit/environment_variables.rb +11 -1
  235. data/lib/shipit/first_parent_commits_iterator.rb +1 -0
  236. data/lib/shipit/flock.rb +1 -0
  237. data/lib/shipit/github_app.rb +41 -10
  238. data/lib/shipit/github_http_cache_middleware.rb +1 -0
  239. data/lib/shipit/null_serializer.rb +1 -0
  240. data/lib/shipit/octokit_check_runs.rb +3 -2
  241. data/lib/shipit/octokit_iterator.rb +3 -2
  242. data/lib/shipit/paginator.rb +3 -2
  243. data/lib/shipit/review_stack_commands.rb +8 -0
  244. data/lib/shipit/rollback_commands.rb +1 -0
  245. data/lib/shipit/same_site_cookie_middleware.rb +29 -0
  246. data/lib/shipit/simple_message_verifier.rb +1 -0
  247. data/lib/shipit/stack_commands.rb +12 -4
  248. data/lib/shipit/stat.rb +1 -0
  249. data/lib/shipit/task_commands.rb +23 -14
  250. data/lib/shipit/version.rb +2 -1
  251. data/lib/snippets/release-gem +5 -1
  252. data/lib/tasks/cron.rake +13 -2
  253. data/lib/tasks/dev.rake +3 -2
  254. data/lib/tasks/shipit.rake +16 -17
  255. data/lib/tasks/teams.rake +1 -0
  256. data/test/controllers/api/base_controller_test.rb +3 -2
  257. data/test/controllers/api/ccmenu_controller_test.rb +9 -8
  258. data/test/controllers/api/commits_controller_test.rb +3 -2
  259. data/test/controllers/api/deploys_controller_test.rb +15 -14
  260. data/test/controllers/api/hooks_controller_test.rb +8 -7
  261. data/test/controllers/api/locks_controller_test.rb +7 -6
  262. data/test/controllers/api/{pull_requests_controller_test.rb → merge_requests_controller_test.rb} +17 -16
  263. data/test/controllers/api/outputs_controller_test.rb +4 -2
  264. data/test/controllers/api/release_statuses_controller_test.rb +2 -1
  265. data/test/controllers/api/rollback_controller_test.rb +113 -0
  266. data/test/controllers/api/stacks_controller_test.rb +65 -16
  267. data/test/controllers/api/tasks_controller_test.rb +13 -12
  268. data/test/controllers/api_clients_controller_test.rb +104 -0
  269. data/test/controllers/ccmenu_controller_test.rb +4 -3
  270. data/test/controllers/commit_checks_controller_test.rb +4 -3
  271. data/test/controllers/commits_controller_test.rb +3 -2
  272. data/test/controllers/deploys_controller_test.rb +33 -22
  273. data/test/controllers/github_authentication_controller_test.rb +1 -0
  274. data/test/controllers/merge_requests_controller_test.rb +32 -0
  275. data/test/controllers/merge_status_controller_test.rb +27 -9
  276. data/test/controllers/release_statuses_controller_test.rb +3 -2
  277. data/test/controllers/repositories_controller_test.rb +71 -0
  278. data/test/controllers/rollbacks_controller_test.rb +9 -8
  279. data/test/controllers/stacks_controller_test.rb +72 -15
  280. data/test/controllers/status_controller_test.rb +1 -0
  281. data/test/controllers/tasks_controller_test.rb +33 -20
  282. data/test/controllers/webhooks_controller_test.rb +36 -9
  283. data/test/dummy/config/application.rb +7 -2
  284. data/test/dummy/config/environments/development.rb +23 -6
  285. data/test/dummy/config/environments/test.rb +2 -5
  286. data/test/dummy/db/schema.rb +76 -24
  287. data/test/dummy/db/seeds.rb +30 -16
  288. data/test/fixtures/payloads/check_suite_master.json +2 -2
  289. data/test/fixtures/payloads/invalid_pull_request.json +117 -0
  290. data/test/fixtures/payloads/provision_disabled_pull_request.json +454 -0
  291. data/test/fixtures/payloads/pull_request_assigned.json +480 -0
  292. data/test/fixtures/payloads/pull_request_closed.json +454 -0
  293. data/test/fixtures/payloads/pull_request_labeled.json +461 -0
  294. data/test/fixtures/payloads/pull_request_opened.json +454 -0
  295. data/test/fixtures/payloads/pull_request_reopened.json +454 -0
  296. data/test/fixtures/payloads/pull_request_unlabeled.json +454 -0
  297. data/test/fixtures/payloads/pull_request_with_no_repo.json +454 -0
  298. data/test/fixtures/shipit/commit_deployment_statuses.yml +4 -4
  299. data/test/fixtures/shipit/commit_deployments.yml +8 -8
  300. data/test/fixtures/shipit/commits.yml +52 -1
  301. data/test/fixtures/shipit/merge_requests.yml +141 -0
  302. data/test/fixtures/shipit/pull_request_assignments.yml +3 -0
  303. data/test/fixtures/shipit/pull_requests.yml +10 -131
  304. data/test/fixtures/shipit/repositories.yml +28 -0
  305. data/test/fixtures/shipit/stacks.yml +335 -30
  306. data/test/fixtures/shipit/statuses.yml +9 -0
  307. data/test/fixtures/shipit/tasks.yml +69 -3
  308. data/test/fixtures/shipit/users.yml +7 -0
  309. data/test/fixtures/timeout +2 -1
  310. data/test/helpers/api_helper.rb +1 -0
  311. data/test/helpers/fixture_aliases_helper.rb +1 -0
  312. data/test/helpers/hooks_helper.rb +2 -1
  313. data/test/helpers/json_helper.rb +15 -11
  314. data/test/helpers/links_helper.rb +4 -3
  315. data/test/helpers/payloads_helper.rb +5 -0
  316. data/test/helpers/queries_helper.rb +3 -2
  317. data/test/jobs/cache_deploy_spec_job_test.rb +2 -1
  318. data/test/jobs/chunk_rollup_job_test.rb +16 -1
  319. data/test/jobs/deliver_hook_job_test.rb +1 -0
  320. data/test/jobs/destroy_repository_job_test.rb +27 -0
  321. data/test/jobs/destroy_stack_job_test.rb +10 -0
  322. data/test/jobs/emit_event_job_test.rb +2 -1
  323. data/test/jobs/fetch_commit_stats_job_test.rb +1 -0
  324. data/test/jobs/fetch_deployed_revision_job_test.rb +1 -0
  325. data/test/jobs/github_sync_job_test.rb +1 -0
  326. data/test/jobs/mark_deploy_healthy_job_test.rb +1 -0
  327. data/test/jobs/perform_task_job_test.rb +12 -11
  328. data/test/jobs/{merge_pull_requests_job_test.rb → process_merge_requests_job_test.rb} +19 -18
  329. data/test/jobs/purge_old_deliveries_job_test.rb +1 -0
  330. data/test/jobs/reap_dead_tasks_job_test.rb +68 -0
  331. data/test/jobs/refresh_github_user_job_test.rb +1 -0
  332. data/test/jobs/refresh_status_job_test.rb +1 -0
  333. data/test/jobs/unique_job_test.rb +1 -0
  334. data/test/jobs/update_github_last_deployed_ref_job_test.rb +1 -0
  335. data/test/lib/shipit/deploy_commands_test.rb +16 -0
  336. data/test/lib/shipit/task_commands_test.rb +17 -0
  337. data/test/middleware/same_site_cookie_middleware_test.rb +52 -0
  338. data/test/models/api_client_test.rb +1 -0
  339. data/test/models/commit_checks_test.rb +1 -0
  340. data/test/models/commit_deployment_status_test.rb +34 -4
  341. data/test/models/commit_deployment_test.rb +9 -11
  342. data/test/models/commits_test.rb +116 -21
  343. data/test/models/delivery_test.rb +2 -1
  344. data/test/models/deploy_spec_test.rb +103 -65
  345. data/test/models/deploy_stats_test.rb +113 -0
  346. data/test/models/deploys_test.rb +207 -26
  347. data/test/models/duration_test.rb +1 -0
  348. data/test/models/github_hook_test.rb +1 -0
  349. data/test/models/hook_test.rb +20 -16
  350. data/test/models/membership_test.rb +1 -0
  351. data/test/models/{pull_request_test.rb → merge_request_test.rb} +48 -41
  352. data/test/models/pull_request_assignment_test.rb +16 -0
  353. data/test/models/release_statuses_test.rb +1 -0
  354. data/test/models/rollbacks_test.rb +1 -0
  355. data/test/models/shipit/check_run_test.rb +1 -0
  356. data/test/models/shipit/provisioning_handler/base_test.rb +33 -0
  357. data/test/models/shipit/provisioning_handler/unregistered_provisioning_handler_test.rb +49 -0
  358. data/test/models/shipit/provisioning_handler_test.rb +64 -0
  359. data/test/models/shipit/pull_request_test.rb +52 -0
  360. data/test/models/shipit/repository_test.rb +81 -0
  361. data/test/models/shipit/review_stack_provision_status_test.rb +77 -0
  362. data/test/models/shipit/review_stack_provisioning_queue_test.rb +63 -0
  363. data/test/models/shipit/review_stack_test.rb +59 -0
  364. data/test/models/{stacks_test.rb → shipit/stacks_test.rb} +120 -60
  365. data/test/models/shipit/webhooks/handlers/pull_request/assigned_handler_test.rb +45 -0
  366. data/test/models/shipit/webhooks/handlers/pull_request/closed_handler_test.rb +192 -0
  367. data/test/models/shipit/webhooks/handlers/pull_request/edited_handler_test.rb +47 -0
  368. data/test/models/shipit/webhooks/handlers/pull_request/label_capturing_handler_test.rb +209 -0
  369. data/test/models/shipit/webhooks/handlers/pull_request/labeled_handler_test.rb +332 -0
  370. data/test/models/shipit/webhooks/handlers/pull_request/opened_handler_test.rb +238 -0
  371. data/test/models/shipit/webhooks/handlers/pull_request/reopened_handler_test.rb +282 -0
  372. data/test/models/shipit/webhooks/handlers/pull_request/review_stack_adapter_test.rb +83 -0
  373. data/test/models/shipit/webhooks/handlers/pull_request/unlabeled_handler_test.rb +324 -0
  374. data/test/models/shipit/webhooks/handlers_test.rb +27 -0
  375. data/test/models/status/group_test.rb +1 -0
  376. data/test/models/status/missing_test.rb +1 -0
  377. data/test/models/status_test.rb +1 -0
  378. data/test/models/task_definitions_test.rb +9 -8
  379. data/test/models/tasks_test.rb +59 -1
  380. data/test/models/team_test.rb +4 -2
  381. data/test/models/undeployed_commits_test.rb +14 -0
  382. data/test/models/users_test.rb +13 -5
  383. data/test/serializers/shipit/pull_request_serializer_test.rb +29 -0
  384. data/test/test_command_integration.rb +3 -2
  385. data/test/test_helper.rb +37 -32
  386. data/test/unit/anonymous_user_serializer_test.rb +14 -0
  387. data/test/unit/command_test.rb +15 -10
  388. data/test/unit/commands_test.rb +1 -0
  389. data/test/unit/commit_serializer_test.rb +16 -0
  390. data/test/unit/csv_serializer_test.rb +3 -2
  391. data/test/unit/deploy_commands_test.rb +14 -4
  392. data/test/unit/deploy_serializer_test.rb +17 -0
  393. data/test/unit/environment_variables_test.rb +5 -4
  394. data/test/unit/github_app_test.rb +137 -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_helper_test.rb +17 -0
  398. data/test/unit/shipit_task_execution_strategy_test.rb +47 -0
  399. data/test/unit/shipit_test.rb +1 -0
  400. data/test/unit/user_serializer_test.rb +14 -0
  401. data/test/unit/variable_definition_test.rb +1 -0
  402. metadata +334 -169
  403. data/app/controllers/shipit/api/pull_requests_controller.rb +0 -36
  404. data/app/controllers/shipit/pull_requests_controller.rb +0 -30
  405. data/app/jobs/shipit/merge_pull_requests_job.rb +0 -31
  406. data/app/jobs/shipit/refresh_pull_request_job.rb +0 -10
  407. data/app/views/shipit/pull_requests/_pull_request.html.erb +0 -29
  408. data/test/controllers/pull_requests_controller_test.rb +0 -31
  409. data/test/fixtures/shipit/output_chunks.yml +0 -47
  410. data/test/models/output_chunk_test.rb +0 -20
@@ -1,15 +1,16 @@
1
+ # frozen_string_literal: true
1
2
  module Shipit
2
3
  class Duration < ActiveSupport::Duration
3
4
  ParseError = Class.new(ArgumentError)
4
5
 
5
- FORMAT = /
6
+ FORMAT = %r{
6
7
  \A
7
8
  (?<days>\d+d)?
8
9
  (?<hours>\d+h)?
9
10
  (?<minutes>\d+m)?
10
11
  (?<seconds>\d+s?)?
11
12
  \z
12
- /x
13
+ }x
13
14
  UNITS = {
14
15
  's' => :seconds,
15
16
  'm' => :minutes,
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Shipit
2
3
  class EphemeralCommitChecks
3
4
  FINAL_STATUSES = %w(failed error success).freeze
@@ -1,5 +1,6 @@
1
+ # frozen_string_literal: true
1
2
  module Shipit
2
- class GithubHook < ActiveRecord::Base
3
+ class GithubHook < Record
3
4
  # TODO: app-migration, delete class
4
5
  belongs_to :stack, required: false # Required for fixtures
5
6
 
@@ -1,6 +1,7 @@
1
+ # frozen_string_literal: true
1
2
  module Shipit
2
3
  module GithubStatus
3
- CACHE_KEY = 'github::status'.freeze
4
+ CACHE_KEY = 'github::status'
4
5
 
5
6
  class << self
6
7
  def status
@@ -1,5 +1,6 @@
1
+ # frozen_string_literal: true
1
2
  module Shipit
2
- class Hook < ActiveRecord::Base
3
+ class Hook < Record
3
4
  class DeliverySpec
4
5
  def initialize(event:, url:, content_type:, payload:)
5
6
  @event = event
@@ -19,7 +20,7 @@ module Shipit
19
20
  def http
20
21
  Faraday::Connection.new do |connection|
21
22
  connection.headers = headers
22
- connection.adapter Faraday.default_adapter
23
+ connection.adapter(Faraday.default_adapter)
23
24
  end
24
25
  end
25
26
 
@@ -44,6 +45,7 @@ module Shipit
44
45
 
45
46
  EVENTS = %w(
46
47
  stack
48
+ review_stack
47
49
  task
48
50
  deploy
49
51
  rollback
@@ -52,14 +54,15 @@ module Shipit
52
54
  deployable_status
53
55
  merge_status
54
56
  merge
57
+ pull_request
55
58
  ).freeze
56
59
 
57
60
  belongs_to :stack, required: false
58
61
  has_many :deliveries
59
62
 
60
- validates :delivery_url, presence: true, url: {no_local: true, allow_blank: true}
61
- validates :content_type, presence: true, inclusion: {in: CONTENT_TYPES.keys}
62
- validates :events, presence: true, subset: {of: EVENTS}
63
+ validates :delivery_url, presence: true, url: { no_local: true, allow_blank: true }
64
+ validates :content_type, presence: true, inclusion: { in: CONTENT_TYPES.keys }
65
+ validates :events, presence: true, subset: { of: EVENTS }
63
66
 
64
67
  serialize :events, Shipit::CSVSerializer
65
68
 
@@ -1,8 +1,9 @@
1
+ # frozen_string_literal: true
1
2
  module Shipit
2
- class Membership < ActiveRecord::Base
3
+ class Membership < Record
3
4
  belongs_to :team, required: true
4
5
  belongs_to :user, required: true
5
6
 
6
- validates :user_id, uniqueness: {scope: :team_id}
7
+ validates :user_id, uniqueness: { scope: :team_id }
7
8
  end
8
9
  end
@@ -0,0 +1,302 @@
1
+ # frozen_string_literal: true
2
+ module Shipit
3
+ class MergeRequest < ApplicationRecord
4
+ include DeferredTouch
5
+
6
+ MERGE_REQUEST_FIELD = 'Merge-Requested-By'
7
+
8
+ WAITING_STATUSES = %w(fetching pending).freeze
9
+ QUEUED_STATUSES = %w(pending revalidating).freeze
10
+ REJECTION_REASONS = %w(ci_missing ci_failing merge_conflict requires_rebase).freeze
11
+ InvalidTransition = Class.new(StandardError)
12
+ NotReady = Class.new(StandardError)
13
+
14
+ class StatusChecker < Status::Group
15
+ def initialize(commit, statuses, deploy_spec)
16
+ @deploy_spec = deploy_spec
17
+ super(commit, statuses)
18
+ end
19
+
20
+ private
21
+
22
+ attr_reader :deploy_spec
23
+
24
+ def reject_hidden(statuses)
25
+ statuses.reject { |s| ignored_statuses.include?(s.context) }
26
+ end
27
+
28
+ def reject_allowed_to_fail(statuses)
29
+ statuses.reject { |s| ignored_statuses.include?(s.context) }
30
+ end
31
+
32
+ def ignored_statuses
33
+ deploy_spec&.merge_request_ignored_statuses || []
34
+ end
35
+
36
+ def required_statuses
37
+ deploy_spec&.merge_request_required_statuses || []
38
+ end
39
+ end
40
+
41
+ belongs_to :stack
42
+ belongs_to :head, class_name: 'Shipit::Commit', optional: true
43
+ belongs_to :base_commit, class_name: 'Shipit::Commit', optional: true
44
+ belongs_to :merge_requested_by, class_name: 'Shipit::User', optional: true
45
+ has_one :merge_commit, class_name: 'Shipit::Commit'
46
+
47
+ deferred_touch stack: :updated_at
48
+
49
+ validates :number, presence: true, uniqueness: { scope: :stack_id }
50
+
51
+ scope :waiting, -> { where(merge_status: WAITING_STATUSES) }
52
+ scope :pending, -> { where(merge_status: 'pending') }
53
+ scope :to_be_merged, -> { pending.order(merge_requested_at: :asc) }
54
+ scope :queued, -> { where(merge_status: QUEUED_STATUSES).order(merge_requested_at: :asc) }
55
+
56
+ after_save :record_merge_status_change
57
+ after_commit :emit_hooks
58
+
59
+ state_machine :merge_status, initial: :fetching do
60
+ state :fetching
61
+ state :pending
62
+ state :rejected
63
+ state :canceled
64
+ state :merged
65
+ state :revalidating
66
+
67
+ event :fetched do
68
+ transition fetching: :pending
69
+ end
70
+
71
+ event :reject do
72
+ transition pending: :rejected
73
+ end
74
+
75
+ event :revalidate do
76
+ transition pending: :revalidating
77
+ end
78
+
79
+ event :cancel do
80
+ transition any => :canceled
81
+ end
82
+
83
+ event :complete do
84
+ transition pending: :merged
85
+ end
86
+
87
+ event :retry do
88
+ transition %i(rejected canceled revalidating) => :pending
89
+ end
90
+
91
+ before_transition rejected: any do |pr|
92
+ pr.rejection_reason = nil
93
+ end
94
+
95
+ before_transition %i(fetching rejected canceled) => :pending do |pr|
96
+ pr.merge_requested_at = Time.now.utc
97
+ end
98
+
99
+ before_transition any => :pending do |pr|
100
+ pr.revalidated_at = Time.now.utc
101
+ end
102
+
103
+ before_transition %i(pending) => :merged do |pr|
104
+ Stack.increment_counter(:undeployed_commits_count, pr.stack_id)
105
+ end
106
+ end
107
+
108
+ def self.schedule_merges
109
+ Shipit::Stack.where(merge_queue_enabled: true).find_each(&:schedule_merges)
110
+ end
111
+
112
+ def self.extract_number(stack, number_or_url)
113
+ case number_or_url
114
+ when /\A#?(\d+)\z/
115
+ $1.to_i
116
+ when %r{\Ahttps://#{Regexp.escape(Shipit.github.domain)}/([^/]+)/([^/]+)/pull/(\d+)}
117
+ return unless $1.downcase == stack.repo_owner.downcase
118
+ return unless $2.downcase == stack.repo_name.downcase
119
+ $3.to_i
120
+ end
121
+ end
122
+
123
+ def self.request_merge!(stack, number, user)
124
+ now = Time.now.utc
125
+ merge_request = begin
126
+ create_with(
127
+ merge_requested_at: now,
128
+ merge_requested_by: user.presence,
129
+ ).find_or_create_by!(
130
+ stack: stack,
131
+ number: number,
132
+ )
133
+ rescue ActiveRecord::RecordNotUnique
134
+ retry
135
+ end
136
+ merge_request.update!(merge_requested_by: user.presence)
137
+ merge_request.retry! if merge_request.rejected? || merge_request.canceled? || merge_request.revalidating?
138
+ merge_request.schedule_refresh!
139
+ merge_request
140
+ end
141
+
142
+ def reject!(reason)
143
+ unless REJECTION_REASONS.include?(reason)
144
+ raise ArgumentError, "invalid reason: #{reason.inspect}, must be one of: #{REJECTION_REASONS.inspect}"
145
+ end
146
+ self.rejection_reason = reason.presence
147
+ super()
148
+ true
149
+ end
150
+
151
+ def reject_unless_mergeable!
152
+ return reject!('merge_conflict') if merge_conflict?
153
+ return reject!('ci_missing') if any_status_checks_missing?
154
+ return reject!('ci_failing') if any_status_checks_failed?
155
+ return reject!('requires_rebase') if stale?
156
+ false
157
+ end
158
+
159
+ def merge!
160
+ raise InvalidTransition unless pending?
161
+
162
+ raise NotReady if not_mergeable_yet?
163
+
164
+ Shipit.github.api.merge_pull_request(
165
+ stack.github_repo_name,
166
+ number,
167
+ merge_message,
168
+ sha: head.sha,
169
+ commit_message: 'Merged by Shipit',
170
+ merge_method: stack.merge_method,
171
+ )
172
+ begin
173
+ if Shipit.github.api.pull_requests(stack.github_repo_name, base: branch).empty?
174
+ Shipit.github.api.delete_branch(stack.github_repo_name, branch)
175
+ end
176
+ rescue Octokit::UnprocessableEntity
177
+ # branch was already deleted somehow
178
+ end
179
+ complete!
180
+ true
181
+ rescue Octokit::MethodNotAllowed # merge conflict
182
+ reject!('merge_conflict')
183
+ false
184
+ rescue Octokit::Conflict # shas didn't match, PR was updated.
185
+ raise NotReady
186
+ end
187
+
188
+ def all_status_checks_passed?
189
+ return false unless head
190
+ StatusChecker.new(head, head.statuses_and_check_runs, stack.cached_deploy_spec).success?
191
+ end
192
+
193
+ def any_status_checks_failed?
194
+ status = StatusChecker.new(head, head.statuses_and_check_runs, stack.cached_deploy_spec)
195
+ status.failure? || status.error?
196
+ end
197
+
198
+ def any_status_checks_missing?
199
+ StatusChecker.new(head, head.statuses_and_check_runs, stack.cached_deploy_spec).missing?
200
+ end
201
+
202
+ def waiting?
203
+ WAITING_STATUSES.include?(merge_status)
204
+ end
205
+
206
+ def need_revalidation?
207
+ timeout = stack.cached_deploy_spec&.revalidate_merge_requests_after
208
+ return false unless timeout
209
+ (revalidated_at + timeout).past?
210
+ end
211
+
212
+ def merge_conflict?
213
+ mergeable == false
214
+ end
215
+
216
+ def not_mergeable_yet?
217
+ mergeable.nil?
218
+ end
219
+
220
+ def schedule_refresh!
221
+ RefreshMergeRequestJob.perform_later(self)
222
+ end
223
+
224
+ def closed?
225
+ state == "closed"
226
+ end
227
+
228
+ def merged_upstream?
229
+ closed? && merged_at
230
+ end
231
+
232
+ def refresh!
233
+ update!(github_pull_request: Shipit.github.api.pull_request(stack.github_repo_name, number))
234
+ head.refresh_statuses!
235
+ fetched! if fetching?
236
+ @comparison = nil
237
+ end
238
+
239
+ def github_pull_request=(github_pull_request)
240
+ self.github_id = github_pull_request.id
241
+ self.api_url = github_pull_request.url
242
+ self.title = github_pull_request.title
243
+ self.state = github_pull_request.state
244
+ self.mergeable = github_pull_request.mergeable
245
+ self.additions = github_pull_request.additions
246
+ self.deletions = github_pull_request.deletions
247
+ self.branch = github_pull_request.head.ref
248
+ self.head = find_or_create_commit_from_github_by_sha!(github_pull_request.head.sha, detached: true)
249
+ self.merged_at = github_pull_request.merged_at
250
+ self.base_ref = github_pull_request.base.ref
251
+ self.base_commit = find_or_create_commit_from_github_by_sha!(github_pull_request.base.sha, detached: true)
252
+ end
253
+
254
+ def merge_message
255
+ return title unless merge_requested_by
256
+ "#{title}\n\n#{MERGE_REQUEST_FIELD}: #{merge_requested_by.login}\n"
257
+ end
258
+
259
+ def stale?
260
+ return false unless base_commit
261
+ spec = stack.cached_deploy_spec
262
+ if max_branch_age = spec.max_divergence_age
263
+ return true if Time.now.utc - head.committed_at > max_branch_age
264
+ end
265
+ if commit_count_limit = spec.max_divergence_commits
266
+ return true if comparison.behind_by > commit_count_limit
267
+ end
268
+ false
269
+ end
270
+
271
+ def comparison
272
+ @comparison ||= Shipit.github.api.compare(
273
+ stack.github_repo_name,
274
+ base_ref,
275
+ head.sha,
276
+ )
277
+ end
278
+
279
+ private
280
+
281
+ def record_merge_status_change
282
+ @merge_status_changed ||= saved_change_to_attribute?(:merge_status)
283
+ end
284
+
285
+ def emit_hooks
286
+ return unless @merge_status_changed
287
+ @merge_status_changed = nil
288
+ Hook.emit('merge', stack, merge_request: self, status: merge_status, stack: stack)
289
+ end
290
+
291
+ def find_or_create_commit_from_github_by_sha!(sha, attributes)
292
+ if commit = stack.commits.by_sha(sha)
293
+ commit
294
+ else
295
+ github_commit = Shipit.github.api.commit(stack.github_repo_name, sha)
296
+ stack.commits.create_from_github!(github_commit, attributes)
297
+ end
298
+ rescue ActiveRecord::RecordNotUnique
299
+ retry
300
+ end
301
+ end
302
+ end
@@ -1,11 +1,16 @@
1
+ # frozen_string_literal: true
1
2
  module Shipit
2
- class OutputChunk < ActiveRecord::Base
3
+ class OutputChunk < Record
3
4
  belongs_to :task
4
5
 
5
6
  scope :tail, ->(start) { order(id: :asc).where('id > ?', start || 0) }
6
7
 
7
8
  def text=(string)
8
- super(string.force_encoding(Encoding::UTF_8).scrub)
9
+ if string.frozen?
10
+ super(string)
11
+ else
12
+ super(string.force_encoding(Encoding::UTF_8).scrub)
13
+ end
9
14
  end
10
15
  end
11
16
  end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shipit
4
+ module ProvisioningHandler
5
+ class << self
6
+ def registry
7
+ @registry ||= reset_registry!
8
+ end
9
+
10
+ def reset_registry!
11
+ @registry = {}
12
+ end
13
+
14
+ def register(handler_class)
15
+ registry[handler_class.to_s] = handler_class
16
+ end
17
+
18
+ def fetch(name)
19
+ return default if name.blank?
20
+ registry.fetch(name) { ProvisioningHandler::UnregisteredProvisioningHandler }
21
+ end
22
+
23
+ def default=(handler_class)
24
+ registry[:default] = handler_class
25
+ end
26
+
27
+ def default
28
+ registry.fetch(:default) { ProvisioningHandler::Base }
29
+ end
30
+ end
31
+ end
32
+ end