shipit-engine 0.30.0 → 0.34.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 +19 -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 +0 -2
  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.rb +4 -0
  54. data/app/jobs/shipit/background_job/unique.rb +1 -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.rb +38 -7
  97. data/app/models/shipit/deploy_spec/bundler_discovery.rb +1 -0
  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 +13 -4
  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 +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.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 +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 +1 -0
  125. data/app/models/shipit/stack.rb +144 -44
  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 +2 -1
  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 +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.rb +11 -0
  141. data/app/models/shipit/webhooks/handlers/check_suite_handler.rb +1 -0
  142. data/app/models/shipit/webhooks/handlers/handler.rb +1 -0
  143. data/app/models/shipit/webhooks/handlers/membership_handler.rb +1 -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 +5 -1
  154. data/app/models/shipit/webhooks/handlers/status_handler.rb +1 -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 +20 -7
  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 +4 -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/lib/shipit.rb +61 -17
  220. data/lib/shipit/cast_value.rb +1 -0
  221. data/lib/shipit/command.rb +20 -21
  222. data/lib/shipit/commands.rb +14 -6
  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 +11 -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 +37 -7
  240. data/lib/shipit/stat.rb +1 -0
  241. data/lib/shipit/task_commands.rb +23 -16
  242. data/lib/shipit/version.rb +2 -1
  243. data/lib/snippets/publish-lerna-independent-packages +35 -34
  244. data/lib/snippets/publish-lerna-independent-packages-legacy +39 -0
  245. data/lib/snippets/release-gem +5 -1
  246. data/lib/tasks/cron.rake +13 -2
  247. data/lib/tasks/dev.rake +3 -2
  248. data/lib/tasks/shipit.rake +15 -14
  249. data/lib/tasks/teams.rake +1 -0
  250. data/test/controllers/api/base_controller_test.rb +3 -2
  251. data/test/controllers/api/ccmenu_controller_test.rb +9 -8
  252. data/test/controllers/api/commits_controller_test.rb +3 -2
  253. data/test/controllers/api/deploys_controller_test.rb +32 -14
  254. data/test/controllers/api/hooks_controller_test.rb +8 -7
  255. data/test/controllers/api/locks_controller_test.rb +7 -6
  256. data/test/controllers/api/{pull_requests_controller_test.rb → merge_requests_controller_test.rb} +17 -16
  257. data/test/controllers/api/outputs_controller_test.rb +3 -1
  258. data/test/controllers/api/release_statuses_controller_test.rb +2 -1
  259. data/test/controllers/api/rollback_controller_test.rb +113 -0
  260. data/test/controllers/api/stacks_controller_test.rb +71 -16
  261. data/test/controllers/api/tasks_controller_test.rb +13 -12
  262. data/test/controllers/api_clients_controller_test.rb +5 -4
  263. data/test/controllers/ccmenu_controller_test.rb +4 -3
  264. data/test/controllers/commit_checks_controller_test.rb +4 -3
  265. data/test/controllers/commits_controller_test.rb +3 -2
  266. data/test/controllers/deploys_controller_test.rb +32 -21
  267. data/test/controllers/github_authentication_controller_test.rb +1 -0
  268. data/test/controllers/merge_requests_controller_test.rb +32 -0
  269. data/test/controllers/merge_status_controller_test.rb +7 -6
  270. data/test/controllers/release_statuses_controller_test.rb +3 -2
  271. data/test/controllers/repositories_controller_test.rb +71 -0
  272. data/test/controllers/rollbacks_controller_test.rb +9 -8
  273. data/test/controllers/stacks_controller_test.rb +41 -19
  274. data/test/controllers/status_controller_test.rb +1 -0
  275. data/test/controllers/tasks_controller_test.rb +32 -19
  276. data/test/controllers/webhooks_controller_test.rb +33 -17
  277. data/test/dummy/app/assets/config/manifest.js +3 -0
  278. data/test/dummy/config/application.rb +7 -2
  279. data/test/dummy/config/database.yml +9 -0
  280. data/test/dummy/config/environments/development.rb +3 -4
  281. data/test/dummy/config/environments/test.rb +2 -5
  282. data/test/dummy/config/secrets_double_github_app.yml +79 -0
  283. data/test/dummy/db/schema.rb +59 -17
  284. data/test/dummy/db/seeds.rb +2 -1
  285. data/test/fixtures/payloads/check_suite_master.json +4 -32
  286. data/test/fixtures/payloads/invalid_pull_request.json +117 -0
  287. data/test/fixtures/payloads/provision_disabled_pull_request.json +454 -0
  288. data/test/fixtures/payloads/pull_request_assigned.json +480 -0
  289. data/test/fixtures/payloads/pull_request_closed.json +454 -0
  290. data/test/fixtures/payloads/pull_request_labeled.json +461 -0
  291. data/test/fixtures/payloads/pull_request_opened.json +454 -0
  292. data/test/fixtures/payloads/pull_request_reopened.json +454 -0
  293. data/test/fixtures/payloads/pull_request_unlabeled.json +454 -0
  294. data/test/fixtures/payloads/pull_request_with_no_repo.json +454 -0
  295. data/test/fixtures/payloads/push_master.json +1 -1
  296. data/test/fixtures/payloads/push_not_master.json +1 -1
  297. data/test/fixtures/shipit/commits.yml +31 -3
  298. data/test/fixtures/shipit/hooks.yml +1 -0
  299. data/test/fixtures/shipit/merge_requests.yml +141 -0
  300. data/test/fixtures/shipit/pull_request_assignments.yml +3 -0
  301. data/test/fixtures/shipit/pull_requests.yml +10 -131
  302. data/test/fixtures/shipit/repositories.yml +5 -0
  303. data/test/fixtures/shipit/stacks.yml +235 -14
  304. data/test/fixtures/shipit/statuses.yml +9 -0
  305. data/test/fixtures/shipit/tasks.yml +4 -1
  306. data/test/fixtures/shipit/users.yml +7 -0
  307. data/test/fixtures/timeout +2 -1
  308. data/test/helpers/api_helper.rb +1 -0
  309. data/test/helpers/fixture_aliases_helper.rb +1 -0
  310. data/test/helpers/hooks_helper.rb +2 -1
  311. data/test/helpers/json_helper.rb +20 -12
  312. data/test/helpers/links_helper.rb +4 -3
  313. data/test/helpers/payloads_helper.rb +5 -0
  314. data/test/helpers/queries_helper.rb +3 -2
  315. data/test/jobs/cache_deploy_spec_job_test.rb +2 -1
  316. data/test/jobs/chunk_rollup_job_test.rb +16 -1
  317. data/test/jobs/deliver_hook_job_test.rb +1 -0
  318. data/test/jobs/destroy_repository_job_test.rb +27 -0
  319. data/test/jobs/destroy_stack_job_test.rb +1 -0
  320. data/test/jobs/emit_event_job_test.rb +2 -1
  321. data/test/jobs/fetch_commit_stats_job_test.rb +1 -0
  322. data/test/jobs/fetch_deployed_revision_job_test.rb +1 -0
  323. data/test/jobs/github_sync_job_test.rb +3 -1
  324. data/test/jobs/mark_deploy_healthy_job_test.rb +1 -0
  325. data/test/jobs/perform_task_job_test.rb +12 -11
  326. data/test/jobs/{merge_pull_requests_job_test.rb → process_merge_requests_job_test.rb} +19 -18
  327. data/test/jobs/purge_old_deliveries_job_test.rb +1 -0
  328. data/test/jobs/reap_dead_tasks_job_test.rb +68 -0
  329. data/test/jobs/refresh_github_user_job_test.rb +1 -0
  330. data/test/jobs/refresh_status_job_test.rb +1 -0
  331. data/test/jobs/unique_job_test.rb +1 -0
  332. data/test/jobs/update_github_last_deployed_ref_job_test.rb +1 -0
  333. data/test/lib/shipit/deploy_commands_test.rb +16 -0
  334. data/test/lib/shipit/task_commands_test.rb +17 -0
  335. data/test/middleware/same_site_cookie_middleware_test.rb +52 -0
  336. data/test/models/api_client_test.rb +1 -0
  337. data/test/models/commit_checks_test.rb +1 -0
  338. data/test/models/commit_deployment_status_test.rb +4 -3
  339. data/test/models/commit_deployment_test.rb +2 -1
  340. data/test/models/commits_test.rb +96 -19
  341. data/test/models/delivery_test.rb +2 -1
  342. data/test/models/deploy_spec_test.rb +110 -65
  343. data/test/models/deploy_stats_test.rb +1 -0
  344. data/test/models/deploys_test.rb +197 -36
  345. data/test/models/duration_test.rb +1 -0
  346. data/test/models/github_hook_test.rb +1 -0
  347. data/test/models/hook_test.rb +47 -10
  348. data/test/models/membership_test.rb +1 -0
  349. data/test/models/{pull_request_test.rb → merge_request_test.rb} +53 -37
  350. data/test/models/pull_request_assignment_test.rb +16 -0
  351. data/test/models/release_statuses_test.rb +1 -0
  352. data/test/models/rollbacks_test.rb +1 -0
  353. data/test/models/shipit/check_run_test.rb +125 -5
  354. data/test/models/shipit/provisioning_handler/base_test.rb +33 -0
  355. data/test/models/shipit/provisioning_handler/unregistered_provisioning_handler_test.rb +49 -0
  356. data/test/models/shipit/provisioning_handler_test.rb +64 -0
  357. data/test/models/shipit/pull_request_test.rb +52 -0
  358. data/test/models/shipit/repository_test.rb +6 -1
  359. data/test/models/shipit/review_stack_provision_status_test.rb +77 -0
  360. data/test/models/shipit/review_stack_provisioning_queue_test.rb +63 -0
  361. data/test/models/shipit/review_stack_test.rb +91 -0
  362. data/test/models/{stacks_test.rb → shipit/stacks_test.rb} +121 -16
  363. data/test/models/shipit/webhooks/handlers/pull_request/assigned_handler_test.rb +45 -0
  364. data/test/models/shipit/webhooks/handlers/pull_request/closed_handler_test.rb +192 -0
  365. data/test/models/shipit/webhooks/handlers/pull_request/edited_handler_test.rb +47 -0
  366. data/test/models/shipit/webhooks/handlers/pull_request/label_capturing_handler_test.rb +209 -0
  367. data/test/models/shipit/webhooks/handlers/pull_request/labeled_handler_test.rb +332 -0
  368. data/test/models/shipit/webhooks/handlers/pull_request/opened_handler_test.rb +238 -0
  369. data/test/models/shipit/webhooks/handlers/pull_request/reopened_handler_test.rb +282 -0
  370. data/test/models/shipit/webhooks/handlers/pull_request/review_stack_adapter_test.rb +107 -0
  371. data/test/models/shipit/webhooks/handlers/pull_request/unlabeled_handler_test.rb +324 -0
  372. data/test/models/shipit/{wehbooks → webhooks}/handlers_test.rb +1 -0
  373. data/test/models/status/group_test.rb +1 -0
  374. data/test/models/status/missing_test.rb +1 -0
  375. data/test/models/status_test.rb +1 -0
  376. data/test/models/task_definitions_test.rb +9 -8
  377. data/test/models/tasks_test.rb +81 -1
  378. data/test/models/team_test.rb +4 -2
  379. data/test/models/undeployed_commits_test.rb +1 -0
  380. data/test/models/users_test.rb +13 -5
  381. data/test/serializers/shipit/pull_request_serializer_test.rb +29 -0
  382. data/test/test_command_integration.rb +3 -2
  383. data/test/test_helper.rb +49 -31
  384. data/test/unit/anonymous_user_serializer_test.rb +14 -0
  385. data/test/unit/command_test.rb +16 -10
  386. data/test/unit/commands_test.rb +1 -0
  387. data/test/unit/commit_serializer_test.rb +16 -0
  388. data/test/unit/csv_serializer_test.rb +3 -2
  389. data/test/unit/deploy_commands_test.rb +75 -18
  390. data/test/unit/deploy_serializer_test.rb +17 -0
  391. data/test/unit/environment_variables_test.rb +5 -4
  392. data/test/unit/github_app_test.rb +3 -3
  393. data/test/unit/github_apps_test.rb +416 -0
  394. data/test/unit/github_url_helper_test.rb +6 -0
  395. data/test/unit/rollback_commands_test.rb +2 -1
  396. data/test/unit/shipit_deployment_checks_test.rb +77 -0
  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 +15 -0
  400. data/test/unit/user_serializer_test.rb +14 -0
  401. data/test/unit/variable_definition_test.rb +1 -0
  402. metadata +320 -178
  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,5 +1,6 @@
