shipit-engine 0.32.0 → 0.35.1

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 (235) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +13 -2
  3. data/app/assets/images/magic-solid.svg +1 -0
  4. data/app/assets/javascripts/shipit/repositories_search.js.coffee +60 -0
  5. data/app/assets/javascripts/shipit/{search.js.coffee → stack_search.js.coffee} +0 -0
  6. data/app/assets/stylesheets/_pages/_deploy.scss +2 -3
  7. data/app/assets/stylesheets/_pages/_repositories.scss +148 -0
  8. data/app/assets/stylesheets/_pages/_stacks.scss +19 -0
  9. data/app/assets/stylesheets/shipit.scss +1 -0
  10. data/app/controllers/shipit/api/ccmenu_controller.rb +1 -1
  11. data/app/controllers/shipit/api/deploys_controller.rb +2 -0
  12. data/app/controllers/shipit/api/{pull_requests_controller.rb → merge_requests_controller.rb} +8 -8
  13. data/app/controllers/shipit/api/rollbacks_controller.rb +2 -1
  14. data/app/controllers/shipit/api/stacks_controller.rb +15 -1
  15. data/app/controllers/shipit/deploys_controller.rb +1 -1
  16. data/app/controllers/shipit/merge_requests_controller.rb +31 -0
  17. data/app/controllers/shipit/merge_status_controller.rb +15 -15
  18. data/app/controllers/shipit/repositories_controller.rb +74 -0
  19. data/app/controllers/shipit/stacks_controller.rb +2 -2
  20. data/app/controllers/shipit/tasks_controller.rb +2 -2
  21. data/app/controllers/shipit/webhooks_controller.rb +23 -4
  22. data/app/helpers/shipit/chunks_helper.rb +2 -2
  23. data/app/helpers/shipit/github_url_helper.rb +8 -0
  24. data/app/helpers/shipit/shipit_helper.rb +0 -1
  25. data/app/helpers/shipit/stacks_helper.rb +4 -0
  26. data/app/jobs/shipit/create_on_github_job.rb +1 -0
  27. data/app/jobs/shipit/deliver_hook_job.rb +1 -1
  28. data/app/jobs/shipit/destroy_repository_job.rb +24 -0
  29. data/app/jobs/shipit/destroy_stack_job.rb +2 -2
  30. data/app/jobs/shipit/github_sync_job.rb +13 -9
  31. data/app/jobs/shipit/perform_task_job.rb +4 -98
  32. data/app/jobs/shipit/process_merge_requests_job.rb +32 -0
  33. data/app/jobs/shipit/refresh_merge_request_job.rb +11 -0
  34. data/app/jobs/shipit/update_github_last_deployed_ref_job.rb +1 -1
  35. data/app/models/shipit/anonymous_user.rb +10 -2
  36. data/app/models/shipit/check_run.rb +38 -2
  37. data/app/models/shipit/command_line_user.rb +4 -0
  38. data/app/models/shipit/commit.rb +31 -20
  39. data/app/models/shipit/commit_checks.rb +14 -13
  40. data/app/models/shipit/commit_deployment.rb +3 -3
  41. data/app/models/shipit/commit_deployment_status.rb +3 -3
  42. data/app/models/shipit/deploy.rb +17 -11
  43. data/app/models/shipit/deploy_spec/file_system.rb +11 -5
  44. data/app/models/shipit/deploy_spec/lerna_discovery.rb +12 -4
  45. data/app/models/shipit/deploy_spec.rb +16 -4
  46. data/app/models/shipit/duration.rb +2 -0
  47. data/app/models/shipit/hook.rb +28 -2
  48. data/app/models/shipit/merge_request.rb +304 -0
  49. data/app/models/shipit/provisioning_handler/base.rb +30 -0
  50. data/app/models/shipit/provisioning_handler/unregistered_provisioning_handler.rb +35 -0
  51. data/app/models/shipit/provisioning_handler.rb +32 -0
  52. data/app/models/shipit/pull_request.rb +26 -265
  53. data/app/models/shipit/pull_request_assignment.rb +10 -0
  54. data/app/models/shipit/release_status.rb +1 -1
  55. data/app/models/shipit/repository.rb +63 -3
  56. data/app/models/shipit/review_stack.rb +130 -0
  57. data/app/models/shipit/review_stack_provisioning_queue.rb +39 -0
  58. data/app/models/shipit/rollback.rb +5 -0
  59. data/app/models/shipit/stack.rb +78 -30
  60. data/app/models/shipit/status/group.rb +1 -1
  61. data/app/models/shipit/task.rb +62 -9
  62. data/app/models/shipit/task_execution_strategy/base.rb +20 -0
  63. data/app/models/shipit/task_execution_strategy/default.rb +109 -0
  64. data/app/models/shipit/team.rb +4 -2
  65. data/app/models/shipit/user.rb +10 -1
  66. data/app/models/shipit/webhooks/handlers/pull_request/assigned_handler.rb +74 -0
  67. data/app/models/shipit/webhooks/handlers/pull_request/closed_handler.rb +68 -0
  68. data/app/models/shipit/webhooks/handlers/pull_request/edited_handler.rb +74 -0
  69. data/app/models/shipit/webhooks/handlers/pull_request/label_capturing_handler.rb +127 -0
  70. data/app/models/shipit/webhooks/handlers/pull_request/labeled_handler.rb +106 -0
  71. data/app/models/shipit/webhooks/handlers/pull_request/opened_handler.rb +83 -0
  72. data/app/models/shipit/webhooks/handlers/pull_request/reopened_handler.rb +88 -0
  73. data/app/models/shipit/webhooks/handlers/pull_request/review_stack_adapter.rb +103 -0
  74. data/app/models/shipit/webhooks/handlers/pull_request/unlabeled_handler.rb +107 -0
  75. data/app/models/shipit/webhooks/handlers/push_handler.rb +4 -1
  76. data/app/models/shipit/webhooks.rb +10 -0
  77. data/app/serializers/shipit/deploy_serializer.rb +6 -0
  78. data/app/serializers/shipit/merge_request_serializer.rb +21 -0
  79. data/app/serializers/shipit/pull_request_serializer.rb +5 -8
  80. data/app/serializers/shipit/review_stack_serializer.rb +7 -0
  81. data/app/serializers/shipit/stack_serializer.rb +7 -6
  82. data/app/serializers/shipit/tail_task_serializer.rb +10 -2
  83. data/app/serializers/shipit/task_serializer.rb +1 -1
  84. data/app/validators/subset_validator.rb +1 -1
  85. data/app/views/layouts/merge_status.html.erb +1 -1
  86. data/app/views/shipit/merge_requests/_merge_request.html.erb +29 -0
  87. data/app/views/shipit/{pull_requests → merge_requests}/index.html.erb +2 -2
  88. data/app/views/shipit/merge_requests/merge_requests/_pull_request.html.erb +29 -0
  89. data/app/views/shipit/merge_requests/merge_requests/index.html.erb +20 -0
  90. data/app/views/shipit/merge_status/_merge_queue_button.html.erb +3 -3
  91. data/app/views/shipit/merge_status/backlogged.html.erb +1 -1
  92. data/app/views/shipit/merge_status/failure.html.erb +1 -1
  93. data/app/views/shipit/merge_status/locked.html.erb +1 -1
  94. data/app/views/shipit/merge_status/success.html.erb +2 -2
  95. data/app/views/shipit/repositories/_header.html.erb +19 -0
  96. data/app/views/shipit/repositories/index.html.erb +31 -0
  97. data/app/views/shipit/repositories/new.html.erb +23 -0
  98. data/app/views/shipit/repositories/settings.html.erb +53 -0
  99. data/app/views/shipit/repositories/show.html.erb +30 -0
  100. data/app/views/shipit/stacks/_banners.html.erb +15 -1
  101. data/app/views/shipit/stacks/_header.html.erb +5 -2
  102. data/app/views/shipit/stacks/_stack.html.erb +8 -0
  103. data/app/views/shipit/stacks/index.html.erb +2 -1
  104. data/app/views/shipit/stacks/new.html.erb +1 -1
  105. data/app/views/shipit/stacks/settings.html.erb +5 -5
  106. data/app/views/shipit/stacks/show.html.erb +1 -1
  107. data/app/views/shipit/tasks/_task_output.html.erb +1 -1
  108. data/config/routes.rb +15 -5
  109. data/config/secrets.development.example.yml +24 -0
  110. data/config/secrets.development.shopify.yml +20 -9
  111. data/db/migrate/20200706145406_add_review_stacks.rb +12 -0
  112. data/db/migrate/20200804144639_rename_pull_request_to_merge_request.rb +7 -0
  113. data/db/migrate/20200804161512_rename_commits_pull_request_id_to_merge_request_id.rb +5 -0
  114. data/db/migrate/20200813134712_recreate_shipit_pull_requests.rb +22 -0
  115. data/db/migrate/20200813194056_create_pull_request_assignments.rb +8 -0
  116. data/db/migrate/20201001125502_add_provision_pr_stacks_flag_to_repositories.rb +7 -0
  117. data/db/migrate/20201008145809_add_retry_attempt_to_tasks.rb +5 -0
  118. data/db/migrate/20201008152744_add_max_retries_to_tasks.rb +5 -0
  119. data/db/migrate/20210325194053_remove_stacks_branch_default.rb +5 -0
  120. data/db/migrate/20210504200438_add_github_updated_at_to_check_runs.rb +5 -0
  121. data/db/migrate/20210823075617_change_check_runs_github_updated_at_default.rb +5 -0
  122. data/lib/shipit/command.rb +7 -6
  123. data/lib/shipit/commands.rb +18 -5
  124. data/lib/shipit/engine.rb +2 -0
  125. data/lib/shipit/flock.rb +8 -1
  126. data/lib/shipit/github_app.rb +8 -6
  127. data/lib/shipit/octokit_iterator.rb +3 -3
  128. data/lib/shipit/review_stack_commands.rb +8 -0
  129. data/lib/shipit/simple_message_verifier.rb +2 -2
  130. data/lib/shipit/stack_commands.rb +36 -7
  131. data/lib/shipit/task_commands.rb +8 -1
  132. data/lib/shipit/version.rb +1 -1
  133. data/lib/shipit.rb +50 -16
  134. data/lib/snippets/publish-lerna-independent-packages +35 -34
  135. data/lib/snippets/publish-lerna-independent-packages-legacy +39 -0
  136. data/lib/tasks/cron.rake +11 -2
  137. data/test/controllers/api/ccmenu_controller_test.rb +1 -1
  138. data/test/controllers/api/deploys_controller_test.rb +17 -0
  139. data/test/controllers/api/{pull_requests_controller_test.rb → merge_requests_controller_test.rb} +12 -12
  140. data/test/controllers/api/outputs_controller_test.rb +1 -0
  141. data/test/controllers/api/rollback_controller_test.rb +1 -1
  142. data/test/controllers/api/stacks_controller_test.rb +42 -8
  143. data/test/controllers/{pull_requests_controller_test.rb → merge_requests_controller_test.rb} +6 -6
  144. data/test/controllers/repositories_controller_test.rb +71 -0
  145. data/test/controllers/stacks_controller_test.rb +9 -1
  146. data/test/controllers/tasks_controller_test.rb +14 -2
  147. data/test/controllers/webhooks_controller_test.rb +27 -12
  148. data/test/dummy/app/assets/config/manifest.js +3 -0
  149. data/test/dummy/config/application.rb +7 -2
  150. data/test/dummy/config/database.yml +9 -0
  151. data/test/dummy/config/environments/development.rb +1 -4
  152. data/test/dummy/config/environments/test.rb +0 -5
  153. data/test/dummy/config/secrets_double_github_app.yml +79 -0
  154. data/test/dummy/db/schema.rb +56 -17
  155. data/test/dummy/db/seeds.rb +2 -1
  156. data/test/fixtures/payloads/check_suite_master.json +4 -32
  157. data/test/fixtures/payloads/invalid_pull_request.json +117 -0
  158. data/test/fixtures/payloads/provision_disabled_pull_request.json +454 -0
  159. data/test/fixtures/payloads/pull_request_assigned.json +480 -0
  160. data/test/fixtures/payloads/pull_request_closed.json +454 -0
  161. data/test/fixtures/payloads/pull_request_labeled.json +461 -0
  162. data/test/fixtures/payloads/pull_request_opened.json +454 -0
  163. data/test/fixtures/payloads/pull_request_reopened.json +454 -0
  164. data/test/fixtures/payloads/pull_request_unlabeled.json +454 -0
  165. data/test/fixtures/payloads/pull_request_with_no_repo.json +454 -0
  166. data/test/fixtures/payloads/push_master.json +1 -1
  167. data/test/fixtures/payloads/push_not_master.json +1 -1
  168. data/test/fixtures/shipit/commits.yml +17 -4
  169. data/test/fixtures/shipit/hooks.yml +1 -0
  170. data/test/fixtures/shipit/merge_requests.yml +141 -0
  171. data/test/fixtures/shipit/pull_request_assignments.yml +3 -0
  172. data/test/fixtures/shipit/pull_requests.yml +10 -131
  173. data/test/fixtures/shipit/repositories.yml +1 -0
  174. data/test/fixtures/shipit/stacks.yml +145 -0
  175. data/test/fixtures/shipit/statuses.yml +9 -0
  176. data/test/fixtures/shipit/tasks.yml +4 -1
  177. data/test/fixtures/shipit/users.yml +7 -0
  178. data/test/helpers/json_helper.rb +5 -1
  179. data/test/helpers/payloads_helper.rb +4 -0
  180. data/test/jobs/chunk_rollup_job_test.rb +15 -1
  181. data/test/jobs/destroy_repository_job_test.rb +27 -0
  182. data/test/jobs/github_sync_job_test.rb +2 -1
  183. data/test/jobs/perform_task_job_test.rb +8 -8
  184. data/test/jobs/{merge_pull_requests_job_test.rb → process_merge_requests_job_test.rb} +18 -18
  185. data/test/lib/shipit/deploy_commands_test.rb +16 -0
  186. data/test/lib/shipit/task_commands_test.rb +17 -0
  187. data/test/models/commit_deployment_status_test.rb +3 -3
  188. data/test/models/commits_test.rb +24 -13
  189. data/test/models/deploy_spec_test.rb +64 -24
  190. data/test/models/deploys_test.rb +188 -14
  191. data/test/models/hook_test.rb +30 -1
  192. data/test/models/{pull_request_test.rb → merge_request_test.rb} +49 -34
  193. data/test/models/pull_request_assignment_test.rb +16 -0
  194. data/test/models/shipit/check_run_test.rb +124 -5
  195. data/test/models/shipit/provisioning_handler/base_test.rb +33 -0
  196. data/test/models/shipit/provisioning_handler/unregistered_provisioning_handler_test.rb +49 -0
  197. data/test/models/shipit/provisioning_handler_test.rb +64 -0
  198. data/test/models/shipit/pull_request_test.rb +52 -0
  199. data/test/models/shipit/repository_test.rb +5 -1
  200. data/test/models/shipit/review_stack_provision_status_test.rb +77 -0
  201. data/test/models/shipit/review_stack_provisioning_queue_test.rb +63 -0
  202. data/test/models/shipit/review_stack_test.rb +91 -0
  203. data/test/models/{stacks_test.rb → shipit/stacks_test.rb} +52 -8
  204. data/test/models/shipit/webhooks/handlers/pull_request/assigned_handler_test.rb +45 -0
  205. data/test/models/shipit/webhooks/handlers/pull_request/closed_handler_test.rb +192 -0
  206. data/test/models/shipit/webhooks/handlers/pull_request/edited_handler_test.rb +47 -0
  207. data/test/models/shipit/webhooks/handlers/pull_request/label_capturing_handler_test.rb +209 -0
  208. data/test/models/shipit/webhooks/handlers/pull_request/labeled_handler_test.rb +332 -0
  209. data/test/models/shipit/webhooks/handlers/pull_request/opened_handler_test.rb +238 -0
  210. data/test/models/shipit/webhooks/handlers/pull_request/reopened_handler_test.rb +282 -0
  211. data/test/models/shipit/webhooks/handlers/pull_request/review_stack_adapter_test.rb +107 -0
  212. data/test/models/shipit/webhooks/handlers/pull_request/unlabeled_handler_test.rb +324 -0
  213. data/test/models/shipit/{wehbooks → webhooks}/handlers_test.rb +0 -0
  214. data/test/models/tasks_test.rb +66 -3
  215. data/test/serializers/shipit/pull_request_serializer_test.rb +29 -0
  216. data/test/test_helper.rb +15 -0
  217. data/test/unit/anonymous_user_serializer_test.rb +1 -1
  218. data/test/unit/command_test.rb +8 -3
  219. data/test/unit/commit_serializer_test.rb +1 -1
  220. data/test/unit/deploy_commands_test.rb +73 -17
  221. data/test/unit/deploy_serializer_test.rb +1 -1
  222. data/test/unit/github_app_test.rb +2 -3
  223. data/test/unit/github_apps_test.rb +416 -0
  224. data/test/unit/github_url_helper_test.rb +5 -0
  225. data/test/unit/shipit_deployment_checks_test.rb +77 -0
  226. data/test/unit/shipit_task_execution_strategy_test.rb +47 -0
  227. data/test/unit/shipit_test.rb +14 -0
  228. data/test/unit/user_serializer_test.rb +1 -1
  229. metadata +306 -188
  230. data/app/controllers/shipit/pull_requests_controller.rb +0 -31
  231. data/app/jobs/shipit/merge_pull_requests_job.rb +0 -32
  232. data/app/jobs/shipit/refresh_pull_request_job.rb +0 -11
  233. data/app/views/shipit/pull_requests/_pull_request.html.erb +0 -29
  234. data/test/fixtures/shipit/output_chunks.yml +0 -47
  235. data/test/models/output_chunk_test.rb +0 -21
