shipit-engine 0.39.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 (315) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +40 -1
  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 +10 -8
  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 +2 -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 +4 -2
  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 -2
  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 +4 -3
  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 +35 -16
  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 +8 -6
  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 +1 -1
  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 +59 -56
  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 +33 -28
  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 +21 -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/ccmenu/project.xml.builder +2 -1
  162. data/app/views/shipit/continuous_delivery_schedules/show.html.erb +59 -0
  163. data/app/views/shipit/stacks/_settings_form.erb +1 -0
  164. data/config/initializers/inflections.rb +1 -0
  165. data/config/locales/en.yml +1 -0
  166. data/config/routes.rb +21 -18
  167. data/db/migrate/20240821003007_add_continuous_delivery_schedules.rb +13 -0
  168. data/db/migrate/20250207203053_embiggen_github_ids.rb +8 -0
  169. data/lib/shipit/cast_value.rb +1 -0
  170. data/lib/shipit/command.rb +29 -9
  171. data/lib/shipit/commands.rb +4 -2
  172. data/lib/shipit/csv_serializer.rb +3 -0
  173. data/lib/shipit/deploy_commands.rb +2 -1
  174. data/lib/shipit/engine.rb +5 -4
  175. data/lib/shipit/environment_variables.rb +2 -0
  176. data/lib/shipit/first_parent_commits_iterator.rb +2 -3
  177. data/lib/shipit/flock.rb +11 -9
  178. data/lib/shipit/github_app.rb +14 -15
  179. data/lib/shipit/github_http_cache_middleware.rb +1 -0
  180. data/lib/shipit/null_serializer.rb +1 -0
  181. data/lib/shipit/octokit_check_runs.rb +1 -0
  182. data/lib/shipit/octokit_iterator.rb +2 -0
  183. data/lib/shipit/paginator.rb +1 -0
  184. data/lib/shipit/rollback_commands.rb +2 -1
  185. data/lib/shipit/same_site_cookie_middleware.rb +1 -0
  186. data/lib/shipit/simple_message_verifier.rb +1 -0
  187. data/lib/shipit/stack_commands.rb +34 -26
  188. data/lib/shipit/stat.rb +1 -0
  189. data/lib/shipit/task_commands.rb +7 -6
  190. data/lib/shipit/version.rb +2 -1
  191. data/lib/shipit.rb +29 -16
  192. data/lib/tasks/cron.rake +2 -1
  193. data/lib/tasks/dev.rake +3 -2
  194. data/lib/tasks/shipit.rake +3 -2
  195. data/lib/tasks/teams.rake +3 -2
  196. data/test/controllers/api/base_controller_test.rb +1 -0
  197. data/test/controllers/api/ccmenu_controller_test.rb +4 -3
  198. data/test/controllers/api/commits_controller_test.rb +1 -0
  199. data/test/controllers/api/deploys_controller_test.rb +2 -1
  200. data/test/controllers/api/hooks_controller_test.rb +6 -5
  201. data/test/controllers/api/locks_controller_test.rb +1 -0
  202. data/test/controllers/api/merge_requests_controller_test.rb +1 -0
  203. data/test/controllers/api/outputs_controller_test.rb +1 -0
  204. data/test/controllers/api/release_statuses_controller_test.rb +4 -3
  205. data/test/controllers/api/rollback_controller_test.rb +3 -2
  206. data/test/controllers/api/stacks_controller_test.rb +13 -12
  207. data/test/controllers/api/tasks_controller_test.rb +7 -6
  208. data/test/controllers/api_clients_controller_test.rb +10 -10
  209. data/test/controllers/ccmenu_controller_test.rb +1 -0
  210. data/test/controllers/commit_checks_controller_test.rb +1 -0
  211. data/test/controllers/commits_controller_test.rb +9 -8
  212. data/test/controllers/continuous_delivery_schedules_controller_test.rb +66 -0
  213. data/test/controllers/deploys_controller_test.rb +4 -2
  214. data/test/controllers/github_authentication_controller_test.rb +6 -4
  215. data/test/controllers/merge_requests_controller_test.rb +1 -0
  216. data/test/controllers/merge_status_controller_test.rb +5 -4
  217. data/test/controllers/release_statuses_controller_test.rb +1 -0
  218. data/test/controllers/repositories_controller_test.rb +6 -5
  219. data/test/controllers/rollbacks_controller_test.rb +3 -2
  220. data/test/controllers/stacks_controller_test.rb +7 -5
  221. data/test/controllers/status_controller_test.rb +1 -0
  222. data/test/controllers/tasks_controller_test.rb +5 -4
  223. data/test/controllers/webhooks_controller_test.rb +10 -9
  224. data/test/dummy/config/application.rb +1 -1
  225. data/test/dummy/db/schema.rb +33 -6
  226. data/test/fixtures/shipit/commits.yml +7 -7
  227. data/test/fixtures/shipit/stacks.yml +4 -10
  228. data/test/fixtures/shipit/tasks.yml +3 -3
  229. data/test/helpers/api_helper.rb +2 -3
  230. data/test/helpers/fixture_aliases_helper.rb +1 -0
  231. data/test/helpers/hooks_helper.rb +1 -0
  232. data/test/helpers/json_helper.rb +4 -3
  233. data/test/helpers/links_helper.rb +2 -1
  234. data/test/helpers/payloads_helper.rb +1 -0
  235. data/test/helpers/queries_helper.rb +4 -3
  236. data/test/jobs/cache_deploy_spec_job_test.rb +3 -2
  237. data/test/jobs/chunk_rollup_job_test.rb +3 -2
  238. data/test/jobs/deliver_hook_job_test.rb +1 -0
  239. data/test/jobs/destroy_repository_job_test.rb +1 -0
  240. data/test/jobs/destroy_stack_job_test.rb +12 -0
  241. data/test/jobs/emit_event_job_test.rb +1 -0
  242. data/test/jobs/fetch_commit_stats_job_test.rb +1 -0
  243. data/test/jobs/fetch_deployed_revision_job_test.rb +1 -0
  244. data/test/jobs/github_sync_job_test.rb +22 -21
  245. data/test/jobs/mark_deploy_healthy_job_test.rb +1 -0
  246. data/test/jobs/perform_task_job_test.rb +3 -3
  247. data/test/jobs/process_merge_requests_job_test.rb +7 -6
  248. data/test/jobs/purge_old_deliveries_job_test.rb +1 -0
  249. data/test/jobs/reap_dead_tasks_job_test.rb +1 -0
  250. data/test/jobs/refresh_github_user_job_test.rb +1 -0
  251. data/test/jobs/refresh_status_job_test.rb +1 -0
  252. data/test/jobs/shipit/background_job_test.rb +35 -0
  253. data/test/jobs/shipit/continuous_delivery_job_test.rb +31 -0
  254. data/test/jobs/unique_job_test.rb +3 -1
  255. data/test/jobs/update_github_last_deployed_ref_job_test.rb +1 -0
  256. data/test/middleware/same_site_cookie_middleware_test.rb +2 -2
  257. data/test/models/api_client_test.rb +1 -0
  258. data/test/models/commit_checks_test.rb +2 -1
  259. data/test/models/commit_deployment_status_test.rb +2 -1
  260. data/test/models/commit_deployment_test.rb +4 -3
  261. data/test/models/commits_test.rb +72 -70
  262. data/test/models/delivery_test.rb +3 -2
  263. data/test/models/deploy_spec_test.rb +113 -109
  264. data/test/models/deploy_stats_test.rb +1 -0
  265. data/test/models/deploys_test.rb +65 -56
  266. data/test/models/duration_test.rb +1 -1
  267. data/test/models/github_hook_test.rb +1 -0
  268. data/test/models/hook_test.rb +7 -4
  269. data/test/models/membership_test.rb +1 -0
  270. data/test/models/merge_request_test.rb +23 -20
  271. data/test/models/release_statuses_test.rb +2 -1
  272. data/test/models/rollbacks_test.rb +4 -3
  273. data/test/models/shipit/check_run_test.rb +16 -15
  274. data/test/models/shipit/continuous_delivery_schedule_test.rb +109 -0
  275. data/test/models/shipit/deploy_spec/file_system_test.rb +54 -10
  276. data/test/models/shipit/pull_request_test.rb +9 -9
  277. data/test/models/shipit/repository_test.rb +3 -2
  278. data/test/models/shipit/review_stack_provisioning_queue_test.rb +2 -2
  279. data/test/models/shipit/stack_test.rb +30 -29
  280. data/test/models/shipit/webhooks/handlers/pull_request/closed_handler_test.rb +36 -34
  281. data/test/models/shipit/webhooks/handlers/pull_request/label_capturing_handler_test.rb +28 -28
  282. data/test/models/shipit/webhooks/handlers/pull_request/labeled_handler_test.rb +42 -42
  283. data/test/models/shipit/webhooks/handlers/pull_request/opened_handler_test.rb +33 -33
  284. data/test/models/shipit/webhooks/handlers/pull_request/reopened_handler_test.rb +37 -37
  285. data/test/models/shipit/webhooks/handlers/pull_request/review_stack_adapter_test.rb +1 -1
  286. data/test/models/shipit/webhooks/handlers/pull_request/unlabeled_handler_test.rb +44 -42
  287. data/test/models/shipit/webhooks/handlers_test.rb +1 -0
  288. data/test/models/status/group_test.rb +3 -2
  289. data/test/models/status/missing_test.rb +1 -0
  290. data/test/models/status_test.rb +2 -1
  291. data/test/models/task_definitions_test.rb +7 -6
  292. data/test/models/tasks_test.rb +5 -4
  293. data/test/models/team_test.rb +5 -4
  294. data/test/models/undeployed_commits_test.rb +10 -9
  295. data/test/models/users_test.rb +21 -20
  296. data/test/test_command_integration.rb +1 -1
  297. data/test/test_helper.rb +11 -9
  298. data/test/unit/anonymous_user_serializer_test.rb +1 -0
  299. data/test/unit/command_test.rb +10 -1
  300. data/test/unit/commands_test.rb +1 -0
  301. data/test/unit/commit_serializer_test.rb +1 -0
  302. data/test/unit/csv_serializer_test.rb +3 -2
  303. data/test/unit/deploy_commands_test.rb +33 -23
  304. data/test/unit/deploy_serializer_test.rb +1 -0
  305. data/test/unit/environment_variables_test.rb +2 -1
  306. data/test/unit/github_app_test.rb +10 -9
  307. data/test/unit/github_apps_test.rb +19 -18
  308. data/test/unit/github_url_helper_test.rb +1 -0
  309. data/test/unit/line_buffer_test.rb +1 -1
  310. data/test/unit/rollback_commands_test.rb +2 -1
  311. data/test/unit/shipit_helper_test.rb +1 -0
  312. data/test/unit/shipit_test.rb +47 -1
  313. data/test/unit/user_serializer_test.rb +1 -0
  314. data/test/unit/variable_definition_test.rb +4 -3
  315. metadata +53 -43