1
+ # frozen_string_literal: true
1
2
  module Shipit
2
- class Status < ActiveRecord::Base
3
+ class Status < Record
3
4
  include Common
4
5
  include DeferredTouch
5
6
 
@@ -11,7 +12,7 @@ module Shipit
11
12
 
12
13
  deferred_touch commit: :updated_at
13
14
 
14
- validates :state, inclusion: {in: STATES, allow_blank: true}, presence: true
15
+ validates :state, inclusion: { in: STATES, allow_blank: true }, presence: true
15
16
 
16
17
  after_create :enable_ci_on_stack
17
18
  after_commit :schedule_continuous_delivery, :broadcast_update, on: :create
@@ -1,24 +1,25 @@
1
+ # frozen_string_literal: true
1
2
  module Shipit
2
3
  class Status
3
4
  module Common
4
5
  def unknown?
5
- state == 'unknown'.freeze
6
+ state == 'unknown'
6
7
  end
7
8
 
8
9
  def pending?
9
- state == 'pending'.freeze
10
+ state == 'pending'
10
11
  end
11
12
 
12
13
  def success?
13
- state == 'success'.freeze
14
+ state == 'success'
14
15
  end
15
16
 
16
17
  def error?
17
- state == 'error'.freeze
18
+ state == 'error'
18
19
  end