@@ -1,5 +1,35 @@
1
1
  # frozen_string_literal: true
2
2
  module Shipit
3
+ class NullRepository
4
+ def id
5
+ nil
6
+ end
7
+
8
+ def stacks
9
+ Shipit::Stack.none
10
+ end
11
+
12
+ def review_stacks
13
+ Shipit::ReviewStack.none
14
+ end
15
+
16
+ def review_stacks_enabled
17
+ false
18
+ end
19
+
20
+ def provisioning_behavior_allow_all?
21
+ false
22
+ end
23
+
24
+ def provisioning_behavior_allow_with_label?
25
+ false
26
+ end
27
+
28
+ def provisioning_behavior_prevent_with_label?
29
+ false
30
+ end
31
+ end
32
+
3
33
  class Repository < ApplicationRecord
4
34
  OWNER_MAX_SIZE = 39
5
35
  private_constant :OWNER_MAX_SIZE
@@ -8,12 +38,16 @@ module Shipit
8
38
  private_constant :NAME_MAX_SIZE
9
39
 
10
40
  validates :name, uniqueness: { scope: %i(owner), case_sensitive: false,
11
- message: 'cannot be used more than once' }
41
+ message: 'cannot be used more than once', }
12
42
  validates :owner, :name, presence: true, ascii_only: true