data/lib/shipit/engine.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Shipit
3
4
  class Engine < ::Rails::Engine
4
5
  isolate_namespace Shipit
@@ -11,7 +12,7 @@ module Shipit
11
12
  # But if AR Encryption is already configured, we just use that
12
13
  app.credentials[:active_record_encryption] = {
13
14
  primary_key: Shipit.user_access_tokens_key,
14
- key_derivation_salt: Digest::SHA256.digest("salt:".b + Shipit.user_access_tokens_key),
15
+ key_derivation_salt: Digest::SHA256.digest("salt:".b + Shipit.user_access_tokens_key)
15
16
  }
16
17
  end
17
18
  end
@@ -24,16 +25,16 @@ module Shipit
24
25
  Rails.application.credentials.deep_symbolize_keys!
25
26
 
26
27
  app.config.assets.paths << Emoji.images_path
27
- app.config.assets.precompile += %w(
28
+ app.config.assets.precompile += %w[
28
29
  favicon.ico
29
30
  task.js
30
31
  shipit.js
31
32
  shipit.css
32
33
  merge_status.js
33
34
  merge_status.css
34
- )
35
+ ]
35
36
  app.config.assets.precompile << proc do |path|
36
- path =~ %r{\Aplugins/[\-\w]+\.(js|css)\Z}
37
+ path =~ %r{\Aplugins/[-\w]+\.(js|css)\Z}
37
38
  end
