shipit-engine 0.38.0 → 0.40.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 (323) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +48 -4
  3. data/Rakefile +2 -1
  4. data/app/assets/javascripts/shipit/continuous_delivery_schedule.js.coffee +15 -0
  5. data/app/controllers/concerns/shipit/active_model_serializers_patch.rb +1 -0
  6. data/app/controllers/concerns/shipit/api/cacheable.rb +1 -0
  7. data/app/controllers/concerns/shipit/api/paginable.rb +3 -2
  8. data/app/controllers/concerns/shipit/api/rendering.rb +1 -0
  9. data/app/controllers/concerns/shipit/authentication.rb +1 -0
  10. data/app/controllers/concerns/shipit/pagination.rb +3 -2
  11. data/app/controllers/shipit/api/base_controller.rb +12 -10
  12. data/app/controllers/shipit/api/ccmenu_controller.rb +2 -1
  13. data/app/controllers/shipit/api/commits_controller.rb +2 -3
  14. data/app/controllers/shipit/api/deploys_controller.rb +6 -1
  15. data/app/controllers/shipit/api/hooks_controller.rb +4 -3
  16. data/app/controllers/shipit/api/locks_controller.rb +1 -0
  17. data/app/controllers/shipit/api/merge_requests_controller.rb +6 -5
  18. data/app/controllers/shipit/api/outputs_controller.rb +1 -0
  19. data/app/controllers/shipit/api/release_statuses_controller.rb +2 -1
  20. data/app/controllers/shipit/api/rollbacks_controller.rb +1 -0
  21. data/app/controllers/shipit/api/stacks_controller.rb +15 -14
  22. data/app/controllers/shipit/api/tasks_controller.rb +6 -5
  23. data/app/controllers/shipit/api_clients_controller.rb +6 -7
  24. data/app/controllers/shipit/ccmenu_url_controller.rb +3 -2
  25. data/app/controllers/shipit/commit_checks_controller.rb +2 -1
  26. data/app/controllers/shipit/commits_controller.rb +1 -0
  27. data/app/controllers/shipit/continuous_delivery_schedules_controller.rb +42 -0
  28. data/app/controllers/shipit/deploys_controller.rb +6 -5
  29. data/app/controllers/shipit/github_authentication_controller.rb +6 -0
  30. data/app/controllers/shipit/merge_requests_controller.rb +1 -0
  31. data/app/controllers/shipit/merge_status_controller.rb +30 -26
  32. data/app/controllers/shipit/release_statuses_controller.rb +1 -0
  33. data/app/controllers/shipit/repositories_controller.rb +4 -7
  34. data/app/controllers/shipit/rollbacks_controller.rb +2 -1
  35. data/app/controllers/shipit/shipit_controller.rb +1 -0
  36. data/app/controllers/shipit/stacks_controller.rb +27 -31
  37. data/app/controllers/shipit/status_controller.rb +1 -0
  38. data/app/controllers/shipit/tasks_controller.rb +3 -1
  39. data/app/controllers/shipit/webhooks_controller.rb +2 -1
  40. data/app/helpers/shipit/api_clients_helper.rb +1 -0
  41. data/app/helpers/shipit/chunks_helper.rb +3 -1
  42. data/app/helpers/shipit/deploys_helper.rb +7 -3
  43. data/app/helpers/shipit/github_url_helper.rb +5 -4
  44. data/app/helpers/shipit/merge_status_helper.rb +1 -0
  45. data/app/helpers/shipit/shipit_helper.rb +11 -10
  46. data/app/helpers/shipit/stacks_helper.rb +10 -11
  47. data/app/helpers/shipit/tasks_helper.rb +2 -1
  48. data/app/jobs/shipit/background_job/unique.rb +3 -2
  49. data/app/jobs/shipit/background_job.rb +9 -1
  50. data/app/jobs/shipit/cache_deploy_spec_job.rb +2 -1
  51. data/app/jobs/shipit/chunk_rollup_job.rb +1 -0
  52. data/app/jobs/shipit/clear_git_cache_job.rb +1 -0
  53. data/app/jobs/shipit/continuous_delivery_job.rb +5 -0
  54. data/app/jobs/shipit/create_on_github_job.rb +1 -0
  55. data/app/jobs/shipit/create_release_statuses_job.rb +2 -0
  56. data/app/jobs/shipit/deferred_touch_job.rb +1 -0
  57. data/app/jobs/shipit/deliver_hook_job.rb +1 -0
  58. data/app/jobs/shipit/destroy_job.rb +1 -0
  59. data/app/jobs/shipit/destroy_repository_job.rb +1 -0
  60. data/app/jobs/shipit/destroy_stack_job.rb +36 -15
  61. data/app/jobs/shipit/emit_event_job.rb +1 -0
  62. data/app/jobs/shipit/fetch_commit_stats_job.rb +1 -0
  63. data/app/jobs/shipit/fetch_deployed_revision_job.rb +1 -0
  64. data/app/jobs/shipit/github_sync_job.rb +4 -2
  65. data/app/jobs/shipit/mark_deploy_healthy_job.rb +1 -0
  66. data/app/jobs/shipit/perform_commit_checks_job.rb +1 -0
  67. data/app/jobs/shipit/perform_task_job.rb +1 -0
  68. data/app/jobs/shipit/process_merge_requests_job.rb +2 -0
  69. data/app/jobs/shipit/purge_old_deliveries_job.rb +1 -0
  70. data/app/jobs/shipit/reap_dead_tasks_job.rb +1 -0
  71. data/app/jobs/shipit/refresh_check_runs_job.rb +1 -0
  72. data/app/jobs/shipit/refresh_github_user_job.rb +1 -0
  73. data/app/jobs/shipit/refresh_merge_request_job.rb +1 -0
  74. data/app/jobs/shipit/refresh_statuses_job.rb +1 -0
  75. data/app/jobs/shipit/setup_github_hook_job.rb +1 -0
  76. data/app/jobs/shipit/update_estimated_deploy_duration_job.rb +1 -0
  77. data/app/jobs/shipit/update_github_last_deployed_ref_job.rb +6 -7
  78. data/app/models/concerns/shipit/deferred_touch.rb +5 -2
  79. data/app/models/shipit/anonymous_user.rb +4 -5
  80. data/app/models/shipit/api_client.rb +5 -3
  81. data/app/models/shipit/application_record.rb +1 -0
  82. data/app/models/shipit/check_run.rb +7 -6
  83. data/app/models/shipit/command_line_user.rb +4 -5
  84. data/app/models/shipit/commit.rb +46 -32
  85. data/app/models/shipit/commit_checks.rb +4 -2
  86. data/app/models/shipit/commit_deployment.rb +7 -5
  87. data/app/models/shipit/commit_deployment_status.rb +5 -3
  88. data/app/models/shipit/commit_message.rb +2 -0
  89. data/app/models/shipit/continuous_delivery_schedule.rb +84 -0
  90. data/app/models/shipit/delivery.rb +5 -4
  91. data/app/models/shipit/deploy.rb +46 -26
  92. data/app/models/shipit/deploy_spec/bundler_discovery.rb +3 -1
  93. data/app/models/shipit/deploy_spec/capistrano_discovery.rb +1 -0
  94. data/app/models/shipit/deploy_spec/file_system.rb +48 -17
  95. data/app/models/shipit/deploy_spec/kubernetes_discovery.rb +4 -3
  96. data/app/models/shipit/deploy_spec/lerna_discovery.rb +32 -31
  97. data/app/models/shipit/deploy_spec/npm_discovery.rb +18 -13
  98. data/app/models/shipit/deploy_spec/pypi_discovery.rb +5 -4
  99. data/app/models/shipit/deploy_spec/rubygems_discovery.rb +1 -0
  100. data/app/models/shipit/deploy_spec.rb +25 -30
  101. data/app/models/shipit/deploy_stats.rb +6 -1
  102. data/app/models/shipit/duration.rb +5 -3
  103. data/app/models/shipit/ephemeral_commit_checks.rb +8 -7
  104. data/app/models/shipit/github_hook.rb +1 -0
  105. data/app/models/shipit/github_status.rb +1 -0
  106. data/app/models/shipit/hook.rb +9 -7
  107. data/app/models/shipit/membership.rb +1 -0
  108. data/app/models/shipit/merge_request.rb +26 -16
  109. data/app/models/shipit/output_chunk.rb +1 -0
  110. data/app/models/shipit/provisioning_handler.rb +1 -0
  111. data/app/models/shipit/pull_request.rb +2 -2
  112. data/app/models/shipit/record.rb +1 -0
  113. data/app/models/shipit/release_status.rb +4 -3
  114. data/app/models/shipit/repository.rb +12 -11
  115. data/app/models/shipit/review_stack.rb +3 -1
  116. data/app/models/shipit/review_stack_provisioning_queue.rb +2 -2
  117. data/app/models/shipit/rollback.rb +2 -0
  118. data/app/models/shipit/stack.rb +71 -60
  119. data/app/models/shipit/status/common.rb +1 -0
  120. data/app/models/shipit/status/group.rb +5 -3
  121. data/app/models/shipit/status/missing.rb +2 -1
  122. data/app/models/shipit/status/unknown.rb +1 -0
  123. data/app/models/shipit/status.rb +5 -4
  124. data/app/models/shipit/task.rb +40 -31
  125. data/app/models/shipit/task_definition.rb +10 -7
  126. data/app/models/shipit/task_execution_strategy/default.rb +13 -13
  127. data/app/models/shipit/team.rb +13 -12
  128. data/app/models/shipit/undeployed_commit.rb +8 -3
  129. data/app/models/shipit/unlimited_api_client.rb +2 -2
  130. data/app/models/shipit/user.rb +23 -16
  131. data/app/models/shipit/variable_definition.rb +2 -1
  132. data/app/models/shipit/webhooks/handlers/check_suite_handler.rb +1 -0
  133. data/app/models/shipit/webhooks/handlers/handler.rb +1 -0
  134. data/app/models/shipit/webhooks/handlers/membership_handler.rb +1 -0
  135. data/app/models/shipit/webhooks/handlers/pull_request/assigned_handler.rb +10 -10
  136. data/app/models/shipit/webhooks/handlers/pull_request/closed_handler.rb +1 -1
  137. data/app/models/shipit/webhooks/handlers/pull_request/edited_handler.rb +10 -10
  138. data/app/models/shipit/webhooks/handlers/pull_request/label_capturing_handler.rb +2 -2
  139. data/app/models/shipit/webhooks/handlers/pull_request/labeled_handler.rb +2 -2
  140. data/app/models/shipit/webhooks/handlers/pull_request/reopened_handler.rb +1 -1
  141. data/app/models/shipit/webhooks/handlers/pull_request/review_stack_adapter.rb +3 -3
  142. data/app/models/shipit/webhooks/handlers/pull_request/unlabeled_handler.rb +1 -1
  143. data/app/models/shipit/webhooks/handlers/push_handler.rb +2 -1
  144. data/app/models/shipit/webhooks/handlers/status_handler.rb +1 -0
  145. data/app/models/shipit/webhooks.rb +3 -2
  146. data/app/serializers/concerns/shipit/conditional_attributes.rb +1 -0
  147. data/app/serializers/shipit/anonymous_user_serializer.rb +1 -0
  148. data/app/serializers/shipit/command_line_user_serializer.rb +1 -0
  149. data/app/serializers/shipit/commit_serializer.rb +2 -1
  150. data/app/serializers/shipit/deploy_serializer.rb +1 -0
  151. data/app/serializers/shipit/hook_serializer.rb +1 -0
  152. data/app/serializers/shipit/merge_request_serializer.rb +2 -1
  153. data/app/serializers/shipit/rollback_serializer.rb +1 -0
  154. data/app/serializers/shipit/short_commit_serializer.rb +1 -0
  155. data/app/serializers/shipit/stack_serializer.rb +4 -3
  156. data/app/serializers/shipit/tail_task_serializer.rb +4 -1
  157. data/app/serializers/shipit/task_serializer.rb +1 -0
  158. data/app/serializers/shipit/user_serializer.rb +1 -0
  159. data/app/validators/ascii_only_validator.rb +4 -3
  160. data/app/validators/subset_validator.rb +1 -0
  161. data/app/views/shipit/_variables.html.erb +1 -1
  162. data/app/views/shipit/ccmenu/project.xml.builder +2 -1
  163. data/app/views/shipit/continuous_delivery_schedules/show.html.erb +59 -0
  164. data/app/views/shipit/merge_status/failure.html.erb +1 -1
  165. data/app/views/shipit/missing_settings.html.erb +1 -1
  166. data/app/views/shipit/stacks/_settings_form.erb +1 -0
  167. data/config/initializers/inflections.rb +1 -0
  168. data/config/locales/en.yml +1 -0
  169. data/config/routes.rb +21 -18
  170. data/config/secrets.development.example.yml +1 -1
  171. data/config/secrets.development.shopify.yml +1 -1
  172. data/db/migrate/20240821003007_add_continuous_delivery_schedules.rb +13 -0
  173. data/db/migrate/20250207203053_embiggen_github_ids.rb +8 -0
  174. data/lib/shipit/cast_value.rb +1 -0
  175. data/lib/shipit/command.rb +29 -9
  176. data/lib/shipit/commands.rb +4 -2
  177. data/lib/shipit/csv_serializer.rb +3 -0
  178. data/lib/shipit/deploy_commands.rb +2 -1
  179. data/lib/shipit/engine.rb +6 -5
  180. data/lib/shipit/environment_variables.rb +2 -0
  181. data/lib/shipit/first_parent_commits_iterator.rb +2 -3
  182. data/lib/shipit/flock.rb +11 -9
  183. data/lib/shipit/github_app.rb +14 -16
  184. data/lib/shipit/github_http_cache_middleware.rb +1 -0
  185. data/lib/shipit/null_serializer.rb +1 -0
  186. data/lib/shipit/octokit_check_runs.rb +2 -3
  187. data/lib/shipit/octokit_iterator.rb +2 -0
  188. data/lib/shipit/paginator.rb +1 -0
  189. data/lib/shipit/rollback_commands.rb +2 -1
  190. data/lib/shipit/same_site_cookie_middleware.rb +1 -0
  191. data/lib/shipit/simple_message_verifier.rb +1 -0
  192. data/lib/shipit/stack_commands.rb +35 -27
  193. data/lib/shipit/stat.rb +1 -0
  194. data/lib/shipit/task_commands.rb +7 -6
  195. data/lib/shipit/version.rb +2 -1
  196. data/lib/shipit.rb +30 -17
  197. data/lib/tasks/cron.rake +2 -1
  198. data/lib/tasks/dev.rake +3 -2
  199. data/lib/tasks/shipit.rake +3 -2
  200. data/lib/tasks/teams.rake +3 -2
  201. data/test/controllers/api/base_controller_test.rb +1 -0
  202. data/test/controllers/api/ccmenu_controller_test.rb +4 -3
  203. data/test/controllers/api/commits_controller_test.rb +1 -0
  204. data/test/controllers/api/deploys_controller_test.rb +26 -1
  205. data/test/controllers/api/hooks_controller_test.rb +6 -5
  206. data/test/controllers/api/locks_controller_test.rb +1 -0
  207. data/test/controllers/api/merge_requests_controller_test.rb +1 -0
  208. data/test/controllers/api/outputs_controller_test.rb +1 -0
  209. data/test/controllers/api/release_statuses_controller_test.rb +4 -3
  210. data/test/controllers/api/rollback_controller_test.rb +3 -2
  211. data/test/controllers/api/stacks_controller_test.rb +13 -12
  212. data/test/controllers/api/tasks_controller_test.rb +7 -6
  213. data/test/controllers/api_clients_controller_test.rb +10 -10
  214. data/test/controllers/ccmenu_controller_test.rb +1 -0
  215. data/test/controllers/commit_checks_controller_test.rb +1 -0
  216. data/test/controllers/commits_controller_test.rb +9 -8
  217. data/test/controllers/continuous_delivery_schedules_controller_test.rb +66 -0
  218. data/test/controllers/deploys_controller_test.rb +4 -2
  219. data/test/controllers/github_authentication_controller_test.rb +6 -4
  220. data/test/controllers/merge_requests_controller_test.rb +1 -0
  221. data/test/controllers/merge_status_controller_test.rb +5 -4
  222. data/test/controllers/release_statuses_controller_test.rb +1 -0
  223. data/test/controllers/repositories_controller_test.rb +6 -5
  224. data/test/controllers/rollbacks_controller_test.rb +3 -2
  225. data/test/controllers/stacks_controller_test.rb +8 -6
  226. data/test/controllers/status_controller_test.rb +1 -0
  227. data/test/controllers/tasks_controller_test.rb +13 -5
  228. data/test/controllers/webhooks_controller_test.rb +10 -9
  229. data/test/dummy/config/application.rb +2 -1
  230. data/test/dummy/config/initializers/0_load_development_secrets.rb +2 -2
  231. data/test/dummy/config/secrets.development.json +3 -0
  232. data/test/dummy/config/secrets.test.json +21 -0
  233. data/test/dummy/db/schema.rb +33 -6
  234. data/test/fixtures/shipit/commits.yml +7 -7
  235. data/test/fixtures/shipit/stacks.yml +4 -10
  236. data/test/fixtures/shipit/tasks.yml +3 -3
  237. data/test/helpers/api_helper.rb +2 -3
  238. data/test/helpers/fixture_aliases_helper.rb +1 -0
  239. data/test/helpers/hooks_helper.rb +1 -0
  240. data/test/helpers/json_helper.rb +4 -3
  241. data/test/helpers/links_helper.rb +2 -1
  242. data/test/helpers/payloads_helper.rb +1 -0
  243. data/test/helpers/queries_helper.rb +4 -3
  244. data/test/jobs/cache_deploy_spec_job_test.rb +3 -2
  245. data/test/jobs/chunk_rollup_job_test.rb +3 -2
  246. data/test/jobs/deliver_hook_job_test.rb +1 -0
  247. data/test/jobs/destroy_repository_job_test.rb +1 -0
  248. data/test/jobs/destroy_stack_job_test.rb +12 -0
  249. data/test/jobs/emit_event_job_test.rb +1 -0
  250. data/test/jobs/fetch_commit_stats_job_test.rb +1 -0
  251. data/test/jobs/fetch_deployed_revision_job_test.rb +1 -0
  252. data/test/jobs/github_sync_job_test.rb +22 -21
  253. data/test/jobs/mark_deploy_healthy_job_test.rb +1 -0
  254. data/test/jobs/perform_task_job_test.rb +3 -3
  255. data/test/jobs/process_merge_requests_job_test.rb +7 -6
  256. data/test/jobs/purge_old_deliveries_job_test.rb +1 -0
  257. data/test/jobs/reap_dead_tasks_job_test.rb +1 -0
  258. data/test/jobs/refresh_github_user_job_test.rb +1 -0
  259. data/test/jobs/refresh_status_job_test.rb +1 -0
  260. data/test/jobs/shipit/background_job_test.rb +35 -0
  261. data/test/jobs/shipit/continuous_delivery_job_test.rb +31 -0
  262. data/test/jobs/unique_job_test.rb +3 -1
  263. data/test/jobs/update_github_last_deployed_ref_job_test.rb +1 -0
  264. data/test/middleware/same_site_cookie_middleware_test.rb +2 -2
  265. data/test/models/api_client_test.rb +1 -0
  266. data/test/models/commit_checks_test.rb +2 -1
  267. data/test/models/commit_deployment_status_test.rb +2 -2
  268. data/test/models/commit_deployment_test.rb +4 -3
  269. data/test/models/commits_test.rb +72 -70
  270. data/test/models/delivery_test.rb +3 -2
  271. data/test/models/deploy_spec_test.rb +113 -109
  272. data/test/models/deploy_stats_test.rb +1 -0
  273. data/test/models/deploys_test.rb +65 -56
  274. data/test/models/duration_test.rb +1 -1
  275. data/test/models/github_hook_test.rb +1 -0
  276. data/test/models/hook_test.rb +7 -4
  277. data/test/models/membership_test.rb +1 -0
  278. data/test/models/merge_request_test.rb +26 -20
  279. data/test/models/release_statuses_test.rb +2 -1
  280. data/test/models/rollbacks_test.rb +4 -3
  281. data/test/models/shipit/check_run_test.rb +16 -15
  282. data/test/models/shipit/continuous_delivery_schedule_test.rb +109 -0
  283. data/test/models/shipit/deploy_spec/file_system_test.rb +54 -10
  284. data/test/models/shipit/pull_request_test.rb +9 -9
  285. data/test/models/shipit/repository_test.rb +3 -2
  286. data/test/models/shipit/review_stack_provisioning_queue_test.rb +2 -2
  287. data/test/models/shipit/{stacks_test.rb → stack_test.rb} +48 -34
  288. data/test/models/shipit/webhooks/handlers/pull_request/closed_handler_test.rb +36 -34
  289. data/test/models/shipit/webhooks/handlers/pull_request/label_capturing_handler_test.rb +28 -28
  290. data/test/models/shipit/webhooks/handlers/pull_request/labeled_handler_test.rb +42 -42
  291. data/test/models/shipit/webhooks/handlers/pull_request/opened_handler_test.rb +33 -33
  292. data/test/models/shipit/webhooks/handlers/pull_request/reopened_handler_test.rb +37 -37
  293. data/test/models/shipit/webhooks/handlers/pull_request/review_stack_adapter_test.rb +1 -1
  294. data/test/models/shipit/webhooks/handlers/pull_request/unlabeled_handler_test.rb +44 -42
  295. data/test/models/shipit/webhooks/handlers_test.rb +1 -0
  296. data/test/models/status/group_test.rb +3 -2
  297. data/test/models/status/missing_test.rb +1 -0
  298. data/test/models/status_test.rb +2 -1
  299. data/test/models/task_definitions_test.rb +7 -6
  300. data/test/models/tasks_test.rb +5 -4
  301. data/test/models/team_test.rb +5 -4
  302. data/test/models/undeployed_commits_test.rb +10 -9
  303. data/test/models/users_test.rb +29 -20
  304. data/test/test_command_integration.rb +1 -1
  305. data/test/test_helper.rb +12 -10
  306. data/test/unit/anonymous_user_serializer_test.rb +1 -0
  307. data/test/unit/command_test.rb +10 -1
  308. data/test/unit/commands_test.rb +1 -0
  309. data/test/unit/commit_serializer_test.rb +1 -0
  310. data/test/unit/csv_serializer_test.rb +3 -2
  311. data/test/unit/deploy_commands_test.rb +33 -23
  312. data/test/unit/deploy_serializer_test.rb +1 -0
  313. data/test/unit/environment_variables_test.rb +2 -1
  314. data/test/unit/github_app_test.rb +11 -10
  315. data/test/unit/github_apps_test.rb +19 -18
  316. data/test/unit/github_url_helper_test.rb +1 -0
  317. data/test/unit/line_buffer_test.rb +1 -1
  318. data/test/unit/rollback_commands_test.rb +2 -1
  319. data/test/unit/shipit_helper_test.rb +1 -0
  320. data/test/unit/shipit_test.rb +47 -1
  321. data/test/unit/user_serializer_test.rb +1 -0
  322. data/test/unit/variable_definition_test.rb +4 -3
  323. metadata +61 -47
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Shipit
3
4
  class DeploySpec
