shipit-engine 0.28.0 → 0.32.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 (314) 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/stylesheets/_pages/_stacks.scss +76 -3
  6. data/app/assets/stylesheets/_structure/_main.scss +2 -1
  7. data/app/assets/stylesheets/merge_status.scss +0 -3
  8. data/app/controllers/concerns/shipit/active_model_serializers_patch.rb +13 -0
  9. data/app/controllers/concerns/shipit/api/cacheable.rb +1 -0
  10. data/app/controllers/concerns/shipit/api/paginable.rb +3 -2
  11. data/app/controllers/concerns/shipit/api/rendering.rb +5 -4
  12. data/app/controllers/concerns/shipit/authentication.rb +3 -2
  13. data/app/controllers/concerns/shipit/pagination.rb +2 -1
  14. data/app/controllers/shipit/api/base_controller.rb +11 -6
  15. data/app/controllers/shipit/api/ccmenu_controller.rb +2 -1
  16. data/app/controllers/shipit/api/commits_controller.rb +2 -1
  17. data/app/controllers/shipit/api/deploys_controller.rb +4 -3
  18. data/app/controllers/shipit/api/hooks_controller.rb +6 -5
  19. data/app/controllers/shipit/api/locks_controller.rb +5 -4
  20. data/app/controllers/shipit/api/outputs_controller.rb +2 -1
  21. data/app/controllers/shipit/api/pull_requests_controller.rb +7 -6
  22. data/app/controllers/shipit/api/release_statuses_controller.rb +3 -2
  23. data/app/controllers/shipit/api/rollbacks_controller.rb +33 -0
  24. data/app/controllers/shipit/api/stacks_controller.rb +37 -5
  25. data/app/controllers/shipit/api/tasks_controller.rb +6 -5
  26. data/app/controllers/shipit/api_clients_controller.rb +50 -0
  27. data/app/controllers/shipit/ccmenu_url_controller.rb +4 -3
  28. data/app/controllers/shipit/commit_checks_controller.rb +2 -1
  29. data/app/controllers/shipit/commits_controller.rb +2 -1
  30. data/app/controllers/shipit/deploys_controller.rb +3 -2
  31. data/app/controllers/shipit/github_authentication_controller.rb +4 -3
  32. data/app/controllers/shipit/merge_status_controller.rb +19 -14
  33. data/app/controllers/shipit/pull_requests_controller.rb +3 -2
  34. data/app/controllers/shipit/release_statuses_controller.rb +3 -2
  35. data/app/controllers/shipit/rollbacks_controller.rb +3 -2
  36. data/app/controllers/shipit/shipit_controller.rb +2 -1
  37. data/app/controllers/shipit/stacks_controller.rb +78 -14
  38. data/app/controllers/shipit/status_controller.rb +2 -1
  39. data/app/controllers/shipit/tasks_controller.rb +6 -5
  40. data/app/controllers/shipit/webhooks_controller.rb +5 -132
  41. data/app/helpers/shipit/chunks_helper.rb +1 -0
  42. data/app/helpers/shipit/deploys_helper.rb +4 -3
  43. data/app/helpers/shipit/github_url_helper.rb +1 -0
  44. data/app/helpers/shipit/merge_status_helper.rb +1 -0
  45. data/app/helpers/shipit/shipit_helper.rb +1 -0
  46. data/app/helpers/shipit/stacks_helper.rb +5 -0
  47. data/app/helpers/shipit/tasks_helper.rb +1 -0
  48. data/app/jobs/shipit/background_job.rb +4 -0
  49. data/app/jobs/shipit/background_job/unique.rb +4 -1
  50. data/app/jobs/shipit/cache_deploy_spec_job.rb +1 -0
  51. data/app/jobs/shipit/chunk_rollup_job.rb +4 -0
  52. data/app/jobs/shipit/clear_git_cache_job.rb +1 -0
  53. data/app/jobs/shipit/continuous_delivery_job.rb +3 -1
  54. data/app/jobs/shipit/create_on_github_job.rb +6 -1
  55. data/app/jobs/shipit/create_release_statuses_job.rb +1 -0
  56. data/app/jobs/shipit/deferred_touch_job.rb +4 -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_stack_job.rb +3 -2
  60. data/app/jobs/shipit/emit_event_job.rb +2 -1
  61. data/app/jobs/shipit/fetch_commit_stats_job.rb +1 -0
  62. data/app/jobs/shipit/fetch_deployed_revision_job.rb +2 -1
  63. data/app/jobs/shipit/github_sync_job.rb +3 -2
  64. data/app/jobs/shipit/{mark_deploy_healty_job.rb → mark_deploy_healthy_job.rb} +1 -0
  65. data/app/jobs/shipit/merge_pull_requests_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 +14 -5
  68. data/app/jobs/shipit/purge_old_deliveries_job.rb +1 -0
  69. data/app/jobs/shipit/reap_dead_tasks_job.rb +21 -0
  70. data/app/jobs/shipit/refresh_check_runs_job.rb +1 -0
  71. data/app/jobs/shipit/refresh_github_user_job.rb +1 -0
  72. data/app/jobs/shipit/refresh_pull_request_job.rb +1 -0
  73. data/app/jobs/shipit/refresh_statuses_job.rb +1 -0
  74. data/app/jobs/shipit/setup_github_hook_job.rb +1 -0
  75. data/app/jobs/shipit/update_estimated_deploy_duration_job.rb +1 -0
  76. data/app/jobs/shipit/update_github_last_deployed_ref_job.rb +6 -3
  77. data/app/models/concerns/shipit/deferred_touch.rb +4 -3
  78. data/app/models/shipit/anonymous_user.rb +5 -0
  79. data/app/models/shipit/api_client.rb +3 -2
  80. data/app/models/shipit/application_record.rb +2 -1
  81. data/app/models/shipit/check_run.rb +4 -3
  82. data/app/models/shipit/command_line_user.rb +1 -0
  83. data/app/models/shipit/commit.rb +31 -12
  84. data/app/models/shipit/commit_checks.rb +1 -0
  85. data/app/models/shipit/commit_deployment.rb +17 -12
  86. data/app/models/shipit/commit_deployment_status.rb +8 -3
  87. data/app/models/shipit/commit_message.rb +1 -0
  88. data/app/models/shipit/delivery.rb +4 -3
  89. data/app/models/shipit/deploy.rb +40 -10
  90. data/app/models/shipit/deploy_spec.rb +22 -3
  91. data/app/models/shipit/deploy_spec/bundler_discovery.rb +2 -1
  92. data/app/models/shipit/deploy_spec/capistrano_discovery.rb +1 -0
  93. data/app/models/shipit/deploy_spec/file_system.rb +10 -3
  94. data/app/models/shipit/deploy_spec/kubernetes_discovery.rb +1 -0
  95. data/app/models/shipit/deploy_spec/lerna_discovery.rb +1 -0
  96. data/app/models/shipit/deploy_spec/npm_discovery.rb +5 -4
  97. data/app/models/shipit/deploy_spec/pypi_discovery.rb +1 -0
  98. data/app/models/shipit/deploy_spec/rubygems_discovery.rb +1 -0
  99. data/app/models/shipit/deploy_stats.rb +58 -0
  100. data/app/models/shipit/duration.rb +3 -2
  101. data/app/models/shipit/ephemeral_commit_checks.rb +1 -0
  102. data/app/models/shipit/github_hook.rb +2 -1
  103. data/app/models/shipit/github_status.rb +3 -2
  104. data/app/models/shipit/hook.rb +6 -5
  105. data/app/models/shipit/membership.rb +3 -2
  106. data/app/models/shipit/output_chunk.rb +7 -2
  107. data/app/models/shipit/pull_request.rb +13 -7
  108. data/app/models/shipit/record.rb +18 -0
  109. data/app/models/shipit/release_status.rb +3 -2
  110. data/app/models/shipit/repository.rb +43 -0
  111. data/app/models/shipit/rollback.rb +1 -0
  112. data/app/models/shipit/stack.rb +109 -50
  113. data/app/models/shipit/status.rb +3 -2
  114. data/app/models/shipit/status/common.rb +7 -6
  115. data/app/models/shipit/status/group.rb +1 -0
  116. data/app/models/shipit/status/missing.rb +2 -1
  117. data/app/models/shipit/status/unknown.rb +2 -1
  118. data/app/models/shipit/task.rb +64 -9
  119. data/app/models/shipit/task_definition.rb +1 -0
  120. data/app/models/shipit/team.rb +2 -1
  121. data/app/models/shipit/undeployed_commit.rb +1 -0
  122. data/app/models/shipit/unlimited_api_client.rb +1 -0
  123. data/app/models/shipit/user.rb +29 -5
  124. data/app/models/shipit/variable_definition.rb +1 -0
  125. data/app/models/shipit/webhooks.rb +33 -0
  126. data/app/models/shipit/webhooks/handlers/check_suite_handler.rb +20 -0
  127. data/app/models/shipit/webhooks/handlers/handler.rb +41 -0
  128. data/app/models/shipit/webhooks/handlers/membership_handler.rb +46 -0
  129. data/app/models/shipit/webhooks/handlers/push_handler.rb +21 -0
  130. data/app/models/shipit/webhooks/handlers/status_handler.rb +27 -0
  131. data/app/serializers/concerns/shipit/conditional_attributes.rb +1 -0
  132. data/app/serializers/shipit/anonymous_user_serializer.rb +1 -0
  133. data/app/serializers/shipit/command_line_user_serializer.rb +1 -0
  134. data/app/serializers/shipit/commit_serializer.rb +1 -0
  135. data/app/serializers/shipit/deploy_serializer.rb +2 -1
  136. data/app/serializers/shipit/hook_serializer.rb +1 -0
  137. data/app/serializers/shipit/pull_request_serializer.rb +1 -0
  138. data/app/serializers/shipit/rollback_serializer.rb +1 -0
  139. data/app/serializers/shipit/short_commit_serializer.rb +1 -0
  140. data/app/serializers/shipit/stack_serializer.rb +7 -1
  141. data/app/serializers/shipit/tail_task_serializer.rb +1 -0
  142. data/app/serializers/shipit/task_serializer.rb +2 -17
  143. data/app/serializers/shipit/user_serializer.rb +6 -1
  144. data/app/validators/ascii_only_validator.rb +4 -3
  145. data/app/validators/subset_validator.rb +1 -0
  146. data/app/views/layouts/_head.html.erb +0 -0
  147. data/app/views/layouts/shipit.html.erb +6 -4
  148. data/app/views/shipit/_variables.html.erb +1 -1
  149. data/app/views/shipit/api_clients/index.html.erb +36 -0
  150. data/app/views/shipit/api_clients/new.html.erb +33 -0
  151. data/app/views/shipit/api_clients/show.html.erb +35 -0
  152. data/app/views/shipit/ccmenu/project.xml.builder +2 -1
  153. data/app/views/shipit/deploys/new.html.erb +17 -12
  154. data/app/views/shipit/deploys/show.html.erb +2 -2
  155. data/app/views/shipit/merge_status/logged_out.erb +1 -1
  156. data/app/views/shipit/stacks/_header.html.erb +27 -12
  157. data/app/views/shipit/stacks/_links.html.erb +1 -0
  158. data/app/views/shipit/stacks/all_tasks.html.erb +28 -0
  159. data/app/views/shipit/stacks/index.html.erb +7 -2
  160. data/app/views/shipit/stacks/settings.html.erb +19 -0
  161. data/app/views/shipit/stacks/statistics.html.erb +82 -0
  162. data/app/views/shipit/tasks/show.html.erb +1 -1
  163. data/config/initializers/inflections.rb +2 -1
  164. data/config/locales/en.yml +18 -5
  165. data/config/routes.rb +14 -2
  166. data/db/migrate/20191209231045_create_shipit_repositories.rb +12 -0
  167. data/db/migrate/20191209231307_add_repository_reference_to_stacks.rb +15 -0
  168. data/db/migrate/20191216162728_backfill_repository_data.rb +22 -0
  169. data/db/migrate/20191216163010_remove_repository_information_from_stacks.rb +20 -0
  170. data/db/migrate/20191219205202_add_archived_since_to_stacks.rb +6 -0
  171. data/db/migrate/20200102175621_optional_task_commits.rb +6 -0
  172. data/db/migrate/20200109132519_add_sha_to_commit_deployments.rb +5 -0
  173. data/db/migrate/20200226211925_add_index_to_tasks_status.rb +5 -0
  174. data/db/migrate/20200427135152_add_pull_request_head_sha_to_commit.rb +5 -0
  175. data/db/migrate/20200615181558_add_rollback_once_aborted_to.rb +5 -0
  176. data/lib/shipit.rb +18 -20
  177. data/lib/shipit/cast_value.rb +1 -0
  178. data/lib/shipit/command.rb +14 -18
  179. data/lib/shipit/commands.rb +5 -4
  180. data/lib/shipit/csv_serializer.rb +1 -0
  181. data/lib/shipit/deploy_commands.rb +1 -0
  182. data/lib/shipit/engine.rb +11 -2
  183. data/lib/shipit/environment_variables.rb +11 -1
  184. data/lib/shipit/first_parent_commits_iterator.rb +1 -0
  185. data/lib/shipit/flock.rb +1 -0
  186. data/lib/shipit/github_app.rb +60 -6
  187. data/lib/shipit/github_http_cache_middleware.rb +57 -0
  188. data/lib/shipit/null_serializer.rb +1 -0
  189. data/lib/shipit/octokit_check_runs.rb +3 -2
  190. data/lib/shipit/octokit_iterator.rb +3 -2
  191. data/lib/shipit/paginator.rb +3 -2
  192. data/lib/shipit/rollback_commands.rb +1 -0
  193. data/lib/shipit/same_site_cookie_middleware.rb +29 -0
  194. data/lib/shipit/simple_message_verifier.rb +1 -0
  195. data/lib/shipit/stack_commands.rb +6 -3
  196. data/lib/shipit/stat.rb +1 -0
  197. data/lib/shipit/task_commands.rb +22 -14
  198. data/lib/shipit/version.rb +2 -1
  199. data/lib/snippets/release-gem +5 -1
  200. data/lib/tasks/cron.rake +2 -0
  201. data/lib/tasks/dev.rake +3 -2
  202. data/lib/tasks/shipit.rake +16 -17
  203. data/lib/tasks/teams.rake +1 -0
  204. data/test/controllers/api/base_controller_test.rb +3 -2
  205. data/test/controllers/api/ccmenu_controller_test.rb +9 -8
  206. data/test/controllers/api/commits_controller_test.rb +3 -2
  207. data/test/controllers/api/deploys_controller_test.rb +15 -14
  208. data/test/controllers/api/hooks_controller_test.rb +8 -7
  209. data/test/controllers/api/locks_controller_test.rb +7 -6
  210. data/test/controllers/api/outputs_controller_test.rb +3 -2
  211. data/test/controllers/api/pull_requests_controller_test.rb +8 -7
  212. data/test/controllers/api/release_statuses_controller_test.rb +2 -1
  213. data/test/controllers/api/rollback_controller_test.rb +113 -0
  214. data/test/controllers/api/stacks_controller_test.rb +44 -15
  215. data/test/controllers/api/tasks_controller_test.rb +13 -12
  216. data/test/controllers/api_clients_controller_test.rb +104 -0
  217. data/test/controllers/ccmenu_controller_test.rb +4 -3
  218. data/test/controllers/commit_checks_controller_test.rb +4 -3
  219. data/test/controllers/commits_controller_test.rb +3 -2
  220. data/test/controllers/deploys_controller_test.rb +33 -22
  221. data/test/controllers/github_authentication_controller_test.rb +1 -0
  222. data/test/controllers/merge_status_controller_test.rb +27 -9
  223. data/test/controllers/pull_requests_controller_test.rb +4 -3
  224. data/test/controllers/release_statuses_controller_test.rb +3 -2
  225. data/test/controllers/rollbacks_controller_test.rb +9 -8
  226. data/test/controllers/stacks_controller_test.rb +64 -15
  227. data/test/controllers/status_controller_test.rb +1 -0
  228. data/test/controllers/tasks_controller_test.rb +20 -19
  229. data/test/controllers/webhooks_controller_test.rb +36 -9
  230. data/test/dummy/config/application.rb +1 -1
  231. data/test/dummy/config/environments/development.rb +24 -4
  232. data/test/dummy/config/environments/test.rb +2 -0
  233. data/test/dummy/db/schema.rb +25 -11
  234. data/test/dummy/db/seeds.rb +34 -17
  235. data/test/fixtures/shipit/commit_deployment_statuses.yml +4 -4
  236. data/test/fixtures/shipit/commit_deployments.yml +8 -8
  237. data/test/fixtures/shipit/commits.yml +38 -0
  238. data/test/fixtures/shipit/repositories.yml +27 -0
  239. data/test/fixtures/shipit/stacks.yml +190 -30
  240. data/test/fixtures/shipit/tasks.yml +66 -3
  241. data/test/fixtures/timeout +2 -1
  242. data/test/helpers/api_helper.rb +1 -0
  243. data/test/helpers/fixture_aliases_helper.rb +1 -0
  244. data/test/helpers/hooks_helper.rb +2 -1
  245. data/test/helpers/json_helper.rb +15 -11
  246. data/test/helpers/links_helper.rb +4 -3
  247. data/test/helpers/payloads_helper.rb +1 -0
  248. data/test/helpers/queries_helper.rb +3 -2
  249. data/test/jobs/cache_deploy_spec_job_test.rb +2 -1
  250. data/test/jobs/chunk_rollup_job_test.rb +1 -0
  251. data/test/jobs/deliver_hook_job_test.rb +2 -1
  252. data/test/jobs/destroy_stack_job_test.rb +10 -0
  253. data/test/jobs/emit_event_job_test.rb +2 -1
  254. data/test/jobs/fetch_commit_stats_job_test.rb +1 -0
  255. data/test/jobs/fetch_deployed_revision_job_test.rb +1 -0
  256. data/test/jobs/github_sync_job_test.rb +1 -0
  257. data/test/jobs/mark_deploy_healthy_job_test.rb +1 -0
  258. data/test/jobs/merge_pull_requests_job_test.rb +5 -4
  259. data/test/jobs/perform_task_job_test.rb +4 -3
  260. data/test/jobs/purge_old_deliveries_job_test.rb +1 -0
  261. data/test/jobs/reap_dead_tasks_job_test.rb +68 -0
  262. data/test/jobs/refresh_github_user_job_test.rb +1 -0
  263. data/test/jobs/refresh_status_job_test.rb +1 -0
  264. data/test/jobs/unique_job_test.rb +1 -0
  265. data/test/jobs/update_github_last_deployed_ref_job_test.rb +13 -11
  266. data/test/middleware/same_site_cookie_middleware_test.rb +52 -0
  267. data/test/models/api_client_test.rb +1 -0
  268. data/test/models/commit_checks_test.rb +1 -0
  269. data/test/models/commit_deployment_status_test.rb +34 -4
  270. data/test/models/commit_deployment_test.rb +9 -11
  271. data/test/models/commits_test.rb +99 -7
  272. data/test/models/delivery_test.rb +3 -2
  273. data/test/models/deploy_spec_test.rb +47 -42
  274. data/test/models/deploy_stats_test.rb +113 -0
  275. data/test/models/deploys_test.rb +60 -13
  276. data/test/models/duration_test.rb +1 -0
  277. data/test/models/github_hook_test.rb +1 -0
  278. data/test/models/hook_test.rb +20 -16
  279. data/test/models/membership_test.rb +1 -0
  280. data/test/models/output_chunk_test.rb +1 -0
  281. data/test/models/pull_request_test.rb +18 -11
  282. data/test/models/release_statuses_test.rb +1 -0
  283. data/test/models/rollbacks_test.rb +1 -0
  284. data/test/models/shipit/check_run_test.rb +1 -0
  285. data/test/models/shipit/repository_test.rb +77 -0
  286. data/test/models/shipit/wehbooks/handlers_test.rb +27 -0
  287. data/test/models/stacks_test.rb +110 -56
  288. data/test/models/status/group_test.rb +1 -0
  289. data/test/models/status/missing_test.rb +1 -0
  290. data/test/models/status_test.rb +1 -0
  291. data/test/models/task_definitions_test.rb +9 -8
  292. data/test/models/tasks_test.rb +18 -1
  293. data/test/models/team_test.rb +4 -2
  294. data/test/models/undeployed_commits_test.rb +14 -0
  295. data/test/models/users_test.rb +109 -1
  296. data/test/test_command_integration.rb +3 -2
  297. data/test/test_helper.rb +38 -34
  298. data/test/unit/anonymous_user_serializer_test.rb +14 -0
  299. data/test/unit/command_test.rb +12 -7
  300. data/test/unit/commands_test.rb +1 -0
  301. data/test/unit/commit_serializer_test.rb +16 -0
  302. data/test/unit/csv_serializer_test.rb +3 -2
  303. data/test/unit/deploy_commands_test.rb +14 -4
  304. data/test/unit/deploy_serializer_test.rb +17 -0
  305. data/test/unit/environment_variables_test.rb +5 -4
  306. data/test/unit/github_app_test.rb +165 -0
  307. data/test/unit/github_url_helper_test.rb +1 -0
  308. data/test/unit/rollback_commands_test.rb +2 -1
  309. data/test/unit/shipit_helper_test.rb +17 -0
  310. data/test/unit/shipit_test.rb +1 -0
  311. data/test/unit/user_serializer_test.rb +14 -0
  312. data/test/unit/variable_definition_test.rb +1 -0
  313. metadata +215 -157
  314. data/lib/shipit/strip_cache_control.rb +0 -40