38
39
  app.config.assets.precompile << proc do |path|
39
40
  path.end_with?('.svg') || (path.start_with?('emoji/') && path.end_with?('.png'))
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Shipit
3
4
  class EnvironmentVariables
4
5
  NotPermitted = Class.new(StandardError)
@@ -12,6 +13,7 @@ module Shipit
12
13
  def permit(variable_definitions)
13
14
  return {} unless @env
14
15
  raise "A whitelist is required to sanitize environment variables" unless variable_definitions
16
+
15
17
  sanitize_env_vars(variable_definitions)
16
18
  end
17
19
 
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Shipit
3
4
  class FirstParentCommitsIterator < OctokitIterator
4
5
  def each
@@ -9,9 +10,7 @@ module Shipit
9
10
  next
10
11
  end
11
12
 
12
- if last_ancestor.parents.empty? || last_ancestor.parents.first.sha == commit.sha
13
- yield last_ancestor = commit
14
- end
13
+ yield last_ancestor = commit if last_ancestor.parents.empty? || last_ancestor.parents.first.sha == commit.sha
15
14
  end
16
15
  end
17
16
  end
data/lib/shipit/flock.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'English'
3
4
  require 'timeout'
4
5
  require 'pathname'
@@ -16,19 +17,20 @@ module Shipit
16
17
 
