shipit-engine 0.31.0 → 0.32.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (290) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +4 -2
  3. data/Rakefile +4 -2
  4. data/app/assets/stylesheets/_pages/_stacks.scss +0 -3
  5. data/app/assets/stylesheets/merge_status.scss +0 -3
  6. data/app/controllers/concerns/shipit/active_model_serializers_patch.rb +1 -0
  7. data/app/controllers/concerns/shipit/api/cacheable.rb +1 -0
  8. data/app/controllers/concerns/shipit/api/paginable.rb +3 -2
  9. data/app/controllers/concerns/shipit/api/rendering.rb +5 -4
  10. data/app/controllers/concerns/shipit/authentication.rb +3 -2
  11. data/app/controllers/concerns/shipit/pagination.rb +2 -1
  12. data/app/controllers/shipit/api/base_controller.rb +11 -6
  13. data/app/controllers/shipit/api/ccmenu_controller.rb +2 -1
  14. data/app/controllers/shipit/api/commits_controller.rb +2 -1
  15. data/app/controllers/shipit/api/deploys_controller.rb +4 -3
  16. data/app/controllers/shipit/api/hooks_controller.rb +6 -5
  17. data/app/controllers/shipit/api/locks_controller.rb +5 -4
  18. data/app/controllers/shipit/api/outputs_controller.rb +2 -1
  19. data/app/controllers/shipit/api/pull_requests_controller.rb +7 -6
  20. data/app/controllers/shipit/api/release_statuses_controller.rb +3 -2
  21. data/app/controllers/shipit/api/rollbacks_controller.rb +33 -0
  22. data/app/controllers/shipit/api/stacks_controller.rb +18 -5
  23. data/app/controllers/shipit/api/tasks_controller.rb +6 -5
  24. data/app/controllers/shipit/api_clients_controller.rb +4 -3
  25. data/app/controllers/shipit/ccmenu_url_controller.rb +4 -3
  26. data/app/controllers/shipit/commit_checks_controller.rb +2 -1
  27. data/app/controllers/shipit/commits_controller.rb +2 -1
  28. data/app/controllers/shipit/deploys_controller.rb +3 -2
  29. data/app/controllers/shipit/github_authentication_controller.rb +4 -3
  30. data/app/controllers/shipit/merge_status_controller.rb +17 -16
  31. data/app/controllers/shipit/pull_requests_controller.rb +3 -2
  32. data/app/controllers/shipit/release_statuses_controller.rb +3 -2
  33. data/app/controllers/shipit/rollbacks_controller.rb +3 -2
  34. data/app/controllers/shipit/shipit_controller.rb +2 -1
  35. data/app/controllers/shipit/stacks_controller.rb +22 -7
  36. data/app/controllers/shipit/status_controller.rb +2 -1
  37. data/app/controllers/shipit/tasks_controller.rb +6 -5
  38. data/app/controllers/shipit/webhooks_controller.rb +3 -2
  39. data/app/helpers/shipit/chunks_helper.rb +1 -0
  40. data/app/helpers/shipit/deploys_helper.rb +4 -3
  41. data/app/helpers/shipit/github_url_helper.rb +1 -0
  42. data/app/helpers/shipit/merge_status_helper.rb +1 -0
  43. data/app/helpers/shipit/shipit_helper.rb +1 -0
  44. data/app/helpers/shipit/stacks_helper.rb +1 -0
  45. data/app/helpers/shipit/tasks_helper.rb +1 -0
  46. data/app/jobs/shipit/background_job.rb +4 -0
  47. data/app/jobs/shipit/background_job/unique.rb +1 -0
  48. data/app/jobs/shipit/cache_deploy_spec_job.rb +1 -0
  49. data/app/jobs/shipit/chunk_rollup_job.rb +4 -0
  50. data/app/jobs/shipit/clear_git_cache_job.rb +1 -0
  51. data/app/jobs/shipit/continuous_delivery_job.rb +2 -1
  52. data/app/jobs/shipit/create_on_github_job.rb +6 -1
  53. data/app/jobs/shipit/create_release_statuses_job.rb +1 -0
  54. data/app/jobs/shipit/deferred_touch_job.rb +4 -0
  55. data/app/jobs/shipit/deliver_hook_job.rb +1 -0
  56. data/app/jobs/shipit/destroy_job.rb +1 -0
  57. data/app/jobs/shipit/destroy_stack_job.rb +1 -0
  58. data/app/jobs/shipit/emit_event_job.rb +2 -1
  59. data/app/jobs/shipit/fetch_commit_stats_job.rb +1 -0
  60. data/app/jobs/shipit/fetch_deployed_revision_job.rb +1 -0
  61. data/app/jobs/shipit/github_sync_job.rb +2 -1
  62. data/app/jobs/shipit/mark_deploy_healthy_job.rb +1 -0
  63. data/app/jobs/shipit/merge_pull_requests_job.rb +1 -0
  64. data/app/jobs/shipit/perform_commit_checks_job.rb +1 -0
  65. data/app/jobs/shipit/perform_task_job.rb +12 -5
  66. data/app/jobs/shipit/purge_old_deliveries_job.rb +1 -0
  67. data/app/jobs/shipit/reap_dead_tasks_job.rb +21 -0
  68. data/app/jobs/shipit/refresh_check_runs_job.rb +1 -0
  69. data/app/jobs/shipit/refresh_github_user_job.rb +1 -0
  70. data/app/jobs/shipit/refresh_pull_request_job.rb +1 -0
  71. data/app/jobs/shipit/refresh_statuses_job.rb +1 -0
  72. data/app/jobs/shipit/setup_github_hook_job.rb +1 -0
  73. data/app/jobs/shipit/update_estimated_deploy_duration_job.rb +1 -0
  74. data/app/jobs/shipit/update_github_last_deployed_ref_job.rb +4 -3
  75. data/app/models/concerns/shipit/deferred_touch.rb +4 -3
  76. data/app/models/shipit/anonymous_user.rb +5 -0
  77. data/app/models/shipit/api_client.rb +3 -2
  78. data/app/models/shipit/application_record.rb +2 -1
  79. data/app/models/shipit/check_run.rb +4 -3
  80. data/app/models/shipit/command_line_user.rb +1 -0
  81. data/app/models/shipit/commit.rb +11 -4
  82. data/app/models/shipit/commit_checks.rb +1 -0
  83. data/app/models/shipit/commit_deployment.rb +3 -2
  84. data/app/models/shipit/commit_deployment_status.rb +2 -1
  85. data/app/models/shipit/commit_message.rb +1 -0
  86. data/app/models/shipit/delivery.rb +4 -3
  87. data/app/models/shipit/deploy.rb +6 -17
  88. data/app/models/shipit/deploy_spec.rb +22 -3
  89. data/app/models/shipit/deploy_spec/bundler_discovery.rb +1 -0
  90. data/app/models/shipit/deploy_spec/capistrano_discovery.rb +1 -0
  91. data/app/models/shipit/deploy_spec/file_system.rb +10 -3
  92. data/app/models/shipit/deploy_spec/kubernetes_discovery.rb +1 -0
  93. data/app/models/shipit/deploy_spec/lerna_discovery.rb +1 -0
  94. data/app/models/shipit/deploy_spec/npm_discovery.rb +5 -4
  95. data/app/models/shipit/deploy_spec/pypi_discovery.rb +1 -0
  96. data/app/models/shipit/deploy_spec/rubygems_discovery.rb +1 -0
  97. data/app/models/shipit/deploy_stats.rb +2 -1
  98. data/app/models/shipit/duration.rb +3 -2
  99. data/app/models/shipit/ephemeral_commit_checks.rb +1 -0
  100. data/app/models/shipit/github_hook.rb +2 -1
  101. data/app/models/shipit/github_status.rb +2 -1
  102. data/app/models/shipit/hook.rb +6 -5
  103. data/app/models/shipit/membership.rb +3 -2
  104. data/app/models/shipit/output_chunk.rb +7 -2
  105. data/app/models/shipit/pull_request.rb +6 -5
  106. data/app/models/shipit/record.rb +18 -0
  107. data/app/models/shipit/release_status.rb +3 -2
  108. data/app/models/shipit/repository.rb +10 -5
  109. data/app/models/shipit/rollback.rb +1 -0
  110. data/app/models/shipit/stack.rb +50 -16
  111. data/app/models/shipit/status.rb +3 -2
  112. data/app/models/shipit/status/common.rb +7 -6
  113. data/app/models/shipit/status/group.rb +1 -0
  114. data/app/models/shipit/status/missing.rb +2 -1
  115. data/app/models/shipit/status/unknown.rb +2 -1
  116. data/app/models/shipit/task.rb +38 -5
  117. data/app/models/shipit/task_definition.rb +1 -0
  118. data/app/models/shipit/team.rb +2 -1
  119. data/app/models/shipit/undeployed_commit.rb +1 -0
  120. data/app/models/shipit/unlimited_api_client.rb +1 -0
  121. data/app/models/shipit/user.rb +10 -8
  122. data/app/models/shipit/variable_definition.rb +1 -0
  123. data/app/models/shipit/webhooks.rb +1 -0
  124. data/app/models/shipit/webhooks/handlers/check_suite_handler.rb +1 -0
  125. data/app/models/shipit/webhooks/handlers/handler.rb +1 -0
  126. data/app/models/shipit/webhooks/handlers/membership_handler.rb +1 -0
  127. data/app/models/shipit/webhooks/handlers/push_handler.rb +1 -0
  128. data/app/models/shipit/webhooks/handlers/status_handler.rb +1 -0
  129. data/app/serializers/concerns/shipit/conditional_attributes.rb +1 -0
  130. data/app/serializers/shipit/anonymous_user_serializer.rb +1 -0
  131. data/app/serializers/shipit/command_line_user_serializer.rb +1 -0
  132. data/app/serializers/shipit/commit_serializer.rb +1 -0
  133. data/app/serializers/shipit/deploy_serializer.rb +2 -1
  134. data/app/serializers/shipit/hook_serializer.rb +1 -0
  135. data/app/serializers/shipit/pull_request_serializer.rb +1 -0
  136. data/app/serializers/shipit/rollback_serializer.rb +1 -0
  137. data/app/serializers/shipit/short_commit_serializer.rb +1 -0
  138. data/app/serializers/shipit/stack_serializer.rb +1 -0
  139. data/app/serializers/shipit/tail_task_serializer.rb +1 -0
  140. data/app/serializers/shipit/task_serializer.rb +2 -17
  141. data/app/serializers/shipit/user_serializer.rb +6 -1
  142. data/app/validators/ascii_only_validator.rb +1 -0
  143. data/app/validators/subset_validator.rb +1 -0
  144. data/app/views/layouts/shipit.html.erb +1 -1
  145. data/app/views/shipit/_variables.html.erb +1 -1
  146. data/app/views/shipit/ccmenu/project.xml.builder +2 -1
  147. data/app/views/shipit/deploys/show.html.erb +2 -2
  148. data/app/views/shipit/stacks/_header.html.erb +3 -0
  149. data/app/views/shipit/stacks/all_tasks.html.erb +28 -0
  150. data/app/views/shipit/stacks/index.html.erb +1 -1
  151. data/app/views/shipit/tasks/show.html.erb +1 -1
  152. data/config/initializers/inflections.rb +2 -1
  153. data/config/locales/en.yml +3 -3
  154. data/config/routes.rb +10 -2
  155. data/db/migrate/20200226211925_add_index_to_tasks_status.rb +5 -0
  156. data/db/migrate/20200427135152_add_pull_request_head_sha_to_commit.rb +5 -0
  157. data/db/migrate/20200615181558_add_rollback_once_aborted_to.rb +5 -0
  158. data/lib/shipit.rb +12 -2
  159. data/lib/shipit/cast_value.rb +1 -0
  160. data/lib/shipit/command.rb +13 -12
  161. data/lib/shipit/commands.rb +5 -4
  162. data/lib/shipit/csv_serializer.rb +1 -0
  163. data/lib/shipit/deploy_commands.rb +1 -0
  164. data/lib/shipit/engine.rb +7 -2
  165. data/lib/shipit/environment_variables.rb +2 -1
  166. data/lib/shipit/first_parent_commits_iterator.rb +1 -0
  167. data/lib/shipit/flock.rb +1 -0
  168. data/lib/shipit/github_app.rb +7 -6
  169. data/lib/shipit/github_http_cache_middleware.rb +1 -0
  170. data/lib/shipit/null_serializer.rb +1 -0
  171. data/lib/shipit/octokit_check_runs.rb +3 -2
  172. data/lib/shipit/octokit_iterator.rb +3 -2
  173. data/lib/shipit/paginator.rb +3 -2
  174. data/lib/shipit/rollback_commands.rb +1 -0
  175. data/lib/shipit/same_site_cookie_middleware.rb +29 -0
  176. data/lib/shipit/simple_message_verifier.rb +1 -0
  177. data/lib/shipit/stack_commands.rb +3 -2
  178. data/lib/shipit/stat.rb +1 -0
  179. data/lib/shipit/task_commands.rb +2 -0
  180. data/lib/shipit/version.rb +2 -1
  181. data/lib/snippets/release-gem +5 -1
  182. data/lib/tasks/cron.rake +2 -0
  183. data/lib/tasks/dev.rake +3 -2
  184. data/lib/tasks/shipit.rake +15 -14
  185. data/lib/tasks/teams.rake +1 -0
  186. data/test/controllers/api/base_controller_test.rb +3 -2
  187. data/test/controllers/api/ccmenu_controller_test.rb +8 -7
  188. data/test/controllers/api/commits_controller_test.rb +3 -2
  189. data/test/controllers/api/deploys_controller_test.rb +15 -14
  190. data/test/controllers/api/hooks_controller_test.rb +8 -7
  191. data/test/controllers/api/locks_controller_test.rb +7 -6
  192. data/test/controllers/api/outputs_controller_test.rb +2 -1
  193. data/test/controllers/api/pull_requests_controller_test.rb +8 -7
  194. data/test/controllers/api/release_statuses_controller_test.rb +2 -1
  195. data/test/controllers/api/rollback_controller_test.rb +113 -0
  196. data/test/controllers/api/stacks_controller_test.rb +30 -9
  197. data/test/controllers/api/tasks_controller_test.rb +13 -12
  198. data/test/controllers/api_clients_controller_test.rb +5 -4
  199. data/test/controllers/ccmenu_controller_test.rb +4 -3
  200. data/test/controllers/commit_checks_controller_test.rb +4 -3
  201. data/test/controllers/commits_controller_test.rb +3 -2
  202. data/test/controllers/deploys_controller_test.rb +32 -21
  203. data/test/controllers/github_authentication_controller_test.rb +1 -0
  204. data/test/controllers/merge_status_controller_test.rb +7 -6
  205. data/test/controllers/pull_requests_controller_test.rb +4 -3
  206. data/test/controllers/release_statuses_controller_test.rb +3 -2
  207. data/test/controllers/rollbacks_controller_test.rb +9 -8
  208. data/test/controllers/stacks_controller_test.rb +33 -19
  209. data/test/controllers/status_controller_test.rb +1 -0
  210. data/test/controllers/tasks_controller_test.rb +19 -18
  211. data/test/controllers/webhooks_controller_test.rb +11 -10
  212. data/test/dummy/config/environments/development.rb +2 -0
  213. data/test/dummy/config/environments/test.rb +2 -0
  214. data/test/dummy/db/schema.rb +4 -1
  215. data/test/fixtures/shipit/commits.yml +15 -0
  216. data/test/fixtures/shipit/repositories.yml +4 -0
  217. data/test/fixtures/shipit/stacks.yml +90 -14
  218. data/test/fixtures/timeout +2 -1
  219. data/test/helpers/api_helper.rb +1 -0
  220. data/test/helpers/fixture_aliases_helper.rb +1 -0
  221. data/test/helpers/hooks_helper.rb +2 -1
  222. data/test/helpers/json_helper.rb +15 -11
  223. data/test/helpers/links_helper.rb +4 -3
  224. data/test/helpers/payloads_helper.rb +1 -0
  225. data/test/helpers/queries_helper.rb +3 -2
  226. data/test/jobs/cache_deploy_spec_job_test.rb +2 -1
  227. data/test/jobs/chunk_rollup_job_test.rb +1 -0
  228. data/test/jobs/deliver_hook_job_test.rb +1 -0
  229. data/test/jobs/destroy_stack_job_test.rb +1 -0
  230. data/test/jobs/emit_event_job_test.rb +2 -1
  231. data/test/jobs/fetch_commit_stats_job_test.rb +1 -0
  232. data/test/jobs/fetch_deployed_revision_job_test.rb +1 -0
  233. data/test/jobs/github_sync_job_test.rb +1 -0
  234. data/test/jobs/mark_deploy_healthy_job_test.rb +1 -0
  235. data/test/jobs/merge_pull_requests_job_test.rb +1 -0
  236. data/test/jobs/perform_task_job_test.rb +4 -3
  237. data/test/jobs/purge_old_deliveries_job_test.rb +1 -0
  238. data/test/jobs/reap_dead_tasks_job_test.rb +68 -0
  239. data/test/jobs/refresh_github_user_job_test.rb +1 -0
  240. data/test/jobs/refresh_status_job_test.rb +1 -0
  241. data/test/jobs/unique_job_test.rb +1 -0
  242. data/test/jobs/update_github_last_deployed_ref_job_test.rb +1 -0
  243. data/test/middleware/same_site_cookie_middleware_test.rb +52 -0
  244. data/test/models/api_client_test.rb +1 -0
  245. data/test/models/commit_checks_test.rb +1 -0
  246. data/test/models/commit_deployment_status_test.rb +1 -0
  247. data/test/models/commit_deployment_test.rb +2 -1
  248. data/test/models/commits_test.rb +72 -6
  249. data/test/models/delivery_test.rb +2 -1
  250. data/test/models/deploy_spec_test.rb +47 -42
  251. data/test/models/deploy_stats_test.rb +1 -0
  252. data/test/models/deploys_test.rb +31 -22
  253. data/test/models/duration_test.rb +1 -0
  254. data/test/models/github_hook_test.rb +1 -0
  255. data/test/models/hook_test.rb +18 -10
  256. data/test/models/membership_test.rb +1 -0
  257. data/test/models/output_chunk_test.rb +1 -0
  258. data/test/models/pull_request_test.rb +4 -3
  259. data/test/models/release_statuses_test.rb +1 -0
  260. data/test/models/rollbacks_test.rb +1 -0
  261. data/test/models/shipit/check_run_test.rb +1 -0
  262. data/test/models/shipit/repository_test.rb +1 -0
  263. data/test/models/shipit/wehbooks/handlers_test.rb +1 -0
  264. data/test/models/stacks_test.rb +30 -8
  265. data/test/models/status/group_test.rb +1 -0
  266. data/test/models/status/missing_test.rb +1 -0
  267. data/test/models/status_test.rb +1 -0
  268. data/test/models/task_definitions_test.rb +9 -8
  269. data/test/models/tasks_test.rb +18 -1
  270. data/test/models/team_test.rb +4 -2
  271. data/test/models/undeployed_commits_test.rb +1 -0
  272. data/test/models/users_test.rb +13 -5
  273. data/test/test_command_integration.rb +3 -2
  274. data/test/test_helper.rb +34 -31
  275. data/test/unit/anonymous_user_serializer_test.rb +14 -0
  276. data/test/unit/command_test.rb +8 -7
  277. data/test/unit/commands_test.rb +1 -0
  278. data/test/unit/commit_serializer_test.rb +16 -0
  279. data/test/unit/csv_serializer_test.rb +3 -2
  280. data/test/unit/deploy_commands_test.rb +5 -4
  281. data/test/unit/deploy_serializer_test.rb +17 -0
  282. data/test/unit/environment_variables_test.rb +5 -4
  283. data/test/unit/github_app_test.rb +1 -0
  284. data/test/unit/github_url_helper_test.rb +1 -0
  285. data/test/unit/rollback_commands_test.rb +2 -1
  286. data/test/unit/shipit_helper_test.rb +17 -0
  287. data/test/unit/shipit_test.rb +1 -0
  288. data/test/unit/user_serializer_test.rb +14 -0
  289. data/test/unit/variable_definition_test.rb +1 -0
  290. metadata +155 -130