4
5
  module CapistranoDiscovery
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Shipit
3
4
  class DeploySpec
4
5
  class FileSystem < DeploySpec
@@ -10,9 +11,12 @@ module Shipit
10
11
  include BundlerDiscovery
11
12
  include KubernetesDiscovery
12
13
 
13
- def initialize(app_dir, env)
14
+ attr_reader :stack
15
+
16
+ def initialize(app_dir, stack)
14
17
  @app_dir = Pathname(app_dir)
15
- @env = env
18
+ @env = stack.environment
19
+ @stack = stack
16
20
  super(nil)
17
21
  end
18
22
 
@@ -39,29 +43,29 @@ module Shipit
39
43
  'method' => merge_request_merge_method,
40
44
  'max_divergence' => {
41
45
  'commits' => max_divergence_commits&.to_i,
42
- 'age' => max_divergence_age&.to_i,
43
- },
46
+ 'age' => max_divergence_age&.to_i
47
+ }
44
48
  },
45
49
  'ci' => {
46
50
  'hide' => hidden_statuses,
47
51
  'allow_failures' => soft_failing_statuses,
48
52
  'require' => required_statuses,
49
- 'blocking' => blocking_statuses,
53
+ 'blocking' => blocking_statuses
50
54
  },
51
55
  'machine' => {
52
56
  'environment' => discover_machine_env.merge(machine_env),
53
57
  'directory' => directory,
54
- 'cleanup' => true,
58
+ 'cleanup' => true
55
59
  },
