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,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
@@ -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
 
@@ -16,12 +20,12 @@ module Shipit
16
20
  belongs_to :user, optional: true
17
21
  belongs_to :aborted_by, class_name: 'User', optional: true
18
22
  belongs_to :stack, counter_cache: true
19
- belongs_to :until_commit, class_name: 'Commit'
20
- belongs_to :since_commit, class_name: 'Commit'
23
+ belongs_to :until_commit, class_name: 'Commit', required: false
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
@@ -29,14 +33,18 @@ module Shipit
29
33
  scope :success, -> { where(status: 'success') }
30
34
  scope :completed, -> { where(status: COMPLETED_STATUSES) }
31
35
  scope :active, -> { where(status: ACTIVE_STATUSES) }
36
+ scope :not_active, -> { where(status: COMPLETED_STATUSES + UNSUCCESSFUL_STATUSES) }
32
37
  scope :exclusive, -> { where(allow_concurrency: false) }
33
38
  scope :unsuccessful, -> { where(status: UNSUCCESSFUL_STATUSES) }
39
+ scope :last_seven_days, -> { where("created_at > ?", 7.days.ago) }
40
+ scope :previous_seven_days, -> { where(created_at: 14.days.ago..7.days.ago) }
34
41
 
35
42
  scope :due_for_rollup, -> { completed.where(rolled_up: false).where('created_at <= ?', 1.hour.ago) }
36
43
 
37
44
  after_save :record_status_change
38
45
  after_create :prevent_concurrency, unless: :allow_concurrency?
39
- after_commit :emit_hooks
46
+ after_commit :emit_hooks, on: :create
47
+ after_commit :emit_hooks_if_status_changed, on: :update
40
48
 
41
49
  class << self
42
50
  def durations
@@ -69,6 +77,10 @@ module Shipit
69
77
  task.async_refresh_deployed_revision
70
78
  end
71
79
 
80
+ after_transition any => %i(aborted success failed error timedout) do |task|
81
+ task.schedule_rollup_chunks
82
+ end
83
+
72
84
  after_transition any => :flapping do |task|
73
85
  task.update!(confirmations: 0)
74
86
  end
@@ -77,6 +89,10 @@ module Shipit
77
89
  task.async_update_estimated_deploy_duration
78
90
  end
79
91
 
92
+ after_transition any => %i(failed error timedout) do |task|
93
+ task.retry_if_necessary
94
+ end
95
+
80
96
  event :run do
81
97
  transition pending: :running
82
98
  end
@@ -187,26 +203,49 @@ module Shipit
187
203
 
188
204
  def write(text)
189
205
  log_output(text)
190
- chunks.create!(text: text)
206
+ Shipit.redis.append(output_key, text)
191
207
  end
192
208
 
193
209
  def chunk_output
194
210
  if rolled_up?
195
211
  output
196
212
  else
197
- 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
198
222
  end
199
223
  end
200
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
+
201
235
  def schedule_rollup_chunks
202
236
  ChunkRollupJob.perform_later(self)
203
237
  end
204
238
 
205
239
  def rollup_chunks
206
240
  ActiveRecord::Base.transaction do
207
- self.output = chunk_output
208
- chunks.delete_all
241
+ chunks = Shipit::OutputChunk.where(task: self).pluck(:text)
242
+ chunks << chunk_output
243
+ self.output = chunks.join("\n")
244
+
209
245
  update_attribute(:rolled_up, true)
246
+
247
+ Shipit.redis.del(output_key)
248
+ Shipit::OutputChunk.where(task: self).delete_all
210
249
  end
211
250
  end
212
251
 
@@ -276,8 +315,12 @@ module Shipit
276
315
  end
277
316
  end
278
317
 