@@ -1,6 +1,7 @@
1
+ # frozen_string_literal: true
1
2
  module Shipit
2
3
  class CheckRun < ApplicationRecord
3
- CONCLUSIONS = %w(success failure neutral cancelled timed_out action_required).freeze
4
+ CONCLUSIONS = %w(success failure neutral cancelled timed_out action_required stale).freeze
4
5
  include DeferredTouch
5
6
  include Status::Common
6
7
 
@@ -9,7 +10,7 @@ module Shipit
9
10
 
10
11
  deferred_touch commit: :updated_at
11
12
 
12
- validates :conclusion, inclusion: {in: CONCLUSIONS, allow_nil: true}
13
+ validates :conclusion, inclusion: { in: CONCLUSIONS, allow_nil: true }
13
14
 
14
15
  after_create :enable_ci_on_stack
15
16
 
@@ -45,7 +46,7 @@ module Shipit
45
46
  'pending'
46
47
  when 'success', 'neutral'
47
48
  'success'
48
- when 'failure', 'cancelled'
49
+ when 'failure', 'cancelled', 'stale'
49
50
  'failure'
50
51
  when 'timed_out'
51
52
  'error'
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Shipit
2
3
  class CommandLineUser
3
4
  def present?
@@ -1,7 +1,10 @@
1
+ # frozen_string_literal: true
1
2
  module Shipit