13
43
  validates :owner, format: { with: /\A[a-z0-9_\-\.]+\z/ }, length: { maximum: OWNER_MAX_SIZE }
14
44
  validates :name, format: { with: /\A[a-z0-9_\-\.]+\z/ }, length: { maximum: NAME_MAX_SIZE }
15
45
 
16
46
  has_many :stacks, dependent: :destroy
47
+ has_many :review_stacks, dependent: :destroy
48
+
49
+ PROVISIONING_BEHAVIORS = %w(allow_all allow_with_label prevent_with_label).freeze
50
+ enum provisioning_behavior: PROVISIONING_BEHAVIORS.zip(PROVISIONING_BEHAVIORS).to_h, _prefix: :provisioning_behavior
17
51
 
18
52
  def self.from_github_repo_name(github_repo_name)
19
53
  repo_owner, repo_name = github_repo_name.downcase.split('/')
@@ -28,8 +62,12 @@ module Shipit
28
62
  super(o&.downcase)
29
63
  end
30
64
 
65
+ def github_repo_name
66
+ [owner, name].join('/')
67
+ end
68
+
31
69
  def http_url
32
- Shipit.github.url(full_name)
70
+ github_app.url(full_name)
33
71
  end
34
72
 
35
73
  def full_name
@@ -37,7 +75,29 @@ module Shipit
37
75
  end