@@ -1,8 +1,9 @@
1
+ # frozen_string_literal: true
1
2
  module Shipit
2
3
  class PullRequest < ApplicationRecord
3
4
  include DeferredTouch
4
5
 
5
- MERGE_REQUEST_FIELD = 'Merge-Requested-By'.freeze
6
+ MERGE_REQUEST_FIELD = 'Merge-Requested-By'
6
7
 
7
8
  WAITING_STATUSES = %w(fetching pending).freeze
8
9
  QUEUED_STATUSES = %w(pending revalidating).freeze
@@ -45,7 +46,7 @@ module Shipit
45
46
 
46
47
  deferred_touch stack: :updated_at
47
48
 
48
- validates :number, presence: true, uniqueness: {scope: :stack_id}
49
+ validates :number, presence: true, uniqueness: { scope: :stack_id }
49
50
 
50
51
  scope :waiting, -> { where(merge_status: WAITING_STATUSES) }
51
52
  scope :pending, -> { where(merge_status: 'pending') }
@@ -176,10 +177,10 @@ module Shipit
176
177
  # branch was already deleted somehow
177
178
  end
178
179
  complete!
179
- return true
180
+ true
180
181
  rescue Octokit::MethodNotAllowed # merge conflict
181
182
  reject!('merge_conflict')