19
20
 
20
21
  def failure?
21
- state == 'failure'.freeze
22
+ state == 'failure'
22
23
  end
23
24
 
24
25
  def missing?
@@ -30,7 +31,7 @@ module Shipit
30
31
  end
31
32
 
32
33
  def simple_state
33
- state == 'error'.freeze ? 'failure'.freeze : state
34
+ state == 'error' ? 'failure' : state
34
35
  end
35
36
 
36
37
  def allowed_to_fail?
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Shipit
2
3
  class Status
3
4
  class Group
@@ -30,7 +31,7 @@ module Shipit
30
31
  end
31
32
 
32
33
  delegate :pending?, :success?, :error?, :failure?, :unknown?, :missing?, :state, :simple_state,
33
- to: :significant_status
34
+ to: :significant_status
34
35
  delegate :each, :size, :map, to: :statuses
35
36
  delegate :required_statuses, to: :commit
36
37
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Shipit
2
3
  class Status
3
4
  class Missing
@@ -15,7 +16,7 @@ module Shipit
15
16
  end
16
17
 
17
18
  def state
18
- 'pending'.freeze
19
+ 'pending'
19
20
  end
20
21
 
21
22
  def missing?
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Shipit
2
3
  class Status
3
4
  class Unknown
@@ -21,7 +22,7 @@ module Shipit
21
22
  end