38
76
 
39
77
  def git_url
40
- "https://#{Shipit.github.domain}/#{owner}/#{name}.git"
78
+ "https://#{github_app.domain}/#{owner}/#{name}.git"
79
+ end
80
+
81
+ def schedule_for_destroy!
82
+ DestroyRepositoryJob.perform_later(self)
83
+ end
84
+
85
+ def to_param
86
+ github_repo_name
87
+ end
88
+
89
+ def self.from_param!(param)
90
+ repo_owner, repo_name = param.split('/')
91
+ where(
92
+ owner: repo_owner.downcase,
93
+ name: repo_name.downcase,
94
+ ).first!
95
+ end
96
+
97
+ protected
98
+
99
+ def github_app
100
+ Shipit.github(organization: owner)
41
101
  end
42
102
  end
43
103
  end
@@ -0,0 +1,130 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shipit
4
+ class ReviewStack < Shipit::Stack
5
+ def self.clear_stale_caches
6
+ Shipit::ReviewStack.where(
7
+ "archived_since > :earliest AND archived_since < :latest",
8
+ earliest: 1.day.ago,
9
+ latest: 1.hour.ago
10
+ ).find_each do |review_stack|
11
+ review_stack.clear_local_files
12
+ end
13
+ end
14
+
15
+ def self.delete_old_deployment_directories
16
+ Shipit::Deploy.not_active.where(
17
+ "created_at > :earliest AND updated_at < :latest",
18
+ earliest: 1.day.ago,
19
+ latest: 1.hour.ago
20
+ ).find_each do |deploy|
21
+ Shipit::Commands.for(deploy).clear_working_directory
22
+ end
23
+ end
24
+
25
+ def update_latest_deployed_ref
26
+ # noop: last deployed ref is useless for review stacks
27
+ end
28
+
29
+ model_name.class_eval do
30
+ def route_key
31
+ "stacks"
32
+ end
33
+
34
+ def singular_route_key
35
+ "stack"
36
+ end
37
+ end
38
+
39
+ has_one :pull_request, foreign_key: :stack_id
40
+
41
+ after_commit :emit_added_hooks, on: :create
42
+ after_commit :emit_updated_hooks, on: :update
43
+ after_commit :emit_removed_hooks, on: :destroy
44
+
45
+ state_machine :provision_status, initial: :deprovisioned do
46
+ state :provisioned
47
+ state :provisioning
48
+ state :deprovisioning
49
+ state :deprovisioned
50
+
51
+ event :provision do
52
+ transition deprovisioned: :provisioning
53
+ end
54
+
55
+ event :provision_success do
56
+ transition provisioning: :provisioned
57
+ end
58
+
59
+ event :provision_failure do
60
+ transition provisioning: :deprovisioned
61
+ end
62
+
63
+ event :deprovision do
64
+ transition provisioned: :deprovisioning
65
+ end
66
+
67
+ event :deprovision_success do
68
+ transition deprovisioning: :deprovisioned
69
+ end
70
+
71
+ event :deprovision_failure do
72
+ transition deprovisioning: :provisioned
73
+ end
74
+
75
+ after_transition deprovisioned: :provisioning do |stack, _|
76
+ stack.provisioner.up
77
+ end
78
+
79
+ after_transition provisioned: :deprovisioning do |stack, _|
80
+ stack.provisioner.down
81
+ end
82
+ end
83
+
84
+ def env
85
+ return super unless pull_request.present?
86
+
87
+ super
88
+ .merge(
89
+ pull_request
90
+ .labels
91
+ .each_with_object({}) { |label_name, labels| labels[label_name.upcase] = "true" }
92
+ )
93
+ end
94
+
95
+ def provisioner
96
+ provisioner_class.new(self)
97
+ end
98
+
99
+ def provisioner_class
100
+ ProvisioningHandler.fetch(provisioning_handler_name)
101
+ end
102
+
103
+ def enqueue_for_provisioning
104
+ return if awaiting_provision
105
+ update!(awaiting_provision: true)
106
+ end
107
+
108
+ def remove_from_provisioning_queue
109
+ return unless awaiting_provision
110
+ update!(awaiting_provision: false)
111
+ end
112
+
113
+ def to_partial_path
114
+ "shipit/stacks/stack"
115
+ end
116
+
117
+ def emit_added_hooks
118
+ Hook.emit(:review_stack, self, action: :added, review_stack: self)
119
+ end
120
+
121
+ def emit_updated_hooks
122
+ changed = !(previous_changes.keys - %w(updated_at)).empty?
123
+ Hook.emit(:review_stack, self, action: :updated, review_stack: self) if changed
124
+ end
125
+
126
+ def emit_removed_hooks
127
+ Hook.emit(:review_stack, self, action: :removed, review_stack: self)
128
+ end
129
+ end
130
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shipit
4
+ class ReviewStackProvisioningQueue
5
+ def self.work
6
+ new.work
7
+ end
8
+
9
+ def self.add(stack)
10
+ stack.enqueue_for_provisioning
11
+ end
12
+
13
+ def self.queued_stacks
14
+ new.queued_stacks
15
+ end
16
+
17
+ def work
18
+ queued_stacks.find_each(&method(:provision))
19
+ end
20
+
21
+ def queued_stacks
22
+ @queued_stacks ||= Shipit::ReviewStack
23
+ .with_provision_status(:deprovisioned)
24
+ .where(awaiting_provision: true)
25
+ end
26
+
27
+ private
28
+
29
+ def provision(stack)
30
+ if stack.provisioner.provision?
31
+ stack.provision
32
+ else
33
+ Rails.logger.info(
34
+ "Putting review ReviewStack<#{stack.id}> back into the provisioning queue - #provision? was falsey."
35
+ )
36
+ end
37
+ end
38
+ end
39
+ end
@@ -33,6 +33,10 @@ module Shipit
33
33
  'deploys/deploy'