182
- return false
183
+ false
183
184
  rescue Octokit::Conflict # shas didn't match, PR was updated.
184
185
  raise NotReady
185
186
  end
@@ -289,7 +290,7 @@ module Shipit
289
290
 
290
291
  def find_or_create_commit_from_github_by_sha!(sha, attributes)
291
292
  if commit = stack.commits.by_sha(sha)
292
- return commit
293
+ commit
293
294
  else
294
295
  github_commit = Shipit.github.api.commit(stack.github_repo_name, sha)
295
296
  stack.commits.create_from_github!(github_commit, attributes)
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+ module Shipit
3
+ class Record < ActiveRecord::Base
4
+ self.abstract_class = true
5
+
6
+ class << self
7
+ def serializer_class
8
+ if defined? @serializer_class
9
+ @serializer_class
10
+ else
11
+ @serializer_class = "#{name}Serializer".safe_constantize
12
+ end
13
+ end
14
+ end
15
+
16
+ delegate :serializer_class, to: :class
17
+ end
18
+ end
@@ -1,5 +1,6 @@
1
+ # frozen_string_literal: true
1
2
  module Shipit
2
- class ReleaseStatus < ActiveRecord::Base
3
+ class ReleaseStatus < Record
3
4
  MAX_DESCRIPTION_LENGTH = 140