17
18
  def lock(timeout:)
18
19
  return yield if @acquired
20
+
19
21
  path.parent.mkpath
20
22
  path.open('w') do |file|
21
- if retrying(timeout: timeout) { file.flock(File::LOCK_EX | File::LOCK_NB) }
22
- file.write($PROCESS_ID.to_s)
23
- @acquired = true
24
- begin
25
- yield
26
- ensure
27
- @acquired = false
28
- end
29
- else
23
+ unless retrying(timeout:) { file.flock(File::LOCK_EX | File::LOCK_NB) }
30
24
  raise TimeoutError, "Couldn't acquire lock for #{path} in #{timeout} seconds"
31
25
  end
26
+
27
+ file.write($PROCESS_ID.to_s)
28
+ @acquired = true
29
+ begin
30
+ yield
31
+ ensure
32
+ @acquired = false
33
+ end
32
34
  end
33
35
  end
34
36
 
@@ -1,8 +1,7 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Shipit
3
4
  class GitHubApp
4
- include Mutex_m
5
-
6
5
  class Token
7
6
  class << self
8
7
  def from_github(github_response)
@@ -44,6 +43,7 @@ module Shipit
44
43
 
45
44
  def initialize(organization, config)
46
45
  super()
46
+ @mutex = Mutex.new
47
47
  @organization = organization
48
48
  @config = (config || {}).with_indifferent_access
49
49
  @domain = @config[:domain] || DOMAIN
@@ -62,9 +62,7 @@ module Shipit
62
62
 
63
63
  def api
64
64
  client = (Thread.current[:github_client] ||= new_client(access_token: token))
65
- if client.access_token != token
66
- client.access_token = token
67
- end
65
+ client.access_token = token if client.access_token != token
68
66
  client
69
67
  end
70
68
 
@@ -88,7 +86,7 @@ module Shipit
88
86
  return 't0kEn' if Rails.env.test? # TODO: figure out something cleaner
89
87
  return unless private_key && app_id && installation_id
90
88
 
91
- @token = @token.presence || synchronize { @token.presence || fetch_new_token }
89
+ @token = @token.presence || @mutex.synchronize { @token.presence || fetch_new_token }
92
90
  @token.to_s
93
91
  end
94
92
 
@@ -99,14 +97,15 @@ module Shipit
99
97
  Rails.cache.fetch(
100
98
  "github:integration:#{cache_key}access-token",
101
99
  expires_in: GITHUB_TOKEN_RAILS_CACHE_LIFETIME,
102
- race_condition_ttl: 4.minutes,
100
+ race_condition_ttl: 4.minutes
103
101
  ) do
104
102
  response = new_client(bearer_token: authentication_payload).create_app_installation_access_token(
105
- installation_id,
103
+ installation_id
106
104
  )
107
105
  token = Token.from_github(response)
108
106
  raise AuthenticationFailed if token.blank?
109
- Rails.logger.info("Created GitHub access token ending #{token.to_s[-5..-1]}, expires at #{token.expires_at}"\
107
+
108
+ Rails.logger.info("Created GitHub access token ending #{token.to_s[-5..]}, expires at #{token.expires_at}"\
110
109
  " and will be refreshed at #{token&.refresh_at}")
111
110
  token
112
111
  end
@@ -122,14 +121,14 @@ module Shipit
122
121
  options = {
123
122
  site: api_endpoint,
124
123
  authorize_url: url('/login/oauth/authorize'),
125
- token_url: url('/login/oauth/access_token'),
124
+ token_url: url('/login/oauth/access_token')
126
125
  }
127
126
  end
128
127
 
129
128
  [
130
129
  oauth_id,
131
130
  oauth_secret,
132
- client_options: options,
131
+ { client_options: options }
133
132
  ]
134
133
  end
135
134
 
@@ -153,8 +152,8 @@ module Shipit
153
152
  def new_client(options = {})
154
153
  if enterprise?
155
154
  options = options.reverse_merge(
156
- api_endpoint: api_endpoint,
157
- web_endpoint: web_endpoint,
155
+ api_endpoint:,
156
+ web_endpoint:
158
157
  )
159
158
  end
160
159
  client = Octokit::Client.new(options)
@@ -173,7 +172,7 @@ module Shipit
173
172
  shared_cache: false,
174
173
  store: Rails.cache,
175
174
  logger: Rails.logger,
176
- serializer: NullSerializer,
175
+ serializer: NullSerializer
177
176
  )