34
34
  end
35
35
 
36
+ def report_complete!
37
+ complete!
38
+ end
39
+
36
40
  private
37
41
 
38
42
  def update_release_status
@@ -40,6 +44,7 @@ module Shipit
40
44
 
41
45
  # When we rollback to a certain revision, assume that all later deploys were faulty
42
46
  stack.deploys.newer_than(deploy.id).until(stack.last_completed_deploy.id).to_a.each do |deploy|
47
+ next if deploy.id == id
43
48
  deploy.report_faulty!(description: "A rollback of #{stack.to_param} was triggered")
44
49
  end
45
50
  end
@@ -27,14 +27,14 @@ module Shipit
27
27
  REQUIRED_HOOKS = %i(push status).freeze
28
28
 
29
29
  has_many :commits, dependent: :destroy
30
- has_many :pull_requests, dependent: :destroy
30
+ has_many :merge_requests, dependent: :destroy
31
31
  has_many :tasks, dependent: :destroy
32
32
  has_many :deploys
33
33
  has_many :rollbacks
34
34
  has_many :deploys_and_rollbacks,
35
- -> { where(type: %w(Shipit::Deploy Shipit::Rollback)) },
36
- class_name: 'Task',
37
- inverse_of: :stack
35
+ -> { where(type: %w(Shipit::Deploy Shipit::Rollback)) },
36
+ class_name: 'Task',
37
+ inverse_of: :stack
38
38
  has_many :github_hooks, dependent: :destroy, class_name: 'Shipit::GithubHook::Repo'