4
5
  include DeferredTouch
5
6
 
@@ -13,7 +14,7 @@ module Shipit
13
14
  scope :to_be_created, -> { where(github_id: nil).order(id: :asc) }
14
15
 
15
16
  STATES = %w(pending success failure error).freeze
16
- validates :state, presence: true, inclusion: {in: STATES}
17
+ validates :state, presence: true, inclusion: { in: STATES }
17
18
 
18
19
  def create_status_on_github!
19
20
  return true if github_id?
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Shipit
2
3
  class Repository < ApplicationRecord
3
4
  OWNER_MAX_SIZE = 39
@@ -6,11 +7,11 @@ module Shipit
6
7
  NAME_MAX_SIZE = 100
7
8
  private_constant :NAME_MAX_SIZE
8
9
 
9
- validates :name, uniqueness: {scope: %i(owner), case_sensitive: false,
10
- message: 'cannot be used more than once'}
10
+ validates :name, uniqueness: { scope: %i(owner), case_sensitive: false,
11
+ message: 'cannot be used more than once' }
11
12
  validates :owner, :name, presence: true, ascii_only: true
12
- validates :owner, format: {with: /\A[a-z0-9_\-\.]+\z/}, length: {maximum: OWNER_MAX_SIZE}
13
- validates :name, format: {with: /\A[a-z0-9_\-\.]+\z/}, length: {maximum: NAME_MAX_SIZE}
13
+ validates :owner, format: { with: /\A[a-z0-9_\-\.]+\z/ }, length: { maximum: OWNER_MAX_SIZE }
14
+ validates :name, format: { with: /\A[a-z0-9_\-\.]+\z/ }, length: { maximum: NAME_MAX_SIZE }
14
15
 