178
177
  builder.use(GitHubHTTPCacheMiddleware)
179
178
  builder.use(Octokit::Response::RaiseError)
@@ -197,7 +196,7 @@ module Shipit
197
196
  payload = {
198
197
  iat: Time.now.to_i,
199
198
  exp: 10.minutes.from_now.to_i,
200
- iss: app_id,
199
+ iss: app_id
201
200
  }
202
201
  key = OpenSSL::PKey::RSA.new(private_key)
203
202
  JWT.encode(payload, key, 'RS256')
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Shipit
3
4
  class GitHubHTTPCacheMiddleware < Faraday::Middleware
4
5
  def call(request_env)
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Shipit
3
4
  module NullSerializer
4
5
  extend self
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module OctokitCheckRuns
3
4
  def check_runs(repo, sha, options = {})
4
5
  paginate("#{Octokit::Repository.path(repo)}/commits/#{sha}/check-runs", options)
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Shipit
3
4
  class OctokitIterator
4
5
  include Enumerable
@@ -20,6 +21,7 @@ module Shipit
20
21
 
21
22
  response.data.each(&block)
22
23
  return unless response.rels[:next]
24
+
23
25
  response = response.rels[:next].get
24
26
  end
25
27
  end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Shipit
3
4
  class Paginator
4
5
  def initialize(resources, controller, order: { id: :desc }, max_page_size: 100, default_page_size: 30)
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Shipit
3
4
  class RollbackCommands < DeployCommands
4
5
  def steps
@@ -7,7 +8,7 @@ module Shipit
7
8
 
8
9
  def env
9
10
  super.merge(
10
- 'ROLLBACK' => '1',
11
+ 'ROLLBACK' => '1'
11
12
  )
12
13
  end
13
14
  end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Shipit
3
4
  class SameSiteCookieMiddleware
4
5
  COOKIE_SEPARATOR = "\n"
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Shipit
3
4
  class SimpleMessageVerifier < ActiveSupport::MessageVerifier
4
5
  def initialize(secret, **options)
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
- # rubocop:disable Lint/MissingSuper
2
+
3
+ # rubocop:disable Lint/MissingCopEnableDirective, Lint/MissingSuper
3
4
  require 'pathname'
4
5
  require 'fileutils'
5
6
 
@@ -16,26 +17,26 @@ module Shipit
16
17
  def fetch_commit(commit)
17
18
  create_directories
18
19
  if valid_git_repository?(@stack.git_path)
19
- git('fetch', 'origin', '--quiet', '--tags', commit.sha, env: env, chdir: @stack.git_path)
20
+ git('fetch', 'origin', *quiet_git_arg, '--tags', '--force', commit.sha, env:, chdir: @stack.git_path)
20
21
  else
21
22
  @stack.clear_git_cache!
22
- git_clone(@stack.repo_git_url, @stack.git_path, branch: @stack.branch, env: env, chdir: @stack.deploys_path)
23
+ git_clone(@stack.repo_git_url, @stack.git_path, branch: @stack.branch, env:, chdir: @stack.deploys_path)
23
24
  end
24
25
  end
25
26
 
26
27
  def fetch
27
28
  create_directories
28
29
  if valid_git_repository?(@stack.git_path)
29
- git('fetch', 'origin', '--quiet', '--tags', @stack.branch, env: env, chdir: @stack.git_path)
30
+ git('fetch', 'origin', *quiet_git_arg, '--tags', '--force', @stack.branch, env:, chdir: @stack.git_path)
30
31
  else
31
32
  @stack.clear_git_cache!
32
- git_clone(@stack.repo_git_url, @stack.git_path, branch: @stack.branch, env: env, chdir: @stack.deploys_path)
33
+ git_clone(@stack.repo_git_url, @stack.git_path, branch: @stack.branch, env:, chdir: @stack.deploys_path)
33
34
  end
34
35
  end
35
36
 
36
37
  def fetched?(commit)
37
38
  if valid_git_repository?(@stack.git_path)
38
- git('rev-parse', '--quiet', '--verify', "#{commit.sha}^{commit}", env: env, chdir: @stack.git_path)
39
+ git('rev-parse', *quiet_git_arg, '--verify', "#{commit.sha}^{commit}", env:, chdir: @stack.git_path)
39
40
  else
40
41
  # When the stack's git cache is not valid, the commit is
41
42
  # NOT fetched. To keep the interface of this method
@@ -43,53 +44,55 @@ module Shipit
43
44
  # method returns false - has a non-zero exit status. We utilize