2
- class Commit < ActiveRecord::Base
3
+ class Commit < Record
3
4
  include DeferredTouch
4
5
 
6
+ RECENT_COMMIT_THRESHOLD = 10.seconds
7
+
5
8
  AmbiguousRevision = Class.new(StandardError)
6
9
 
7
10
  belongs_to :stack
@@ -90,7 +93,7 @@ module Shipit
90
93
  committer = User.find_or_create_committer_from_github_commit(commit)
91
94
  committer ||= Anonymous.new
92
95
 
93
- new(
96
+ record = new(
94
97
  sha: commit.sha,
95
98
  message: commit.commit.message,
96
99
  author: author,
@@ -100,6 +103,20 @@ module Shipit
100
103
  additions: commit.stats&.additions,
101
104
  deletions: commit.stats&.deletions,
102
105
  )
106
+
107
+ if record.pull_request?
108
+ record.pull_request_head_sha = commit.parents.last.sha
109
+ end
110
+
111
+ record
112
+ end
113
+
114
+ def message=(message)
115
+ limit = self.class.columns_hash['message'].limit
116
+ if limit && message && message.size > limit
117
+ message = message.truncate_bytes(limit)
118
+ end
119
+ super(message)
103
120
  end
104
121
 
105
122
  def reload(*)
@@ -126,7 +143,9 @@ module Shipit
126
143
  end
127
144
 
128
145
  def refresh_statuses!
129
- github_statuses = stack.handle_github_redirections { Shipit.github.api.statuses(github_repo_name, sha) }
146
+ github_statuses = stack.handle_github_redirections do
147
+ Shipit.github.api.statuses(github_repo_name, sha, per_page: 100)
148
+ end
130
149
  github_statuses.each do |status|
131
150
  create_status_from_github!(status)
132
151
  end
@@ -177,13 +196,7 @@ module Shipit
177
196
  def active?
178
197
  return false unless stack.active_task?
179
198
 
180
- active_task = stack.active_task
181
-
182
- if active_task.since_commit == active_task.until_commit
183
- id == active_task.since_commit.id
184
- else
185
- id > active_task.since_commit.id && id <= active_task.until_commit.id
186
- end
199
+ stack.active_task.includes_commit?(self)
187
200
  end
188
201
 
189
202
  def deployable?
@@ -242,7 +255,9 @@ module Shipit
242
255
 
243
256
  def schedule_continuous_delivery
244
257
  return unless deployable? && stack.continuous_deployment? && stack.deployable?
245
- ContinuousDeliveryJob.perform_later(stack)
258
+ # This buffer is to allow for statuses and checks to be refreshed before evaluating if the commit is deployable
259
+ # - e.g. if the commit was fast-forwarded with already passing CI.
260
+ ContinuousDeliveryJob.set(wait: RECENT_COMMIT_THRESHOLD).perform_later(stack)
246
261
  end
247
262
 
248
263
  def github_commit
@@ -311,6 +326,10 @@ module Shipit
311
326
  update!(locked: false, lock_author: nil)
312
327
  end
313
328
 
329
+ def recently_pushed?
330
+ created_at > RECENT_COMMIT_THRESHOLD.ago
331
+ end
332
+
314
333
  private
315
334
 
316
335
  def message_parser
@@ -326,7 +345,7 @@ module Shipit
326
345
  new_status = status
327
346
 
328
347
  unless already_deployed
329
- payload = {commit: self, stack: stack, status: new_status.state}
348
+ payload = { commit: self, stack: stack, status: new_status.state }
330
349
  if previous_status != new_status
331
350
  Hook.emit(:commit_status, stack, payload.merge(commit_status: new_status))
332
351
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Shipit
2
3
  class CommitChecks < EphemeralCommitChecks
3
4
  OUTPUT_TTL = 10.minutes.to_i
@@ -1,6 +1,6 @@
1
+ # frozen_string_literal: true
1
2
  module Shipit
2
- class CommitDeployment < ActiveRecord::Base
3
- belongs_to :commit
3
+ class CommitDeployment < Record
4
4
  belongs_to :task
5
5
  has_many :statuses, dependent: :destroy, class_name: 'CommitDeploymentStatus'
6
6
 
@@ -9,11 +9,10 @@ module Shipit
9
9
  delegate :stack, :author, to: :task
10
10
 
11
11
  def create_on_github!
12
- return unless commit.pull_request?
13
-
14
12
  create_deployment_on_github!
15
13
  statuses.order(id: :asc).each(&:create_on_github!)
16
- rescue Octokit::NotFound, Octokit::Forbidden
14
+ rescue Octokit::NotFound, Octokit::Forbidden => error
15
+ Rails.logger.warn("Got #{error.class.name} creating deployment or statuses: #{error.message}")
17
16
  # If no one can create the deployment we can only give up
18
17
  end
19
18
 
@@ -34,25 +33,31 @@ module Shipit
34
33
  update!(github_id: response.id, api_url: response.url)
35
34
  end
36
35
 
37
- def pull_request_head
38
- pull_request = Shipit.github.api.pull_request(stack.github_repo_name, commit.pull_request_number)
39
- pull_request.head.sha
40
- end
41
-
42
36
  def schedule_create_on_github
43
37
  CreateOnGithubJob.perform_later(self)
44
38
  end
45
39
 
40
+ def short_sha
41
+ sha[0..9]
42
+ end
43
+
46
44
  private
47
45
 
48
46
  def create_deployment_on_github(client)
49
47
  client.create_deployment(
50
48
  stack.github_repo_name,
51
- pull_request_head,
49
+ sha,
52
50
  auto_merge: false,
53
51
  required_contexts: [],
54
- description: "Via Shipit",
52
+ description: "Via #{Shipit.app_name}",
55
53
  environment: stack.environment,
54
+ payload: {
55
+ shipit: {
56
+ task_id: task.id,
57
+ from_sha: task.since_commit.sha,
58
+ to_sha: task.until_commit.sha,
59
+ },
60
+ }.to_json,
56
61
  )
57
62
  end
58
63
  end
@@ -1,5 +1,8 @@
1
+ # frozen_string_literal: true
1
2
  module Shipit
2
- class CommitDeploymentStatus < ActiveRecord::Base
3
+ class CommitDeploymentStatus < Record
4
+ DESCRIPTION_CHARACTER_LIMIT_ON_GITHUB = 140
5
+
3
6
  belongs_to :commit_deployment
4
7
 
5
8
  after_commit :schedule_create_on_github, on: :create
@@ -25,7 +28,7 @@ module Shipit
25
28
  def description
26
29
  I18n.t(
27
30
  "deployment_description.#{task_type}.#{status}",
28
- sha: task.until_commit.sha,
31
+ sha: task.until_commit.short_sha,
29
32
  author: task.author.login,
30
33
  stack: stack.to_param,
31
34
  )
@@ -45,8 +48,10 @@ module Shipit
45
48
  client.create_deployment_status(
46
49
  commit_deployment.api_url,
47
50
  status,
51
+ accept: 'application/vnd.github.flash-preview+json',
48
52
  target_url: url_helpers.stack_deploy_url(stack, task),
49
- description: description,
53
+ description: description.truncate(DESCRIPTION_CHARACTER_LIMIT_ON_GITHUB),
54
+ environment_url: stack.deploy_url,
50
55
  )
51
56
  end
52
57
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Shipit
2
3
  class CommitMessage
3
4
  GITHUB_MERGE_COMMIT_PATTERN = /\AMerge pull request #(?<pr_id>\d+) from \S+\n\n(?<pr_title>.*)/
@@ -1,11 +1,12 @@
1
+ # frozen_string_literal: true
1
2
  module Shipit
2
- class Delivery < ActiveRecord::Base
3
+ class Delivery < Record
3
4
  STATUSES = %w(pending scheduled sent).freeze
4
5
  enum status: STATUSES.zip(STATUSES).to_h
5
6
 
6
7
  belongs_to :hook
7
8
 
8
- validates :url, presence: true, url: {no_local: true, allow_blank: true}
9
+ validates :url, presence: true, url: { no_local: true, allow_blank: true }
9
10
  validates :content_type, presence: true
10
11
 
11
12
  serialize :response_headers, JSON
@@ -36,7 +37,7 @@ module Shipit
36
37
  def http
37
38
  Faraday::Connection.new do |connection|
38
39
  connection.headers = headers
39
- connection.adapter Faraday.default_adapter
40
+ connection.adapter(Faraday.default_adapter)
40
41
  end
41
42
  end
42
43
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'fileutils'
2
3
 
3
4
  module Shipit
@@ -14,20 +15,41 @@ module Shipit
14
15
  after_transition any => any, do: :update_last_deploy_time
15
16
  end
16
17
 
18
+ belongs_to :until_commit, class_name: 'Commit', required: true, inverse_of: :deploys
19
+ belongs_to :since_commit, class_name: 'Commit', required: true, inverse_of: :deploys
17
20
  has_many :commit_deployments, dependent: :destroy, inverse_of: :task, foreign_key: :task_id do
18
21
  GITHUB_STATUSES = {
19
22
  'pending' => 'pending',
23
+ 'running' => 'in_progress',
20
24
  'failed' => 'failure',
25
+ 'timedout' => 'failure',
21
26
  'success' => 'success',
27
+ 'faulty' => 'error',
22
28
  'error' => 'error',
23
29
  'aborted' => 'error',
24
30
  }.freeze
25
31
 
26
32
  def append_status(task_status)
27
33
  if github_status = GITHUB_STATUSES[task_status]
28
- each do |deployment|
34
+ # Deployments and statuses are created async, we reload the association to ensure we update all instances
35
+ reload.each do |deployment|
36
+ Rails.logger.info(
37
+ "Creating #{github_status} deploy status for deployment #{deployment.id}. "\
38
+ "Commit: #{deployment.sha}, Github id: #{deployment.github_id}, "\
39
+ "Repo: #{deployment.stack.repo_name}, Environment: #{deployment.stack.environment}, "\
40
+ "API Url: #{deployment.api_url}.",
41
+ )
29
42
  deployment.statuses.create!(status: github_status)
30
43
  end
44
+ else
45
+ each do |deployment|
46
+ Rails.logger.warn(
47
+ "No GitHub status for task status #{task_status}. "\
48
+ "Commit: #{deployment.sha}, Github id: #{deployment.github_id}, "\
49
+ "Repo: #{deployment.stack.repo_name}, Environment: #{deployment.stack.environment}, "\
50
+ "API Url: #{deployment.api_url}.",
51
+ )
52
+ end
31
53
  end
32
54
  end
33
55
  end
@@ -87,8 +109,8 @@ module Shipit
87
109
  end
88
110
 
89
111
  # Rolls the stack back to the most recent **previous** successful deploy
90
- def trigger_revert(force: false)
91
- previous_successful_commit = commit_to_rollback_to
112
+ def trigger_revert(force: false, rollback_to: nil)
113
+ previous_successful_commit = rollback_to&.until_commit || commit_to_rollback_to
92
114
 
93
115
  rollback = Rollback.create!(
94
116
  user_id: user_id,
@@ -215,12 +237,24 @@ module Shipit
215
237
  end
216
238
  end
217
239
 
240
+ def update_commit_deployments
241
+ commit_deployments.append_status(status)
242
+ end
243
+
218
244
  private
219
245
 
220
246
  def create_commit_deployments
221
- commits.each do |commit|
222
- commit_deployments.create!(commit: commit)
247
+ # Create one deployment for the head of the batch
248
+ commit_deployments.create!(sha: until_commit.sha)
249
+
250
+ # Create one for each pull request in the batch, to give feedback on the PR timeline
251
+ commits.select(&:pull_request?).each do |commit|
252
+ next if commit.pull_request_head_sha.blank? # This attribute was not always populated
253
+ commit_deployments.create!(sha: commit.pull_request_head_sha)
223
254
  end
255
+
256
+ # Immediately update to publish the status to the commit deployments
257
+ update_commit_deployments
224
258
  end
225
259
 
226
260
  def update_release_status
@@ -245,14 +279,10 @@ module Shipit
245
279
  end
246
280
  end
247
281
 
248
- def update_commit_deployments
249
- commit_deployments.append_status(status)
250
- end
251
-
252
282
  def trigger_revert_if_required
253
283
  return unless rollback_once_aborted?
254
284
  return unless supports_rollback?
255
- trigger_revert
285
+ trigger_revert(rollback_to: rollback_once_aborted_to)
256
286
  end
257
287
 
258
288
  def default_since_commit_id
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'pathname'
2
3
 
3
4
  module Shipit
@@ -5,20 +6,34 @@ module Shipit
5
6
  Error = Class.new(StandardError)
6
7
 
7
8
  class << self
9
+ attr_accessor :pretty_generate
10
+
8
11
  def load(json)
9
12
  config = json.blank? ? {} : JSON.parse(json)
10
13
  new(config)
11
14
  end
12
15
 
13
16
  def dump(spec)
14
- JSON.dump(spec.cacheable.config) if spec
17
+ return unless spec
18
+
19
+ if pretty_generate?
20
+ JSON.pretty_generate(spec.cacheable.config)
21
+ else
22
+ JSON.dump(spec.cacheable.config)
23
+ end
15
24
  end
16
25
 
17
26
  def bundle_path
18
27
  Rails.root.join('data', 'bundler')
19
28
  end
29
+
30
+ def pretty_generate?
31
+ @pretty_generate
32
+ end
20
33
  end
21
34
 
35
+ self.pretty_generate = false
36
+
22
37
  def initialize(config)
23
38
  @config = config
24
39
  end
@@ -40,6 +55,10 @@ module Shipit
40
55
  end
41
56
  end
42
57
 
58
+ def blank?
59
+ config.empty?
60
+ end
61
+
43
62
  def supports_fetch_deployed_revision?
44
63
  fetch_deployed_revision_steps.present?
45
64
  end
@@ -255,11 +274,11 @@ module Shipit
255
274
  end
256
275
 
257
276
  def task_not_found!(id)
258
- raise TaskDefinition::NotFound.new("No definition for task #{id.inspect}")
277
+ raise TaskDefinition::NotFound, "No definition for task #{id.inspect}"
259
278
  end
260
279
 
261
280
  def cant_detect!(type)
262
- raise DeploySpec::Error.new(I18n.t("deploy_spec.hint.#{type}"))
281
+ raise DeploySpec::Error, I18n.t("deploy_spec.hint.#{type}")
263
282
  end
264
283
  end
265
284
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Shipit
2
3
  class DeploySpec
3
4
  module BundlerDiscovery
@@ -31,7 +32,7 @@ module Shipit
31
32
 
32
33
  def remove_ruby_version_from_gemfile
33
34
  # Heroku apps often specify a ruby version.
34
- if /darwin/ =~ RUBY_PLATFORM
35
+ if /darwin/i.match?(RUBY_PLATFORM)
35
36
  # OSX is nitpicky about the -i.
36
37
  %q(/usr/bin/sed -i '' '/^ruby\s/d' Gemfile)
37
38
  else
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Shipit
2
3
  class DeploySpec
3
4
  module CapistranoDiscovery
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Shipit
2
3
  class DeploySpec
3
4
  class FileSystem < DeploySpec
@@ -61,14 +62,14 @@ module Shipit
61
62
  'context' => release_status_context,
62
63
  'delay' => release_status_delay,
63
64
  },
64
- 'dependencies' => {'override' => dependencies_steps},
65
+ 'dependencies' => { 'override' => dependencies_steps },
65
66
  'deploy' => {
66
67
  'override' => deploy_steps,
67
68
  'variables' => deploy_variables.map(&:to_h),
68
69
  'max_commits' => maximum_commits_per_deploy,
69
70
  'interval' => pause_between_deploys,
70
71
  },
71
- 'rollback' => {'override' => rollback_steps},
72
+ 'rollback' => { 'override' => rollback_steps },
72
73
  'fetch' => fetch_deployed_revision_steps,
73
74
  'tasks' => cacheable_tasks,
74
75
  )
@@ -84,10 +85,16 @@ module Shipit
84
85
  end
85
86
 
86
87
  def load_config
87
- read_config(file("shipit.#{@env}.yml", root: true)) ||
88
+ read_config(file("#{app_name}.#{@env}.yml", root: true)) ||
89
+ read_config(file("#{app_name}.yml", root: true)) ||
90
+ read_config(file("shipit.#{@env}.yml", root: true)) ||
88
91
  read_config(file('shipit.yml', root: true))
89
92
  end
90
93
 
94
+ def app_name
95
+ @app_name ||= Shipit.app_name.downcase
96
+ end
97
+
91
98
  def read_config(path)
92
99
  SafeYAML.load(path.read) if path.exist?
93
100
  end