15
16
  has_many :stacks, dependent: :destroy
16
17
 
@@ -28,7 +29,11 @@ module Shipit
28
29
  end
29
30
 
30
31
  def http_url
31
- Shipit.github.url("#{owner}/#{name}")
32
+ Shipit.github.url(full_name)
33
+ end
34
+
35
+ def full_name
36
+ "#{owner}/#{name}"
32
37
  end
33
38
 
34
39
  def git_url
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Shipit
2
3
  class Rollback < Deploy
3
4
  belongs_to :deploy, foreign_key: :parent_id, inverse_of: false
@@ -1,7 +1,8 @@
1
+ # frozen_string_literal: true
1
2
  require 'fileutils'
2
3
 
3
4
  module Shipit
4
- class Stack < ActiveRecord::Base
5
+ class Stack < Record
5
6
  module NoDeployedCommit
6
7
  extend self
7
8
 
@@ -43,6 +44,8 @@ module Shipit
43
44
 
44
45
  scope :not_archived, -> { where(archived_since: nil) }
45
46
 
47
+ default_scope { preload(:repository) }
48
+
46
49
  def env
47
50
  {
48
51
  'ENVIRONMENT' => environment,
@@ -82,10 +85,10 @@ module Shipit
82
85
  scope: %i(environment), case_sensitive: false,
83
86
  message: 'cannot be used more than once with this environment. Check archived stacks.'
84
87
  }