44
45
  # the POSIX 'test' command with no arguments which should
45
46
  # always have an exit status of 1.
46
- Command.new('test', env: env, chdir: @stack.deploys_path)
47
+ Command.new('test', env:, chdir: @stack.deploys_path)
47
48
  end
48
49
  end
49
50
 
50
51
  def fetch_deployed_revision
51
52
  with_temporary_working_directory(commit: @stack.commits.reachable.last) do |dir|
52
- spec = DeploySpec::FileSystem.new(dir, @stack.environment)
53
+ spec = DeploySpec::FileSystem.new(dir, @stack)
53
54
  outputs = spec.fetch_deployed_revision_steps!.map do |command_line|
54
- Command.new(command_line, env: env, chdir: dir).run
55
+ Command.new(command_line, env:, chdir: dir).run
55
56
  end
56
57
  outputs.find(&:present?).try(:strip)
57
58
  end
58
59
  end
59
60
 
60
61
  def build_cacheable_deploy_spec
61
- with_temporary_working_directory do |dir|
62
- DeploySpec::FileSystem.new(dir, @stack.environment).cacheable
62
+ with_temporary_working_directory(recursive: false) do |dir|
63
+ DeploySpec::FileSystem.new(dir, @stack).cacheable
63
64
  end
64
65
  end
65
66
 
66
- def with_temporary_working_directory(commit: nil)
67
+ def with_temporary_working_directory(commit: nil, recursive: true)
67
68
  commit ||= @stack.last_deployed_commit.presence || @stack.commits.reachable.last
68
69
 
69
70
  if !commit || !fetched?(commit).tap(&:run).success?
70
71
  @stack.acquire_git_cache_lock do
71
- unless fetched?(commit).tap(&:run).success?
72
- fetch.run!
73
- end
72
+ fetch.run! unless fetched?(commit).tap(&:run).success?
74
73
  end
75
74
  end
76
75
 
76
+ git_args = []
77
+ git_args << '--recursive' if recursive
77
78
  Dir.mktmpdir do |dir|
78
79
  git(
79
80
  'clone', @stack.git_path, @stack.repo_name,
80
- '--recursive', '--origin', 'cache',
81
+ *git_args, '--origin', 'cache',
81
82
  chdir: dir
82
83
  ).run!
83
84
 
84
85
  git_dir = File.join(dir, @stack.repo_name)
85
- git(
86
- '-c',
87
- 'advice.detachedHead=false',
88
- 'checkout',
89
- '--quiet',
90
- commit.sha,
91
- chdir: git_dir
92
- ).run! if commit
86
+ if commit
87
+ git(
88
+ '-c',
89
+ 'advice.detachedHead=false',
90
+ 'checkout',
91
+ *quiet_git_arg,
92
+ commit.sha,
93
+ chdir: git_dir
94
+ ).run!
95
+ end
93
96
  yield Pathname.new(git_dir)
94
97
  end
95
98
  end
@@ -107,18 +110,23 @@ module Shipit
107
110
  end
108
111
 
109
112
  def git_clone(url, path, branch: 'main', **kwargs)
110
- git('clone', '--quiet', *modern_git_args, '--recursive', '--branch', branch, url, path, **kwargs)
113
+ git('clone', *quiet_git_arg, *modern_git_args, '--recursive', '--branch', branch, url, path, **kwargs)
111
114
  end
112
115
 
113
116
  def modern_git_args
114
117
  return [] unless git_version >= Gem::Version.new('1.7.10')
115
- %w(--single-branch)
118
+
119
+ %w[--single-branch]
116
120
  end
117
121
 
118
122
  def create_directories
119
123
  FileUtils.mkdir_p(@stack.deploys_path)
120
124
  end
121
125
 
126
+ def quiet_git_arg
127
+ Shipit.git_progress_output ? [] : ['--quiet']
128
+ end
129
+
122
130
  private
123
131
 
124
132
  def github
data/lib/shipit/stat.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Shipit
3
4
  module Stat
4
5
  extend self
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
- # rubocop:disable Lint/MissingSuper
2
+
3
+ # rubocop:disable Lint/MissingCopEnableDirective, Lint/MissingSuper
3
4
  module Shipit
4
5
  class TaskCommands < Commands
5
6
  delegate :fetch_commit, :fetch, :fetched?, to: :stack_commands
@@ -10,18 +11,18 @@ module Shipit
10
11
  end
11
12
 
12
13
  def deploy_spec
13
- @deploy_spec ||= DeploySpec::FileSystem.new(@task.working_directory, @stack.environment)
14
+ @deploy_spec ||= DeploySpec::FileSystem.new(@task.working_directory, @stack)
14
15
  end