22
23
 
23
24
  def state
24
- 'unknown'.freeze
25
+ 'unknown'
25
26
  end
26
27
 
27
28
  def missing?
@@ -1,13 +1,17 @@
1
+ # frozen_string_literal: true
1
2
  module Shipit
2
- class Task < ActiveRecord::Base
3
+ class Task < Record
3
4
  include DeferredTouch
4
5
 
5
6
  ConcurrentTaskRunning = Class.new(StandardError)
6
7
 
7
- PRESENCE_CHECK_TIMEOUT = 15
8
+ PRESENCE_CHECK_TIMEOUT = 30
8
9
  ACTIVE_STATUSES = %w(pending running aborting).freeze
9
10
  COMPLETED_STATUSES = %w(success flapping faulty validating).freeze
10
11
  UNSUCCESSFUL_STATUSES = %w(error failed aborted flapping timedout faulty).freeze
12
+ OUTPUT_SIZE_LIMIT = 16.megabytes # A MySQL mediumblob
13
+ HUMAN_READABLE_OUTPUT_LIMIT = ActionController::Base.helpers.number_to_human_size(OUTPUT_SIZE_LIMIT)
14
+ OUTPUT_TRUNCATED_MESSAGE = "Output exceeded the limit of #{HUMAN_READABLE_OUTPUT_LIMIT} and was truncated\n"
11
15
 