85
- validates :environment, format: {with: /\A[a-z0-9\-_\:]+\z/}, length: {maximum: ENVIRONMENT_MAX_SIZE}
86
- validates :deploy_url, format: {with: URI.regexp(%w(http https ssh))}, allow_blank: true
88
+ validates :environment, format: { with: /\A[a-z0-9\-_\:]+\z/ }, length: { maximum: ENVIRONMENT_MAX_SIZE }
89
+ validates :deploy_url, format: { with: URI.regexp(%w(http https ssh)) }, allow_blank: true
87
90
 
88
- validates :lock_reason, length: {maximum: 4096}
91
+ validates :lock_reason, length: { maximum: 4096 }
89
92
 
90
93
  serialize :cached_deploy_spec, DeploySpec
91
94
  delegate :find_task_definition, :supports_rollback?, :release_status?, :release_status_delay,
@@ -140,9 +143,24 @@ module Shipit
140
143
  end
141
144
 
142
145
  def trigger_deploy(*args, **kwargs)
146
+ if changed?
147
+ # If this is the first deploy since the spec changed it's possible the record will be dirty here, meaning we
148
+ # cant lock. In this one case persist the changes, otherwise log a warning and let the lock raise, so we
149
+ # can debug what's going on here. We don't expect anything other than the deploy spec to dirty the model
150
+ # instance, because of how that field is serialised.
151
+ if changes.keys == ['cached_deploy_spec']
152
+ save!
153
+ else
154
+ Rails.logger.warning("#{changes.keys} field(s) were unexpectedly modified on stack #{id} while deploying")
155
+ end
156
+ end
157
+
143
158
  run_now = kwargs.delete(:run_now)
144
- deploy = build_deploy(*args, **kwargs)
145
- deploy.save!
159
+ deploy = with_lock do
160
+ deploy = build_deploy(*args, **kwargs)
161
+ deploy.save!
162
+ deploy
163
+ end
146
164
  run_now ? deploy.run_now! : deploy.enqueue
147
165
  continuous_delivery_resumed!
148
166
  deploy
@@ -161,15 +179,16 @@ module Shipit
161
179
  end
162
180
 
163
181
  def trigger_continuous_delivery
182
+ return if cached_deploy_spec.blank?
183
+
164
184
  commit = next_commit_to_deploy
165
185
 
166
- if !deployable? || deployed_too_recently? || commit.nil? || commit.deployed?
186
+ if should_resume_continuous_delivery?(commit)
167
187
  continuous_delivery_resumed!
168
188
  return
169
189
  end
170
190
 
171
- if commit.deploy_failed? || (checks? && !EphemeralCommitChecks.new(commit).run.success?) ||
172
- commit.recently_pushed?
191
+ if should_delay_continuous_delivery?(commit)
173
192
  continuous_delivery_delayed!
174
193
  return
175
194
  end