39
39
  has_many :hooks, dependent: :destroy
40
40
  has_many :api_clients, dependent: :destroy
@@ -44,6 +44,9 @@ module Shipit
44
44
 
45
45
  scope :not_archived, -> { where(archived_since: nil) }
46
46
 
47
+ include DeferredTouch
48
+ deferred_touch repository: :updated_at
49
+
47
50
  default_scope { preload(:repository) }
48
51
 
49
52
  def env
@@ -80,19 +83,36 @@ module Shipit
80
83
  after_commit :emit_merge_status_hooks, on: :update
81
84
  after_commit :sync_github, on: :create
82
85
  after_commit :schedule_merges_if_necessary, on: :update
86
+ after_commit :sync_github_if_necessary, on: :update
87
+
88
+ def sync_github_if_necessary
89
+ if (archived_since_previously_changed? && archived_since.nil?) || branch_previously_changed?
90
+ sync_github
91
+ end
92
+ end
83
93
 
84
94
  validates :repository, uniqueness: {
85
95
  scope: %i(environment), case_sensitive: false,
86
- message: 'cannot be used more than once with this environment. Check archived stacks.'
96
+ message: 'cannot be used more than once with this environment. Check archived stacks.',
87
97
  }
88
98
  validates :environment, format: { with: /\A[a-z0-9\-_\:]+\z/ }, length: { maximum: ENVIRONMENT_MAX_SIZE }