56
60
  'review' => {
57
61
  'checklist' => review_checklist,
58
62
  'monitoring' => review_monitoring,
59
- 'checks' => review_checks,
63
+ 'checks' => review_checks
60
64
  },
61
65
  'plugins' => plugins,
62
66
  'status' => {
63
67
  'context' => release_status_context,
64
- 'delay' => release_status_delay,
68
+ 'delay' => release_status_delay
65
69
  },
66
70
  'dependencies' => { 'override' => dependencies_steps },
67
71
  'provision' => { 'handler_name' => provisioning_handler_name },
@@ -70,19 +74,19 @@ module Shipit
70
74
  'variables' => deploy_variables.map(&:to_h),
71
75
  'max_commits' => maximum_commits_per_deploy,
72
76
  'interval' => pause_between_deploys,
73
- 'retries' => retries_on_deploy,
77
+ 'retries' => retries_on_deploy
74
78
  },
75
79
  'rollback' => {
76
80
  'override' => rollback_steps,
77
- 'retries' => retries_on_rollback,
81
+ 'retries' => retries_on_rollback
78
82
  },
79
83
  'fetch' => fetch_deployed_revision_steps,
80
- 'tasks' => cacheable_tasks,
84
+ 'tasks' => cacheable_tasks
81
85
  )