279
- def abort!(rollback_once_aborted: false, aborted_by:)
280
- update!(rollback_once_aborted: rollback_once_aborted, aborted_by_id: aborted_by.id)
318
+ def abort!(rollback_once_aborted: false, rollback_once_aborted_to: nil, aborted_by:)
319
+ update!(
320
+ rollback_once_aborted: rollback_once_aborted,
321
+ rollback_once_aborted_to: rollback_once_aborted_to,
322
+ aborted_by_id: aborted_by.id
323
+ )
281
324
 
282
325
  if alive?
283
326
  aborting
@@ -303,9 +346,13 @@ module Shipit
303
346
  end
304
347
  end
305
348
 
306
- def emit_hooks
349
+ def emit_hooks_if_status_changed
307
350
  return unless @status_changed
308
351
  @status_changed = nil
352
+ emit_hooks
353
+ end
354
+
355
+ def emit_hooks
309
356
  Hook.emit(hook_event, stack, hook_event => self, status: status, stack: stack)
310
357
  end
311
358
 
@@ -327,12 +374,61 @@ module Shipit
327
374
  end
328
375
  end
329
376
 
377
+ def commit_range?
378
+ since_commit && until_commit
379
+ end
380
+
381
+ def includes_commit?(commit)
382
+ return false unless commit_range?
383
+
384
+ if since_commit == until_commit
385
+ commit.id == since_commit.id
386
+ else
387
+ commit.id > since_commit.id && commit.id <= until_commit.id
388
+ end
389
+ end
390
+
391
+ def self.recently_created_at
392
+ 5.minutes.ago
393
+ end
394
+
395
+ ZOMBIE_STATES = %w(running aborting).freeze
396
+ private_constant :ZOMBIE_STATES
397
+ def self.zombies
398
+ where(status: ZOMBIE_STATES)
399
+ .where(
400
+ "created_at <= :recently",
401
+ recently: recently_created_at,
402
+ )
403
+ .reject(&:alive?)
404
+ end
405
+
406
+ def retry_if_necessary
407
+ return unless retries_configured? && !stack.reload.locked?
408
+
409
+ if retry_attempt < max_retries
410
+ retry_task = duplicate_task
411
+ retry_task.retry_attempt = duplicate_task.retry_attempt + 1
412
+ retry_task.save!
413
+
414
+ retry_task.enqueue
415
+ end
416
+ end
417
+
418
+ def retries_configured?
419
+ !max_retries.nil? && max_retries > 0
420
+ end
421
+
330
422
  private
331
423
 
332
424
  def prevent_concurrency
333
425
  raise ConcurrentTaskRunning if stack.tasks.active.exclusive.count > 1
334
426
  end
335
427
 
428
+ def output_key
429
+ "#{status_key}:output"
430
+ end
431
+
336
432
  def status_key
337
433
  "shipit:task:#{id}"
338
434
  end
@@ -350,5 +446,13 @@ module Shipit
350
446
  def output_line_buffer
351
447
  @output_line_buffer ||= LineBuffer.new
352
448
  end
449
+
450
+ def duplicate_task
451
+ copy_task = dup
452
+ copy_task.status = 'pending'
453
+ copy_task.started_at = nil
454
+ copy_task.ended_at = nil
455
+ copy_task
456
+ end
353
457
  end
354
458
  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,110 @@
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 = Time.now
87
+ command.start do
88
+ @task.ping
89
+ check_for_abort
90
+ end
91
+ @task.write("$ #{command}\npid: #{command.pid}\nstarted at: #{started_at}\n")
92
+ @task.pid = command.pid
93
+ command.stream! do |line|
94
+ @task.write(line)
95
+ end
96
+ @task.write("\n")
97
+ finished_at = Time.now
98
+ @task.write("pid: #{command.pid}\nfinished at: #{finished_at}\nran in: #{finished_at - started_at} seconds\n")
99
+ command.success?
100
+ end
101
+
102
+ def capture(command)
103
+ capture!(command)
104
+ command.success?
105
+ rescue Command::Error
106
+ false
107
+ end
108
+ end
109
+ end
110
+ end