89
99
  validates :deploy_url, format: { with: URI.regexp(%w(http https ssh)) }, allow_blank: true
100
+ validates :branch, presence: true
90
101
 
91
102
  validates :lock_reason, length: { maximum: 4096 }
92
103
 
93
104
  serialize :cached_deploy_spec, DeploySpec
94
- delegate :find_task_definition, :supports_rollback?, :release_status?, :release_status_delay,
95
- :release_status_context, :supports_fetch_deployed_revision?, to: :cached_deploy_spec, allow_nil: true
105
+ delegate(
106
+ :provisioning_handler_name,
107
+ :find_task_definition,
108
+ :release_status?,
109
+ :release_status_context,
110
+ :release_status_delay,
111
+ :supports_fetch_deployed_revision?,
112
+ :supports_rollback?,
113
+ to: :cached_deploy_spec,
114
+ allow_nil: true
115
+ )
96
116
 
97
117
  def self.refresh_deployed_revisions
98
118
  find_each.select(&:supports_fetch_deployed_revision?).each(&:async_refresh_deployed_revision)
@@ -139,6 +159,7 @@ module Shipit
139
159
  env: filter_deploy_envs(env&.to_h || {}),
140
160
  allow_concurrency: force,
141
161
  ignored_safeties: force || !until_commit.deployable?,
162
+ max_retries: retries_on_deploy,
142
163
  )
143
164
  end
144
165
 
@@ -171,7 +192,7 @@ module Shipit
171
192
  end
172
193
 
173
194
  def continuous_delivery_delayed?
174
- continuous_delivery_delayed_since? && continuous_deployment? && checks?
195
+ continuous_delivery_delayed_since? && continuous_deployment? && (checks? || deployment_checks?)
175
196
  end
176
197
 
177
198
  def continuous_delivery_delayed!
@@ -200,7 +221,7 @@ module Shipit
200
221
  end
201
222
 
202
223
  def schedule_merges
203
- MergePullRequestsJob.perform_later(self)
224
+ ProcessMergeRequestsJob.perform_later(self)
204
225
  end
205
226
 
206
227
  def next_commit_to_deploy
@@ -340,7 +361,7 @@ module Shipit
340
361
  end
341
362
 
342
363
  def deployable?
343
- !locked? && !active_task?
364
+ !locked? && !active_task? && !awaiting_provision? && deployment_checks_passed?
344
365
  end
345
366
 
346
367
  def allows_merges?
@@ -348,7 +369,7 @@ module Shipit
348
369
  end
349
370
 
350
371
  def merge_method
351
- cached_deploy_spec&.pull_request_merge_method || Shipit.default_merge_method
372
+ cached_deploy_spec&.merge_request_merge_method || Shipit.default_merge_method
352
373
  end
353
374
 
354
375
  delegate :name=, to: :repository, prefix: :repo
@@ -359,42 +380,51 @@ module Shipit
359
380
  delegate :git_url, to: :repository, prefix: :repo
360
381
 
361
382
  def base_path
362
- Rails.root.join('data', 'stacks', repo_owner, repo_name, environment)
383
+ @base_path ||= Rails.root.join('data', 'stacks', repo_owner, repo_name, environment)
363
384
  end
364
385
 
365
386
  def deploys_path
366
- File.join(base_path, "deploys")
387
+ @deploys_path ||= base_path.join("deploys")
367
388
  end
368
389
 
369
390
  def git_path
370
- File.join(base_path, "git")
391
+ @git_path ||= base_path.join("git")
371
392
  end
372
393
 
373
394
  def acquire_git_cache_lock(timeout: 15, &block)
374
- Flock.new(git_path.to_s + '.lock').lock(timeout: timeout, &block)
395
+ @git_cache_lock ||= Flock.new(git_path.to_s + '.lock')
396
+ @git_cache_lock.lock(timeout: timeout, &block)
375
397
  end
376
398
 
377
399
  def clear_git_cache!
378
400
  tmp_path = "#{git_path}-#{SecureRandom.hex}"