82
86
  end
83
87
 
84
88
  def cacheable_tasks
85
- discover_task_definitions.map { |k, c| [k, coerce_task_definition(c)] }.to_h
89
+ discover_task_definitions.transform_values { |c| coerce_task_definition(c) }
86
90
  end
87
91
 
88
92
  def config(*)
@@ -97,15 +101,28 @@ module Shipit
97
101
  return { 'deploy' => { 'pre' => [shipit_not_obeying_bare_file_echo_command, 'exit 1'] } }
98
102
  end
99
103
 
100
- read_config(config_file_path)
104
+ config_obj = read_config(config_file_path)
105
+ build_config(config_file_path, config_obj)
101
106
  end
102
107
 
103
108
  def shipit_file_names_in_priority_order
104
- ["#{app_name}.#{@env}.yml", "#{app_name}.yml", "shipit.#{@env}.yml", "shipit.yml"].uniq
109
+ [
110
+ "#{app_name}.#{@env}.yml",
111
+ ".shipit/#{app_name}.#{@env}.yml",
112
+
113
+ "#{app_name}.yml",
114
+ ".shipit/#{app_name}.yml",
115
+
116
+ "shipit.#{@env}.yml",
117
+ ".shipit/#{@env}.yml",
118
+
119
+ "shipit.yml",
120
+ ".shipit/shipit.yml"
121
+ ].uniq
105
122
  end