@@ -201,7 +220,7 @@ module Shipit
201
220
  def async_refresh_deployed_revision
202
221
  async_refresh_deployed_revision!
203
222
  rescue => error
204
- logger.warn "Failed to dispatch FetchDeployedRevisionJob: [#{error.class.name}] #{error.message}"
223
+ logger.warn("Failed to dispatch FetchDeployedRevisionJob: [#{error.class.name}] #{error.message}")
205
224
  end
206
225
 
207
226
  def async_refresh_deployed_revision!
@@ -269,8 +288,8 @@ module Shipit
269
288
  next if commits_to_lock.empty?
270
289
 
271
290
  affected_rows += commits
272
- .where(id: commits_to_lock.map(&:id).uniq)
273
- .lock_all(revert.author)
291
+ .where(id: commits_to_lock.map(&:id).uniq)
292
+ .lock_all(revert.author)
274
293
  end
275
294
 
276
295
  touch if affected_rows > 1
@@ -409,7 +428,7 @@ module Shipit
409
428
  end
410
429
 
411
430
  def lock(reason, user)
412
- params = {lock_reason: reason, lock_author: user}
431
+ params = { lock_reason: reason, lock_author: user }
413
432
  update!(params)
414
433
  end
415
434
 
@@ -481,13 +500,15 @@ module Shipit
481
500
  end
482
501
 
483
502
  def update_latest_deployed_ref
484
- UpdateGithubLastDeployedRefJob.perform_later(self)
503
+ if Shipit.update_latest_deployed_ref
504
+ UpdateGithubLastDeployedRefJob.perform_later(self)
505
+ end
485
506
  end
486
507
 
487
508
  def broadcast_update
488
509
  Pubsubstub.publish(
489
510
  "stack.#{id}",
490
- {id: id, updated_at: updated_at}.to_json,
511
+ { id: id, updated_at: updated_at }.to_json,
491
512
  name: 'update',
492
513
  )
493
514
  end
@@ -581,7 +602,7 @@ module Shipit
581
602
  return unless previous_changes.include?('lock_reason')
582
603
 
583
604
  lock_details = if previous_changes['lock_reason'].last.blank?
584
- {from: previous_changes['locked_since'].first, until: Time.zone.now}
605
+ { from: previous_changes['locked_since'].first, until: Time.zone.now }
585
606
  end
586
607
 
587
608
  Hook.emit(:lock, self, locked: locked?, lock_details: lock_details, stack: self)
@@ -607,5 +628,18 @@ module Shipit
607
628
  def ci_enabled_cache_key
608
629
  "stacks:#{id}:ci_enabled"
609
630
  end
631
+
632
+ def should_resume_continuous_delivery?(commit)
633
+ !deployable? ||
634
+ deployed_too_recently? ||
635
+ commit.nil? ||
636
+ commit.deployed?
637
+ end
638
+
639
+ def should_delay_continuous_delivery?(commit)
640
+ commit.deploy_failed? ||
641
+ (checks? && !EphemeralCommitChecks.new(commit).run.success?) ||
642
+ commit.recently_pushed?
643
+ end
610
644
  end
611
645
  end
@@ -1,5 +1,6 @@
1
+ # frozen_string_literal: true
1
2
  module Shipit
2
- class Status < ActiveRecord::Base
3
+ class Status < Record
3
4
  include Common
4
5
  include DeferredTouch
5
6
 
@@ -11,7 +12,7 @@ module Shipit
11
12
 
12
13
  deferred_touch commit: :updated_at
13
14
 
14
- validates :state, inclusion: {in: STATES, allow_blank: true}, presence: true
15
+ validates :state, inclusion: { in: STATES, allow_blank: true }, presence: true
15
16
 
16
17
  after_create :enable_ci_on_stack
17
18
  after_commit :schedule_continuous_delivery, :broadcast_update, on: :create
@@ -1,24 +1,25 @@
1
+ # frozen_string_literal: true
1
2
  module Shipit
2
3
  class Status
3
4
  module Common
4
5
  def unknown?
5
- state == 'unknown'.freeze
6
+ state == 'unknown'
6
7
  end
7
8
 
8
9
  def pending?
9
- state == 'pending'.freeze
10
+ state == 'pending'
10
11
  end
11
12
 
12
13
  def success?
13
- state == 'success'.freeze
14
+ state == 'success'
14
15
  end
15
16
 
16
17
  def error?
17
- state == 'error'.freeze
18
+ state == 'error'
18
19
  end
19
20
 
20
21
  def failure?
21
- state == 'failure'.freeze
22
+ state == 'failure'
22
23
  end
23
24
 
24
25
  def missing?
@@ -30,7 +31,7 @@ module Shipit
30
31
  end
31
32
 
32
33
  def simple_state
33
- state == 'error'.freeze ? 'failure'.freeze : state
34
+ state == 'error' ? 'failure' : state
34
35
  end
35
36
 
36
37
  def allowed_to_fail?
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Shipit
2
3
  class Status