15
16
 
16
17
  def install_dependencies
17
18
  deploy_spec.dependencies_steps!.map do |command_line|
18
- Command.new(command_line, env: env, chdir: steps_directory)
19
+ Command.new(command_line, env:, chdir: steps_directory)
19
20
  end
20
21
  end
21
22
 
22
23
  def perform
23
24
  steps.map do |command_line|
24
- Command.new(command_line, env: env, chdir: steps_directory)
25
+ Command.new(command_line, env:, chdir: steps_directory)
25
26
  end
26
27
  end
27
28
 
@@ -40,7 +41,7 @@ module Shipit
40
41
  'TASK_ID' => @task.id.to_s,
41
42
  'IGNORED_SAFETIES' => @task.ignored_safeties? ? '1' : '0',
42
43
  'GIT_COMMITTER_NAME' => @task.user&.name || Shipit.committer_name,
43
- 'GIT_COMMITTER_EMAIL' => @task.user&.email || Shipit.committer_email,
44
+ 'GIT_COMMITTER_EMAIL' => @task.user&.email || Shipit.committer_email
44
45
  )
45
46
  .merge(deploy_spec.machine_env)
46
47
  .merge(@task.env)
@@ -68,7 +69,7 @@ module Shipit
68
69
  @task.working_directory,
69
70
  chdir: @stack.deploys_path
70
71
  ),
71
- git('remote', 'add', 'origin', @stack.repo_git_url, chdir: @task.working_directory),
72
+ git('remote', 'add', 'origin', @stack.repo_git_url, chdir: @task.working_directory)
72
73
  ]
73
74
  end
74
75
 
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Shipit
3
- VERSION = '0.39.0'
4
+ VERSION = '0.40.0'
4
5
  end
data/lib/shipit.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'active_support/all'
3
4
  require 'active_model_serializers'
4
5
  require 'state_machines-activerecord'
@@ -60,17 +61,17 @@ module Shipit
60
61
  extend self
61
62
 
62
63
  GithubOrganizationUnknown = Class.new(StandardError)
63
- TOP_LEVEL_GH_KEYS = [:app_id, :installation_id, :webhook_secret, :private_key, :oauth, :domain]
64
+ TOP_LEVEL_GH_KEYS = [:app_id, :installation_id, :webhook_secret, :private_key, :oauth, :domain].freeze
64
65
 
65
66
  delegate :table_name_prefix, to: :secrets
66
67
 
67
68
  attr_accessor :disable_api_authentication, :timeout_exit_codes, :deployment_checks, :respect_bare_shipit_file,
68
- :database_serializer
69
+ :database_serializer
69
70
  attr_writer(
70
71
  :internal_hook_receivers,
71
72
  :preferred_org_emails,
72
73
  :task_execution_strategy,
73
- :task_logger,
74
+ :task_logger
74
75
  )
75
76
 
76
77
  def task_execution_strategy
@@ -80,7 +81,7 @@ module Shipit
80
81
  self.timeout_exit_codes = [].freeze
81
82
  self.respect_bare_shipit_file = true
82
83
 
83
- alias_method :respect_bare_shipit_file?, :respect_bare_shipit_file
84
+ alias respect_bare_shipit_file? respect_bare_shipit_file
84
85
 
85
86
  def authentication_disabled?
86
87
  ENV['SHIPIT_DISABLE_AUTH'].present?
@@ -95,7 +96,7 @@ module Shipit
95
96
  end
96
97
 
97
98
  def redis_url
98
- secrets.redis_url.present? ? URI(secrets.redis_url) : nil
99
+ secrets.redis_url.present? ? URI(secrets.redis_url) : ENV["REDIS_URL"]
99
100
  end
100
101
 
101
102
  def redis
@@ -104,14 +105,19 @@ module Shipit
104
105
  logger: Rails.logger,
105
106
  reconnect_attempts: 3,
106
107
  reconnect_delay: 0.5,
107
- reconnect_delay_max: 1,
108
+ reconnect_delay_max: 1
108
109
  )
109
110
  end
110
111
 
112
+ def redis=(client)
113
+ @redis ||= client
114
+ end
115
+
111
116
  module SafeJSON
112
117
  class << self
113
118
  def load(serial)
114
119
  return nil if serial.nil?
120
+
115
121
  # JSON.load is unsafe, we should use parse instead
116
122
  JSON.parse(serial)
117
123
  end
@@ -136,6 +142,7 @@ module Shipit
136
142
 
137
143
  def dump(object)