106
123
 
107
124
  def bare_shipit_filenames
108
- ["#{app_name}.yml", "shipit.yml"].uniq
125
+ ["#{app_name}.yml", "shipit.yml", ".shipit/#{app_name}.yml", ".shipit/shipit.yml"].uniq
109
126
  end
110
127
 
111
128
  def config_file_path
@@ -121,16 +138,30 @@ module Shipit
121
138
  @app_name ||= Shipit.app_name.downcase
122
139
  end
123
140
 
141
+ SHIPIT_CONFIG_INHERIT_FROM_KEY = "inherit_from"
142
+ def build_config(path, config_obj)
143
+ return config_obj if config_obj.blank? || !config_obj.key?(SHIPIT_CONFIG_INHERIT_FROM_KEY)
144
+
145
+ inherits_from_path = path.dirname.join(config_obj.delete(SHIPIT_CONFIG_INHERIT_FROM_KEY))
146
+ if inherits_from_path.exist?
147
+ inherits_config_obj = read_config(inherits_from_path)
148
+ config_obj = inherits_config_obj.deep_merge(config_obj)
149
+ path = inherits_from_path
150
+ end
151
+
152
+ build_config(path, config_obj)
153
+ end
154
+
124
155
  def read_config(path)
125
156
  SafeYAML.load(path.read) if path.exist?
126
157
  end
127
158
 
128
159
  def shipit_not_obeying_bare_file_echo_command
129
- <<~EOM
160
+ <<~WARNING_MESSAGE
130
161
  echo \"\e[1;31mShipit is configured to ignore the bare '#{app_name}.yml' file.
131
162
  Please rename this file to more specifically include the environment name.