3
4
  class Group
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Shipit
2
3
  class Status
3
4
  class Missing
@@ -15,7 +16,7 @@ module Shipit
15
16
  end
16
17
 
17
18
  def state
18
- 'pending'.freeze
19
+ 'pending'
19
20
  end
20
21
 
21
22
  def missing?
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Shipit
2
3
  class Status
3
4
  class Unknown
@@ -21,7 +22,7 @@ module Shipit
21
22
  end
22
23
 
23
24
  def state
24
- 'unknown'.freeze
25
+ 'unknown'
25
26
  end
26
27
 
27
28
  def missing?
@@ -1,13 +1,17 @@
1
+ # frozen_string_literal: true
1
2
  module Shipit
2
- class Task < ActiveRecord::Base
3
+ class Task < Record
3
4
  include DeferredTouch
4
5
 
5
6
  ConcurrentTaskRunning = Class.new(StandardError)
6
7
 
7
- PRESENCE_CHECK_TIMEOUT = 15
8
+ PRESENCE_CHECK_TIMEOUT = 30
8
9
  ACTIVE_STATUSES = %w(pending running aborting).freeze
9
10
  COMPLETED_STATUSES = %w(success flapping faulty validating).freeze
10
11
  UNSUCCESSFUL_STATUSES = %w(error failed aborted flapping timedout faulty).freeze
12
+ OUTPUT_SIZE_LIMIT = 16.megabytes # A MySQL mediumblob
13
+ HUMAN_READABLE_OUTPUT_LIMIT = ActionController::Base.helpers.number_to_human_size(OUTPUT_SIZE_LIMIT)
14
+ OUTPUT_TRUNCATED_MESSAGE = "Output exceeded the limit of #{HUMAN_READABLE_OUTPUT_LIMIT} and was truncated\n"
11
15
 
12
16
  attr_accessor :pid
13
17
 
@@ -19,6 +23,8 @@ module Shipit
19
23
  belongs_to :until_commit, class_name: 'Commit', required: false
20
24
  belongs_to :since_commit, class_name: 'Commit', required: false
21
25
 
26
+ belongs_to :rollback_once_aborted_to, class_name: 'Task', optional: true
27
+
22
28
  deferred_touch stack: :updated_at
23
29
 
24
30
  has_many :chunks, -> { order(:id) }, class_name: 'OutputChunk', dependent: :delete_all, inverse_of: :task
@@ -198,7 +204,15 @@ module Shipit
198
204
  if rolled_up?
199
205
  output
200
206
  else
201
- chunks.pluck(:text).join
207
+ blob = chunks.pluck(:text).join
208
+
209
+ if blob.size > OUTPUT_SIZE_LIMIT
210
+ Rails.logger.warn("Task #{id} output exceeds limit of #{HUMAN_READABLE_OUTPUT_LIMIT}, and will be truncated.")
211
+ blob = blob.last(OUTPUT_SIZE_LIMIT - OUTPUT_TRUNCATED_MESSAGE.size)
212
+ blob = OUTPUT_TRUNCATED_MESSAGE + blob
213
+ end
214
+
215
+ blob
202
216
  end
203
217
  end
204
218
 
@@ -280,8 +294,12 @@ module Shipit
280
294
  end
281
295
  end
282
296
 
283
- def abort!(rollback_once_aborted: false, aborted_by:)
284
- update!(rollback_once_aborted: rollback_once_aborted, aborted_by_id: aborted_by.id)
297
+ def abort!(rollback_once_aborted: false, rollback_once_aborted_to: nil, aborted_by:)
298
+ update!(
299
+ rollback_once_aborted: rollback_once_aborted,
300
+ rollback_once_aborted_to: rollback_once_aborted_to,
301
+ aborted_by_id: aborted_by.id
302
+ )
285
303
 
286
304
  if alive?
287
305
  aborting
@@ -349,6 +367,21 @@ module Shipit
349
367
  end
350
368
  end
351
369
 
370
+ def self.recently_created_at
371
+ 5.minutes.ago
372
+ end
373
+
374
+ ZOMBIE_STATES = %w(running aborting).freeze
375
+ private_constant :ZOMBIE_STATES
376
+ def self.zombies
377
+ where(status: ZOMBIE_STATES)
378
+ .where(
379
+ "created_at <= :recently",
380
+ recently: recently_created_at,
381
+ )
382
+ .reject(&:alive?)
383
+ end
384
+
352
385
  private
353
386
 
354
387
  def prevent_concurrency
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Shipit
2
3
  class TaskDefinition
3
4
  NotFound = Class.new(StandardError)
@@ -1,5 +1,6 @@
1
+ # frozen_string_literal: true
1
2
  module Shipit
2
- class Team < ActiveRecord::Base
3
+ class Team < Record
3
4
  REQUIRED_HOOKS = %i(membership).freeze
4
5
 
5
6
  has_many :memberships