12
16
  attr_accessor :pid
13
17
 
@@ -19,9 +23,9 @@ module Shipit
19
23
  belongs_to :until_commit, class_name: 'Commit', required: false
20
24
  belongs_to :since_commit, class_name: 'Commit', required: false
21
25
 
22
- deferred_touch stack: :updated_at
26
+ belongs_to :rollback_once_aborted_to, class_name: 'Task', optional: true
23
27
 
24
- has_many :chunks, -> { order(:id) }, class_name: 'OutputChunk', dependent: :delete_all, inverse_of: :task
28
+ deferred_touch stack: :updated_at
25
29
 
26
30
  serialize :definition, TaskDefinition
27
31
  serialize :env, Hash
@@ -35,7 +39,7 @@ module Shipit
35
39
  scope :last_seven_days, -> { where("created_at > ?", 7.days.ago) }
36
40
  scope :previous_seven_days, -> { where(created_at: 14.days.ago..7.days.ago) }
37
41
 
38
- scope :due_for_rollup, -> { completed.where(rolled_up: false).where('created_at <= ?', 1.hour.ago) }
42
+ scope :due_for_rollup, -> { not_active.where(rolled_up: false).where('created_at <= ?', 1.hour.ago) }
39
43
 
40
44
  after_save :record_status_change
41
45
  after_create :prevent_concurrency, unless: :allow_concurrency?
@@ -73,6 +77,10 @@ module Shipit
73
77
  task.async_refresh_deployed_revision
74
78
  end
75
79
 
80
+ after_transition any => %i(aborted success failed error timedout) do |task|
81
+ task.schedule_rollup_chunks
82
+ end
83
+
76
84
  after_transition any => :flapping do |task|
77
85
  task.update!(confirmations: 0)
78
86
  end
@@ -81,6 +89,10 @@ module Shipit
81
89
  task.async_update_estimated_deploy_duration
82
90
  end
83
91
 
92
+ after_transition any => %i(failed error timedout) do |task|
93
+ task.retry_if_necessary
94
+ end
95
+
84
96
  event :run do
85
97
  transition pending: :running
86
98
  end
@@ -163,7 +175,7 @@ module Shipit
163
175
  end
164
176
 
165
177
  delegate :acquire_git_cache_lock, :async_refresh_deployed_revision, :async_update_estimated_deploy_duration,
166
- to: :stack
178
+ to: :stack
167
179
 
168
180
  delegate :checklist, to: :definition
169
181
 
@@ -191,26 +203,49 @@ module Shipit
191
203
 
192
204
  def write(text)
193
205
  log_output(text)
194
- chunks.create!(text: text)
206
+ Shipit.redis.append(output_key, text)
195
207
  end
196
208
 
197
209
  def chunk_output
198
210
  if rolled_up?
199
211
  output
200
212
  else
201
- chunks.pluck(:text).join
213
+ blob = Shipit.redis.get(output_key)
214
+
215
+ if blob && blob.size > OUTPUT_SIZE_LIMIT
216
+ Rails.logger.warn("Task #{id} output exceeds limit of #{HUMAN_READABLE_OUTPUT_LIMIT}, and will be truncated.")
217
+ blob = blob.last(OUTPUT_SIZE_LIMIT - OUTPUT_TRUNCATED_MESSAGE.size)
218
+ blob = OUTPUT_TRUNCATED_MESSAGE + blob
219
+ end
220
+
221
+ blob
202
222
  end