132
163
  Deployments will fail until a valid '#{app_name}.#{@env}.yml' file is found.\e[0m\"
133
- EOM
164
+ WARNING_MESSAGE
134
165
  end
135
166
  end
136
167
  end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Shipit
3
4
  class DeploySpec
4
5
  module KubernetesDiscovery
@@ -16,8 +17,8 @@ module Shipit
16
17
  'restart' => {
17
18
  'action' => "Restart application",
18
19
  'description' => "Simulates a rollout of Kubernetes deployments by using kubernetes-restart utility",
19
- 'steps' => [kubernetes_restart_cmd],
20
- },
20
+ 'steps' => [kubernetes_restart_cmd]
21
+ }
21
22
  }.merge!(super)
22
23
  else
23
24
  super
@@ -55,7 +56,7 @@ module Shipit
55
56
  cmd = [
56
57
  "kubernetes-restart",
57
58
  kube_config.fetch('namespace'),
58
- kube_config.fetch('context'),
59
+ kube_config.fetch('context')
59
60
  ]
60
61
  cmd += ["--max-watch-seconds", timeout_duration] if timeout_duration
61
62
  Shellwords.join(cmd)
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'json'
3
4
 
4
5
  module Shipit
@@ -23,23 +24,23 @@ module Shipit
23
24
  end
24
25
 
25
26
  def discover_lerna_checklist