379
- return unless File.exist?(git_path)
401
+ return unless git_path.exist?
380
402
  acquire_git_cache_lock do
381
- File.rename(git_path, tmp_path)
403
+ git_path.rename(tmp_path)
382
404
  end
383
405
  FileUtils.rm_rf(tmp_path)
384
406
  end
385
407
 
386
408
  def github_repo_name
387
- [repo_owner, repo_name].join('/')
409
+ repository.github_repo_name
388
410
  end
389
411
 
390
412
  def github_commits
391
413
  handle_github_redirections do
392
- Shipit.github.api.commits(github_repo_name, sha: branch)
414
+ github_api.commits(github_repo_name, sha: branch)
393
415
  end
394
416
  rescue Octokit::Conflict
395
417
  [] # Repository is empty...
396
418
  end
397
419
 
420
+ def github_api
421
+ github_app.api
422
+ end
423
+
424
+ def github_app
425
+ Shipit.github(organization: repository.owner)
426
+ end
427
+
398
428
  def handle_github_redirections
399
429
  # https://developer.github.com/v3/#http-redirects
400
430
  resource = yield
@@ -407,9 +437,9 @@ module Shipit
407
437
  end
408
438
 
409
439
  def refresh_repository!
410
- resource = Shipit.github.api.repo(github_repo_name)
440
+ resource = github_api.repo(github_repo_name)
411
441
  if resource.try(:message) == 'Moved Permanently'
412
- resource = Shipit.github.api.get(resource.url)
442
+ resource = github_api.get(resource.url)
413
443
  end
414
444
  repository.update!(owner: resource.owner.login, name: resource.name)
415
445
  end
@@ -474,8 +504,9 @@ module Shipit
474
504
  end
475
505
 
476
506
  delegate :plugins, :task_definitions, :hidden_statuses, :required_statuses, :soft_failing_statuses,
477
- :blocking_statuses, :deploy_variables, :filter_task_envs, :filter_deploy_envs,
478
- :maximum_commits_per_deploy, :pause_between_deploys, to: :cached_deploy_spec
507
+ :blocking_statuses, :deploy_variables, :filter_task_envs, :filter_deploy_envs,
508
+ :maximum_commits_per_deploy, :pause_between_deploys, :retries_on_deploy, :retries_on_rollback,
509
+ to: :cached_deploy_spec
479
510
 
480
511
  def monitoring?
481
512
  monitoring.present?
@@ -567,19 +598,31 @@ module Shipit
567
598
  links_spec.transform_values { |url| context.interpolate(url) }
568
599
  end
569
600
 
601
+ def clear_local_files
602
+ FileUtils.rm_rf(base_path.to_s)
603
+ end
604
+
605
+ def deployment_checks_passed?
606
+ return true unless deployment_checks?
607
+
608
+ Shipit.deployment_checks.call(self)
609
+ end
610
+
570
611
  private
571
612
 
572
613
  def clear_cache
573
614
  remove_instance_variable(:@active_task) if defined?(@active_task)
574
615
  end
575
616
 
576
- def clear_local_files
577
- FileUtils.rm_rf(base_path.to_s)
578
- end
579
-
580
617
  def update_defaults
581
618
  self.environment = 'production' if environment.blank?
582
- self.branch = 'master' if branch.blank?
619
+ self.branch = default_branch_name if branch.blank?
620
+ end
621
+
622
+ def default_branch_name
623
+ Shipit.github.api.repo(github_repo_name).default_branch
624
+ rescue Octokit::NotFound, Octokit::InvalidRepository
625
+ nil
583
626
  end
584
627
 
585
628
  def set_locked_since
@@ -593,7 +636,7 @@ module Shipit
593
636
  end
594
637
 
595
638
  def schedule_merges_if_necessary
596
- if previous_changes.include?('lock_reason') && previous_changes['lock_reason'].last.blank?
639
+ if lock_reason_previously_changed? && lock_reason.blank?
597
640
  schedule_merges
598
641
  end
599
642
  end
@@ -630,7 +673,7 @@ module Shipit
630
673
  end
631
674
 
632
675
  def should_resume_continuous_delivery?(commit)
633
- !deployable? ||
676
+ (deployment_checks_passed? && !deployable?) ||
634
677
  deployed_too_recently? ||
635
678
  commit.nil? ||
636
679
  commit.deployed?
@@ -639,7 +682,12 @@ module Shipit
639
682
  def should_delay_continuous_delivery?(commit)
640
683
  commit.deploy_failed? ||
641
684
  (checks? && !EphemeralCommitChecks.new(commit).run.success?) ||
685
+ !deployment_checks_passed? ||
642
686
  commit.recently_pushed?
643
687
  end
688
+
689
+ def deployment_checks?
690
+ Shipit.deployment_checks.present?
691
+ end
644
692
  end
645
693
  end