203
223
  end
204
224
 
225
+ def chunk_output_size
226
+ return 0 if rolled_up?
227
+
228
+ Shipit.redis.strlen(output_key)
229
+ end
230
+
231
+ def tail_output(range_start)
232
+ Shipit.redis.getrange(output_key, range_start || 0, -1)
233
+ end
234
+
205
235
  def schedule_rollup_chunks
206
236
  ChunkRollupJob.perform_later(self)
207
237
  end
208
238
 
209
239
  def rollup_chunks
210
240
  ActiveRecord::Base.transaction do
211
- self.output = chunk_output
212
- chunks.delete_all
241
+ chunks = Shipit::OutputChunk.where(task: self).pluck(:text)
242
+ chunks << chunk_output
243
+ self.output = chunks.join("\n")
244
+
213
245
  update_attribute(:rolled_up, true)
246
+
247
+ Shipit.redis.del(output_key)
248
+ Shipit::OutputChunk.where(task: self).delete_all
214
249
  end
215
250
  end
216
251
 
@@ -248,6 +283,10 @@ module Shipit
248
283
  user || AnonymousUser.new
249
284
  end
250
285
 
286
+ def author=(user)
287
+ super(user.presence)
288
+ end
289
+
251
290
  def finished?
252
291
  !pending? && !running? && !aborting?
253
292
  end
@@ -280,8 +319,12 @@ module Shipit
280
319
  end
281
320
  end
282
321
 
283
- def abort!(rollback_once_aborted: false, aborted_by:)
284
- update!(rollback_once_aborted: rollback_once_aborted, aborted_by_id: aborted_by.id)
322
+ def abort!(rollback_once_aborted: false, rollback_once_aborted_to: nil, aborted_by:)
323
+ update!(
324
+ rollback_once_aborted: rollback_once_aborted,
325
+ rollback_once_aborted_to: rollback_once_aborted_to,
326
+ aborted_by_id: aborted_by.id
327
+ )
285
328
 
286
329
  if alive?
287
330
  aborting
@@ -349,12 +392,47 @@ module Shipit
349
392
  end
350
393
  end
351
394
 
395
+ def self.recently_created_at
396
+ 5.minutes.ago
397
+ end
398
+
399
+ ZOMBIE_STATES = %w(running aborting).freeze
400
+ private_constant :ZOMBIE_STATES
401
+ def self.zombies
402
+ where(status: ZOMBIE_STATES)
403
+ .where(
404
+ "created_at <= :recently",
405
+ recently: recently_created_at,
406
+ )
407
+ .reject(&:alive?)
408
+ end
409
+
410
+ def retry_if_necessary
411
+ return unless retries_configured? && !stack.reload.locked?
412
+
413
+ if retry_attempt < max_retries
414
+ retry_task = duplicate_task
415
+ retry_task.retry_attempt = duplicate_task.retry_attempt + 1
416
+ retry_task.save!
417
+
418
+ retry_task.enqueue
419
+ end
420
+ end
421
+
422
+ def retries_configured?
423
+ !max_retries.nil? && max_retries > 0
424
+ end
425
+
352
426
  private
353
427
 
354
428
  def prevent_concurrency
355
429
  raise ConcurrentTaskRunning if stack.tasks.active.exclusive.count > 1
356
430
  end
357
431
 
432
+ def output_key
433
+ "#{status_key}:output"
434
+ end
435
+
358
436
  def status_key
359
437
  "shipit:task:#{id}"
360
438
  end
@@ -372,5 +450,13 @@ module Shipit
372
450
  def output_line_buffer
373
451
  @output_line_buffer ||= LineBuffer.new
374
452
  end
453
+
454
+ def duplicate_task
455
+ copy_task = dup
456
+ copy_task.status = 'pending'
457
+ copy_task.started_at = nil
458
+ copy_task.ended_at = nil
459
+ copy_task
460
+ end
375
461
  end
376
462
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Shipit
2
3
  class TaskDefinition