26
- if lerna?
27
- command = if lerna_lerna >= LATEST_MAJOR_VERSION
28
- 'lerna version'
29
- else
30
- %(
27
+ return unless lerna?
28
+
29
+ command = if lerna_lerna >= LATEST_MAJOR_VERSION
30
+ 'lerna version'
31
+ else
32
+ %(
31
33
  lerna publish --skip-npm
32
34
  && git add -A
33
35
  && git push --follow-tags
34
36
  )
35
- end
37
+ end
36
38
 
37
- [%(
39
+ [%(
38
40
  <strong>Don't forget version and tag before publishing!</strong>
39
41
  You can do this with:<br/>
40
42
  <pre>#{command}</pre>
41
43
  )]
42
- end
43
44
  end
44
45
 
45
46
  def lerna?
@@ -72,47 +73,47 @@ module Shipit
72
73
 
73
74
  def publish_lerna_packages
74
75
  return publish_independent_packages if lerna_version == 'independent'
76
+
75
77
  publish_fixed_version_packages
76
78
  end
77
79
 
78
80
  def publish_independent_packages
79
- command = if lerna_lerna >= LATEST_MAJOR_VERSION
81
+ if lerna_lerna >= LATEST_MAJOR_VERSION
80
82
  [
81
83
  'assert-lerna-independent-version-tags',
82
- 'publish-lerna-independent-packages',
84
+ 'publish-lerna-independent-packages'
83
85
  ]
84
86
  else
85
87
  [
86
88
  'assert-lerna-independent-version-tags',
87
- 'publish-lerna-independent-packages-legacy',
89
+ 'publish-lerna-independent-packages-legacy'
88
90
  ]
89
91
  end
90
- command
91
92
  end
92
93
 
93
94
  def publish_fixed_version_packages
94
95
  check_tags = 'assert-lerna-fixed-version-tag'
95
96
  version = lerna_version
96
97
  publish = if lerna_lerna >= LATEST_MAJOR_VERSION
97
- %W(
98
- node_modules/.bin/lerna publish
99
- from-git
100
- --yes
101
- --dist-tag #{dist_tag(version)}
102
- ).join(" ")
103
- else
104
- # `yarn publish` requires user input, so always use npm.
105
- %W(
106
- node_modules/.bin/lerna publish
107
- --yes
108
- --skip-git
109
- --repo-version #{version}
110
- --force-publish=*
111
- --npm-tag #{dist_tag(version)}
112
- --npm-client=npm
113
- --skip-npm=false
114
- ).join(" ")
115
- end
98
+ %W[
99
+ node_modules/.bin/lerna publish
100
+ from-git
101
+ --yes
102
+ --dist-tag #{dist_tag(version)}
103
+ ].join(" ")
104
+ else
105
+ # `yarn publish` requires user input, so always use npm.
106
+ %W[
107
+ node_modules/.bin/lerna publish
108
+ --yes
109
+ --skip-git
110
+ --repo-version #{version}
111
+ --force-publish=*
112
+ --npm-tag #{dist_tag(version)}
113
+ --npm-client=npm
114
+ --skip-npm=false
115
+ ].join(" ")
116
+ end
116
117
 
117
118
  [check_tags, publish]
118
119
  end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'json'
3
4
 
4
5
  module Shipit
@@ -27,19 +28,19 @@ module Shipit
27
28
  end
28
29
 
29
30
  def discover_yarn_checklist
30
- if yarn?
31
- [%(<strong>Don't forget version and tag before publishing!</strong> You can do this with:<br/>
31
+ return unless yarn?
32
+
33
+ [%(<strong>Don't forget version and tag before publishing!</strong> You can do this with:<br/>
32
34
  yarn version --new-version <strong>&lt;major|minor|patch&gt;</strong>
33
35
  && git push --follow-tags</pre>)]
34
- end
35
36
  end
36
37
 
37
38
  def discover_npm_checklist
38
- if npm?
39
- [%(<strong>Don't forget version and tag before publishing!</strong> You can do this with:<br/>
39
+ return unless npm?
40
+
41
+ [%(<strong>Don't forget version and tag before publishing!</strong> You can do this with:<br/>
40
42
  npm version <strong>&lt;major|minor|patch&gt;</strong>
41
43
  && git push --follow-tags</pre>)]
42
- end
43
44
  end
44
45
 
45
46
  def npm?
@@ -59,6 +60,7 @@ module Shipit
59
60
  # An 1.0.0-beta.1 would be installable using both:
60
61
  # `yarn add package@1.0.0-beta.1` and `yarn add package@next`
61
62
  return 'next' if ['-beta', '-alpha', '-rc', '-next'].any? { |tag| version.include?(tag) }
63
+
62
64
  'latest'
63
65
  end
64
66
 
@@ -104,21 +106,25 @@ module Shipit
104
106
  # default to private deploy when we enforce a publishConfig
105
107
  if enforce_publish_config?
106
108
  return PRIVATE if config.blank?
109
+
107
110
  config['access'] || PRIVATE
108
111
  end
109
112
 
110
113
  return PUBLIC if config.blank?
114
+
111
115
  config['access'] || PUBLIC
112
116
  end
113
117
 
114
118
  def scoped_package?
115
119
  return false if Shipit.npm_org_scope.nil?
120
+
116
121
  package_name.start_with?(Shipit.npm_org_scope)
117
122
  end
118
123
 
119
124
  def enforce_publish_config?
120
125
  enforce = Shipit.enforce_publish_config
121
126
  return false if enforce.nil? || enforce.to_s == "0"
127
+
122
128
  true
123
129
  end
124
130
 
@@ -148,9 +154,7 @@ module Shipit
148
154
  scope = Shipit.npm_org_scope
149
155
  prefix = scoped_package? ? "#{scope}:registry" : "registry"
150
156
 
151
- if publish_config_access == PUBLIC
152
- return "#{prefix}=#{NPM_REGISTRY}"
153
- end
157
+ return "#{prefix}=#{NPM_REGISTRY}" if publish_config_access == PUBLIC
154
158
 
155
159
  "#{prefix}=#{Shipit.private_npm_registry}"
156
160
  end
@@ -164,15 +168,16 @@ module Shipit
164
168
  publish = "npm publish --tag #{dist_tag(package_version)} --access #{publish_config_access}"
165
169
 
166
170
  return [check_tags, generate_npmrc, publish] if enforce_publish_config?
171
+
167
172
  [check_tags, publish]
168
173
  end
169
174
 
170
175
  def js_command(command_args)
171
176
  runner = if yarn?
172
- 'yarn'
173
- else
174
- 'npm'
175
- end
177
+ 'yarn'
178
+ else
179
+ 'npm'
180
+ end
176
181
 
177
182
  "#{runner} #{command_args}"
178
183
  end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Shipit
3
4
  class DeploySpec
4
5
  module PypiDiscovery
@@ -15,10 +16,10 @@ module Shipit
15
16
  end
16
17
 
17
18
  def discover_pypi_checklist
18
- if egg?
19
- [%(<strong>Don't forget to add a tag before deploying!</strong> You can do this with:
19
+ return unless egg?
20
+
21
+ [%(<strong>Don't forget to add a tag before deploying!</strong> You can do this with:
20
22
  git tag -a -m "Version <strong>x.y.z</strong>" v<strong>x.y.z</strong> && git push --tags)]
21
- end
22
23
  end
23
24
 
24
25
  def egg?
@@ -33,7 +34,7 @@ module Shipit
33
34
  [
34
35
  "assert-egg-version-tag #{setup_dot_py}",
35
36
  'python setup.py register sdist',
36
- 'twine upload dist/*',
37
+ 'twine upload dist/*'
37
38
  ]
38
39
  end
39
40
  end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Shipit
3
4
  class DeploySpec
4
5
  module RubygemsDiscovery
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'pathname'
3
4
 
4
5
  module Shipit
@@ -47,11 +48,9 @@ module Shipit
47
48
  def config(*keys, &default)
48
49
  default ||= -> { nil }
49
50
  keys.flatten.reduce(@config) do |hash, key|
50
- if hash.is_a?(Hash)
51
- hash.fetch(key) { return default.call }
52
- else
53
- return default.call
54
- end
51
+ return default.call unless hash.is_a?(Hash)
52
+
53
+ hash.fetch(key) { return default.call }
55
54
  end
56
55
  end
57
56
 
@@ -80,7 +79,7 @@ module Shipit
80
79
  config('dependencies', 'override') { discover_dependencies_steps || [] }
81
80
  end
82
81
  end
83
- alias_method :dependencies_steps!, :dependencies_steps
82
+ alias dependencies_steps! dependencies_steps
84
83
 
85
84
  def maximum_commits_per_deploy
86
85
  config('deploy', 'max_commits') { 8 }
@@ -95,9 +94,9 @@ module Shipit
95
94
  end
96
95
 
97
96
  def release_status_delay
98
- if delay = config('status', 'delay') { config('deploy', 'interval') { 0 } }
99
- Duration.parse(delay)
100
- end
97
+ return unless delay = config('status', 'delay') { config('deploy', 'interval') { 0 } }
98
+
99
+ Duration.parse(delay)
101
100
  end
102
101
 
103
102
  def pause_between_deploys
@@ -193,7 +192,7 @@ module Shipit
193
192
 
194
193
  def merge_request_merge_method
195
194
  method = config('merge', 'method')
196
- method if %w(merge rebase squash).include?(method)
195
+ method if %w[merge rebase squash].include?(method)
197
196
  end
198
197
 
199
198
  def merge_request_required_statuses
@@ -213,11 +212,11 @@ module Shipit
213
212
  end
214
213
 
215
214
  def revalidate_merge_requests_after
216
- if timeout = config('merge', 'revalidate_after')
217
- begin
218
- Duration.parse(timeout)
219
- rescue Duration::ParseError
220
- end
215
+ return unless timeout = config('merge', 'revalidate_after')
216
+
217
+ begin
218
+ Duration.parse(timeout)
219
+ rescue Duration::ParseError
221
220
  end
222
221
  end
223
222
 
@@ -226,11 +225,11 @@ module Shipit
226
225
  end
227
226
 
228
227
  def max_divergence_age
229
- if timeout = config('merge', 'max_divergence', 'age')
230
- begin
231
- Duration.parse(timeout)
232
- rescue Duration::ParseError
233
- end
228
+ return unless timeout = config('merge', 'max_divergence', 'age')
229
+
230
+ begin
231
+ Duration.parse(timeout)
232
+ rescue Duration::ParseError
234
233
  end
235
234
  end
236
235
 
@@ -255,6 +254,7 @@ module Shipit
255
254
  def around_steps(section)
256
255
  steps = yield
257
256
  return unless steps
257
+
258
258
  config(section, 'pre') { [] } + steps + config(section, 'post') { [] }
259
259
  end
260
260
 
@@ -262,24 +262,19 @@ module Shipit
262
262
  config
263
263
  end
264
264
 
265
- def discover_review_checklist
266
- end
265
+ def discover_review_checklist; end
267
266
 
268
267
  def discover_task_definitions
269
268
  config('tasks') || {}
270
269
  end
271
270
 
272
- def discover_dependencies_steps
273
- end
271
+ def discover_dependencies_steps; end
274
272
 
275
- def discover_deploy_steps
276
- end
273
+ def discover_deploy_steps; end
277
274
 
278
- def discover_rollback_steps
279
- end
275
+ def discover_rollback_steps; end
280
276
 
281
- def discover_fetch_deployed_revision_steps
282
- end
277
+ def discover_fetch_deployed_revision_steps; end
283
278
 
284
279
  def discover_machine_env
285
280
  {}
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Shipit
3
4
  class DeployStats
4
5
  delegate :empty?, to: :@deploys
@@ -14,6 +15,7 @@ module Shipit
14
15
 
15
16
  def average_duration
16
17
  return if empty?
18
+
17
19
  @durations.sum / @durations.length.to_f
18
20
  end
19
21
 
@@ -27,11 +29,13 @@ module Shipit
27
29
 
28
30
  def median_duration
29
31
  return if @durations.empty?
32
+
30
33
  (sorted_durations[(@durations.length - 1) / 2] + sorted_durations[@durations.length / 2]) / 2.0
31
34
  end
32
35
 
33
36
  def success_rate
34
37
  return if empty?
38
+
35
39
  (@deploys.count(&:success?) / @deploys.length.to_f) * 100
36
40
  end
37
41
 
@@ -39,7 +43,7 @@ module Shipit
39
43
  {
40
44
  count: percent_change(compare_stats.count, count),
41
45
  average_duration: percent_change(compare_stats.average_duration, average_duration),
42
- median_duration: percent_change(compare_stats.median_duration, median_duration),
46
+ median_duration: percent_change(compare_stats.median_duration, median_duration)
43
47
  }
44
48
  end
45
49
 
@@ -52,6 +56,7 @@ module Shipit
52
56
  def percent_change(from, to)
53
57
  return if to.nil? || from.nil?
54
58
  return to * 100 if from.zero?
59
+
55
60
  ((to - from) / from.to_f) * 100
56
61
  end
57
62
  end
@@ -1,21 +1,22 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Shipit
3
4
  class Duration < ActiveSupport::Duration
4
5
  ParseError = Class.new(ArgumentError)
5
6
 
6
- FORMAT = %r{
7
+ FORMAT = /
7
8
  \A
8
9
  (?<days>\d+d)?
9
10
  (?<hours>\d+h)?
10
11
  (?<minutes>\d+m)?
11
12
  (?<seconds>\d+s?)?
12
13
  \z
13
- }x
14
+ /x
14
15
  UNITS = {
15
16
  's' => :seconds,
16
17
  'm' => :minutes,
17
18
  'h' => :hours,
18
- 'd' => :days,
19
+ 'd' => :days
19
20
  }.freeze
20
21
 
21
22
  class << self
@@ -25,6 +26,7 @@ module Shipit
25
26
  unless match = FORMAT.match(value.to_s)
26
27
  raise ParseError, "not a duration: #{value.inspect}"
27
28
  end
29
+
28
30
  parts = []
29
31
  UNITS.each_value do |unit|
30
32
  if value = match[unit]
@@ -1,7 +1,8 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Shipit
3
4
  class EphemeralCommitChecks
4
- FINAL_STATUSES = %w(failed error success).freeze
5
+ FINAL_STATUSES = %w[failed error success].freeze
5
6
 
6
7
  def initialize(commit)
7
8
  @commit = commit
@@ -13,8 +14,8 @@ module Shipit
13
14
  def run
14
15
  self.status = 'running'
15
16
  commands = StackCommands.new(stack)
16
- commands.with_temporary_working_directory(commit: commit) do |directory|
17
- deploy_spec = DeploySpec::FileSystem.new(directory, stack.environment)
17
+ commands.with_temporary_working_directory(commit:) do |directory|
18
+ deploy_spec = DeploySpec::FileSystem.new(directory, stack)
18
19
  capture_all(build_commands(deploy_spec.dependencies_steps, chdir: directory))
19
20
  capture_all(build_commands(deploy_spec.review_checks, chdir: directory))
20
21
  end
@@ -22,7 +23,7 @@ module Shipit
22
23
  rescue Command::Error
23
24
  self.status = 'failed'
24
25
  self
25
- rescue
26
+ rescue StandardError
26
27
  self.status = 'error'
27
28
  raise
28
29
  else
@@ -46,7 +47,7 @@ module Shipit
46
47
  private
47
48
 
48
49
  def build_commands(commands, chdir:)
49
- commands.map { |c| Command.new(c, env: Shipit.env, chdir: chdir) }
50
+ commands.map { |c| Command.new(c, env: Shipit.env, chdir:) }
50
51
  end
51
52
 
52
53
  def capture_all(commands)
@@ -59,8 +60,8 @@ module Shipit
59
60
  command.stream! do |line|
60
61
  write(line)
61
62
  end
62
- rescue Command::Error => error
63
- write(error.message)
63
+ rescue Command::Error => e
64
+ write(e.message)
64
65
  raise
65
66
  ensure
66
67
  write("\n")
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Shipit
3
4
  class GithubHook < Record
4
5
  # TODO: app-migration, delete class
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Shipit
3
4
  module GithubStatus
4
5
  CACHE_KEY = 'github::status'