138
144
  return if object.nil?
145
+
139
146
  JSON.dump(object)
140
147
  end
141
148
  end
@@ -144,7 +151,7 @@ module Shipit
144
151
  self.database_serializer = TransitionalSerializer
145
152
 
146
153
  def serialized_column(attribute_name, type: nil, coder: nil)
147
- column = Paquito::SerializedColumn.new(database_serializer, type, attribute_name: attribute_name)
154
+ column = Paquito::SerializedColumn.new(database_serializer, type, attribute_name:)
148
155
  if coder
149
156
  Paquito.chain(coder, column)
150
157
  else
@@ -167,12 +174,14 @@ module Shipit
167
174
 
168
175
  def github_default_organization
169
176
  return nil unless secrets&.github
177
+
170
178
  org = secrets.github.keys.first
171
179
  TOP_LEVEL_GH_KEYS.include?(org) ? nil : org
172
180
  end
173
181
 
174
182
  def github_organizations
175
183
  return [nil] unless github_default_organization
184
+
176
185
  secrets.github.keys
177
186
  end
178
187
 
@@ -183,9 +192,9 @@ module Shipit
183
192
  end
184
193
 
185
194
  def legacy_github_api
186
- if secrets&.github_api.present?
187
- @legacy_github_api ||= github.new_client(access_token: secrets.github_api[:access_token])
188
- end
195
+ return unless secrets&.github_api.present?
196
+
197
+ @legacy_github_api ||= github.new_client(access_token: secrets.github_api[:access_token])
189
198
  end
190
199
 
191
200
  def user
@@ -204,7 +213,7 @@ module Shipit
204
213
  if secrets.user_access_tokens_key.present?
205
214
  secrets.user_access_tokens_key
206
215
  elsif secrets.secret_key_base
207
- Digest::SHA256.digest("user_access_tokens_key" + secrets.secret_key_base)
216
+ Digest::SHA256.digest("user_access_tokens_key#{secrets.secret_key_base}")
208
217
  end
209
218
  end
210
219
 
@@ -220,6 +229,10 @@ module Shipit
220
229
  secrets.update_latest_deployed_ref
221
230
  end
222
231
 
232
+ def git_progress_output
233
+ secrets.git_progress_output || false
234
+ end
235
+
223
236
  def enforce_publish_config
224
237
  secrets.enforce_publish_config.presence
225
238
  end
@@ -240,7 +253,7 @@ module Shipit
240
253
  @all_settings_present ||= [
241
254
  secrets.github, # TODO: handle GitHub settings
242
255
  redis_url,
243
- host,
256
+ host
244
257
  ].all?(&:present?)
245
258
  end
246
259
 
@@ -254,10 +267,10 @@ module Shipit
254
267
 
255
268
  def revision
256
269
  @revision ||= if revision_file.exist?
257
- revision_file.read
258
- else
259
- %x(git rev-parse HEAD)
260
- end.strip
270
+ revision_file.read
271
+ else
272
+ `git rev-parse HEAD`
273
+ end.strip
261
274
  end
262
275
 
263
276
  def default_inactivity_timeout
data/lib/tasks/cron.rake CHANGED
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  namespace :cron do
3
4
  desc "Updates deployed revisions"
4
5
  task minutely: :environment do
@@ -10,7 +11,7 @@ namespace :cron do
10
11
  Shipit::ReviewStackProvisioningQueue.work
11
12
  end
12
13
 
13
- task hourly: %i(rollup refresh_users clear_stale_caches delete_old_deployment_directories)
14
+ task hourly: %i[rollup refresh_users clear_stale_caches delete_old_deployment_directories]
14
15
 
15
16
  desc "Rolls-up output chunks for completed deploys older than an hour"
16
17
  task rollup: :environment do
data/lib/tasks/dev.rake CHANGED
@@ -1,9 +1,10 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  namespace :dev do
3
4
  desc "Appends chunks to the last deploy, or specify with DEPLOY=id"
4
5
  task stream: :environment do
5
6
  require 'faker'
6
- logger = Logger.new(STDOUT)
7
+ logger = Logger.new($stdout)
7
8
 
8
9
  deploy = Shipit::Deploy.find(ENV['DEPLOY']) if ENV['DEPLOY']
9
10
  deploy ||= Deploy.last
@@ -25,7 +26,7 @@ namespace :dev do
25
26
 
26
27
  logger.error(sentence)
27
28
 
28
- deploy.chunks.create(text: sentence + "\n")
29
+ deploy.chunks.create(text: "#{sentence}\n")
29
30
  sleep 1
30
31
  end
31
32
  end