3
4
  NotFound = Class.new(StandardError)
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shipit
4
+ module TaskExecutionStrategy
5
+ class Base
6
+ def initialize(task)
7
+ self.task = task
8
+ end
9
+
10
+ def execute
11
+ raise(
12
+ NotImplmentedError,
13
+ "subclasses of TaskExectuionStrategy::Base must implement the #execute method"
14
+ )
15
+ end
16
+
17
+ attr_accessor :task
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,109 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shipit
4
+ module TaskExecutionStrategy
5
+ class Default < Base
6
+ def execute
7
+ @commands = Commands.for(@task)
8
+ unless @task.pending?
9
+ Rails.logger.error("Task ##{@task.id} already in `#{@task.status}` state. Aborting.")
10
+ return
11
+ end
12
+ run
13
+ ensure
14
+ @commands.clear_working_directory
15
+ end
16
+
17
+ def run
18
+ @task.ping
19
+ @task.run!
20
+ checkout_repository
21
+ perform_task
22
+ @task.write("\nCompleted successfully\n")
23
+ @task.report_complete!
24
+ rescue Command::TimedOut => error
25
+ @task.write("\n#{error.message}\n")
26
+ @task.report_timeout!(error)
27
+ rescue Command::Error => error
28
+ @task.write("\n#{error.message}\n")
29
+ @task.report_failure!(error)
30
+ rescue StandardError => error
31
+ @task.report_error!(error)
32
+ rescue Exception => error
33
+ @task.report_error!(error)
34
+ raise
35
+ end
36
+
37
+ def abort!(signal: 'TERM')
38
+ pid = @task.pid
39
+ if pid
40
+ @task.write("$ kill #{pid}\n")
41
+ Process.kill(signal, pid)
42
+ else
43
+ @task.write("Can't abort, no recorded pid, WTF?\n")
44
+ end
45
+ rescue SystemCallError => error
46
+ @task.write("kill: (#{pid}) - #{error.message}\n")
47
+ end
48
+
49
+ def check_for_abort
50
+ @task.should_abort? do |times_killed|
51
+ if times_killed > 3
52
+ abort!(signal: 'KILL')
53
+ else
54
+ abort!
55
+ end
56
+ end
57
+ end
58
+
59
+ def perform_task
60
+ capture_all!(@commands.install_dependencies)
61
+ capture_all!(@commands.perform)
62
+ end
63
+
64
+ def checkout_repository
65
+ unless @commands.fetched?(@task.until_commit).tap(&:run).success?
66
+ # acquire_git_cache_lock can take upto 15 seconds
67
+ # to process. Try to make sure that the job isn't
68
+ # marked dead while we attempt to acquire the lock.
69
+ @task.ping
70
+ @task.acquire_git_cache_lock do
71
+ @task.ping
72
+ unless @commands.fetched?(@task.until_commit).tap(&:run).success?
73
+ capture!(@commands.fetch)
74
+ end
75
+ end
76
+ end
77
+ capture_all!(@commands.clone)
78
+ capture!(@commands.checkout(@task.until_commit))
79
+ end
80
+
81
+ def capture_all!(commands)
82
+ commands.map { |c| capture!(c) }
83
+ end
84
+
85
+ def capture!(command)
86
+ started_at = Process.clock_gettime(Process::CLOCK_MONOTONIC)
87
+ command.start do
88
+ @task.ping
89
+ check_for_abort
90
+ end
91
+ @task.write("\n$ #{command}\npid: #{command.pid}\n")
92
+ @task.pid = command.pid
93
+ command.stream! do |line|
94
+ @task.write(line)
95
+ end
96
+ finished_at = Process.clock_gettime(Process::CLOCK_MONOTONIC)
97
+ @task.write("pid: #{command.pid} finished in: #{finished_at - started_at} seconds\n")
98
+ command.success?
99
+ end
100
+
101
+ def capture(command)
102
+ capture!(command)
103
+ command.success?
104
+ rescue Command::Error
105
+ false
106
+ end
107
+ end
108
+ end
109
+ end