shipit-engine 0.32.0 → 0.33.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 (176) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/images/magic-solid.svg +1 -0
  3. data/app/assets/javascripts/shipit/repositories_search.js.coffee +60 -0
  4. data/app/assets/javascripts/shipit/{search.js.coffee → stack_search.js.coffee} +0 -0
  5. data/app/assets/stylesheets/_pages/_repositories.scss +148 -0
  6. data/app/assets/stylesheets/_pages/_stacks.scss +19 -0
  7. data/app/assets/stylesheets/shipit.scss +1 -0
  8. data/app/controllers/shipit/api/{pull_requests_controller.rb → merge_requests_controller.rb} +8 -8
  9. data/app/controllers/shipit/api/stacks_controller.rb +14 -1
  10. data/app/controllers/shipit/deploys_controller.rb +2 -2
  11. data/app/controllers/shipit/merge_requests_controller.rb +31 -0
  12. data/app/controllers/shipit/merge_status_controller.rb +15 -15
  13. data/app/controllers/shipit/repositories_controller.rb +74 -0
  14. data/app/controllers/shipit/tasks_controller.rb +4 -4
  15. data/app/helpers/shipit/chunks_helper.rb +2 -2
  16. data/app/helpers/shipit/github_url_helper.rb +8 -0
  17. data/app/helpers/shipit/stacks_helper.rb +4 -0
  18. data/app/jobs/shipit/create_on_github_job.rb +1 -0
  19. data/app/jobs/shipit/destroy_repository_job.rb +24 -0
  20. data/app/jobs/shipit/destroy_stack_job.rb +2 -2
  21. data/app/jobs/shipit/perform_task_job.rb +4 -98
  22. data/app/jobs/shipit/process_merge_requests_job.rb +32 -0
  23. data/app/jobs/shipit/refresh_merge_request_job.rb +11 -0
  24. data/app/models/shipit/anonymous_user.rb +4 -0
  25. data/app/models/shipit/check_run.rb +2 -2
  26. data/app/models/shipit/command_line_user.rb +4 -0
  27. data/app/models/shipit/commit.rb +11 -11
  28. data/app/models/shipit/commit_checks.rb +1 -0
  29. data/app/models/shipit/deploy.rb +1 -0
  30. data/app/models/shipit/deploy_spec.rb +16 -4
  31. data/app/models/shipit/deploy_spec/file_system.rb +11 -5
  32. data/app/models/shipit/hook.rb +2 -0
  33. data/app/models/shipit/merge_request.rb +302 -0
  34. data/app/models/shipit/provisioning_handler.rb +32 -0
  35. data/app/models/shipit/provisioning_handler/base.rb +30 -0
  36. data/app/models/shipit/provisioning_handler/unregistered_provisioning_handler.rb +35 -0
  37. data/app/models/shipit/pull_request.rb +25 -264
  38. data/app/models/shipit/pull_request_assignment.rb +10 -0
  39. data/app/models/shipit/repository.rb +54 -0
  40. data/app/models/shipit/review_stack.rb +116 -0
  41. data/app/models/shipit/review_stack_provisioning_queue.rb +39 -0
  42. data/app/models/shipit/stack.rb +22 -8
  43. data/app/models/shipit/task.rb +56 -7
  44. data/app/models/shipit/task_execution_strategy/base.rb +20 -0
  45. data/app/models/shipit/task_execution_strategy/default.rb +110 -0
  46. data/app/models/shipit/user.rb +6 -1
  47. data/app/models/shipit/webhooks.rb +10 -0
  48. data/app/models/shipit/webhooks/handlers/pull_request/assigned_handler.rb +74 -0
  49. data/app/models/shipit/webhooks/handlers/pull_request/closed_handler.rb +68 -0
  50. data/app/models/shipit/webhooks/handlers/pull_request/edited_handler.rb +74 -0
  51. data/app/models/shipit/webhooks/handlers/pull_request/label_capturing_handler.rb +127 -0
  52. data/app/models/shipit/webhooks/handlers/pull_request/labeled_handler.rb +106 -0
  53. data/app/models/shipit/webhooks/handlers/pull_request/opened_handler.rb +83 -0
  54. data/app/models/shipit/webhooks/handlers/pull_request/reopened_handler.rb +88 -0
  55. data/app/models/shipit/webhooks/handlers/pull_request/review_stack_adapter.rb +103 -0
  56. data/app/models/shipit/webhooks/handlers/pull_request/unlabeled_handler.rb +107 -0
  57. data/app/serializers/shipit/deploy_serializer.rb +6 -0
  58. data/app/serializers/shipit/merge_request_serializer.rb +21 -0
  59. data/app/serializers/shipit/pull_request_serializer.rb +5 -8
  60. data/app/serializers/shipit/review_stack_serializer.rb +7 -0
  61. data/app/serializers/shipit/stack_serializer.rb +7 -6
  62. data/app/serializers/shipit/tail_task_serializer.rb +10 -2
  63. data/app/serializers/shipit/task_serializer.rb +1 -1
  64. data/app/views/shipit/merge_requests/_merge_request.html.erb +29 -0
  65. data/app/views/shipit/{pull_requests → merge_requests}/index.html.erb +2 -2
  66. data/app/views/shipit/merge_requests/merge_requests/_pull_request.html.erb +29 -0
  67. data/app/views/shipit/merge_requests/merge_requests/index.html.erb +20 -0
  68. data/app/views/shipit/merge_status/_merge_queue_button.html.erb +3 -3
  69. data/app/views/shipit/merge_status/backlogged.html.erb +1 -1
  70. data/app/views/shipit/merge_status/failure.html.erb +1 -1
  71. data/app/views/shipit/merge_status/locked.html.erb +1 -1
  72. data/app/views/shipit/merge_status/success.html.erb +2 -2
  73. data/app/views/shipit/repositories/_header.html.erb +19 -0
  74. data/app/views/shipit/repositories/index.html.erb +31 -0
  75. data/app/views/shipit/repositories/new.html.erb +23 -0
  76. data/app/views/shipit/repositories/settings.html.erb +53 -0
  77. data/app/views/shipit/repositories/show.html.erb +30 -0
  78. data/app/views/shipit/stacks/_banners.html.erb +13 -0
  79. data/app/views/shipit/stacks/_header.html.erb +5 -2
  80. data/app/views/shipit/stacks/_stack.html.erb +8 -0
  81. data/app/views/shipit/stacks/index.html.erb +2 -1
  82. data/app/views/shipit/stacks/settings.html.erb +5 -5
  83. data/app/views/shipit/stacks/show.html.erb +1 -1
  84. data/app/views/shipit/tasks/_task_output.html.erb +1 -1
  85. data/config/routes.rb +15 -5
  86. data/db/migrate/20200706145406_add_review_stacks.rb +12 -0
  87. data/db/migrate/20200804144639_rename_pull_request_to_merge_request.rb +7 -0
  88. data/db/migrate/20200804161512_rename_commits_pull_request_id_to_merge_request_id.rb +5 -0
  89. data/db/migrate/20200813134712_recreate_shipit_pull_requests.rb +22 -0
  90. data/db/migrate/20200813194056_create_pull_request_assignments.rb +8 -0
  91. data/db/migrate/20201001125502_add_provision_pr_stacks_flag_to_repositories.rb +7 -0
  92. data/db/migrate/20201008145809_add_retry_attempt_to_tasks.rb +5 -0
  93. data/db/migrate/20201008152744_add_max_retries_to_tasks.rb +5 -0
  94. data/lib/shipit.rb +11 -1
  95. data/lib/shipit/github_app.rb +1 -1
  96. data/lib/shipit/review_stack_commands.rb +8 -0
  97. data/lib/shipit/stack_commands.rb +6 -1
  98. data/lib/shipit/task_commands.rb +1 -0
  99. data/lib/shipit/version.rb +1 -1
  100. data/lib/tasks/cron.rake +11 -2
  101. data/test/controllers/api/{pull_requests_controller_test.rb → merge_requests_controller_test.rb} +12 -12
  102. data/test/controllers/api/outputs_controller_test.rb +1 -0
  103. data/test/controllers/api/rollback_controller_test.rb +1 -1
  104. data/test/controllers/api/stacks_controller_test.rb +21 -1
  105. data/test/controllers/{pull_requests_controller_test.rb → merge_requests_controller_test.rb} +6 -6
  106. data/test/controllers/repositories_controller_test.rb +71 -0
  107. data/test/controllers/stacks_controller_test.rb +9 -1
  108. data/test/controllers/tasks_controller_test.rb +14 -2
  109. data/test/controllers/webhooks_controller_test.rb +1 -1
  110. data/test/dummy/config/application.rb +6 -1
  111. data/test/dummy/config/environments/development.rb +0 -3
  112. data/test/dummy/config/environments/test.rb +0 -5
  113. data/test/dummy/db/schema.rb +52 -14
  114. data/test/dummy/db/seeds.rb +1 -1
  115. data/test/fixtures/payloads/check_suite_master.json +2 -2
  116. data/test/fixtures/payloads/invalid_pull_request.json +117 -0
  117. data/test/fixtures/payloads/provision_disabled_pull_request.json +454 -0
  118. data/test/fixtures/payloads/pull_request_assigned.json +480 -0
  119. data/test/fixtures/payloads/pull_request_closed.json +454 -0
  120. data/test/fixtures/payloads/pull_request_labeled.json +461 -0
  121. data/test/fixtures/payloads/pull_request_opened.json +454 -0
  122. data/test/fixtures/payloads/pull_request_reopened.json +454 -0
  123. data/test/fixtures/payloads/pull_request_unlabeled.json +454 -0
  124. data/test/fixtures/payloads/pull_request_with_no_repo.json +454 -0
  125. data/test/fixtures/shipit/commits.yml +15 -2
  126. data/test/fixtures/shipit/merge_requests.yml +141 -0
  127. data/test/fixtures/shipit/pull_request_assignments.yml +3 -0
  128. data/test/fixtures/shipit/pull_requests.yml +10 -131
  129. data/test/fixtures/shipit/repositories.yml +1 -0
  130. data/test/fixtures/shipit/stacks.yml +145 -0
  131. data/test/fixtures/shipit/statuses.yml +9 -0
  132. data/test/fixtures/shipit/tasks.yml +3 -0
  133. data/test/fixtures/shipit/users.yml +7 -0
  134. data/test/helpers/payloads_helper.rb +4 -0
  135. data/test/jobs/chunk_rollup_job_test.rb +15 -1
  136. data/test/jobs/destroy_repository_job_test.rb +27 -0
  137. data/test/jobs/perform_task_job_test.rb +8 -8
  138. data/test/jobs/{merge_pull_requests_job_test.rb → process_merge_requests_job_test.rb} +18 -18
  139. data/test/lib/shipit/deploy_commands_test.rb +16 -0
  140. data/test/lib/shipit/task_commands_test.rb +17 -0
  141. data/test/models/commits_test.rb +22 -13
  142. data/test/models/deploy_spec_test.rb +57 -24
  143. data/test/models/deploys_test.rb +148 -14
  144. data/test/models/{pull_request_test.rb → merge_request_test.rb} +30 -30
  145. data/test/models/pull_request_assignment_test.rb +16 -0
  146. data/test/models/shipit/provisioning_handler/base_test.rb +33 -0
  147. data/test/models/shipit/provisioning_handler/unregistered_provisioning_handler_test.rb +49 -0
  148. data/test/models/shipit/provisioning_handler_test.rb +64 -0
  149. data/test/models/shipit/pull_request_test.rb +52 -0
  150. data/test/models/shipit/repository_test.rb +5 -1
  151. data/test/models/shipit/review_stack_provision_status_test.rb +77 -0
  152. data/test/models/shipit/review_stack_provisioning_queue_test.rb +63 -0
  153. data/test/models/shipit/review_stack_test.rb +59 -0
  154. data/test/models/{stacks_test.rb → shipit/stacks_test.rb} +10 -4
  155. data/test/models/shipit/webhooks/handlers/pull_request/assigned_handler_test.rb +45 -0
  156. data/test/models/shipit/webhooks/handlers/pull_request/closed_handler_test.rb +192 -0
  157. data/test/models/shipit/webhooks/handlers/pull_request/edited_handler_test.rb +47 -0
  158. data/test/models/shipit/webhooks/handlers/pull_request/label_capturing_handler_test.rb +209 -0
  159. data/test/models/shipit/webhooks/handlers/pull_request/labeled_handler_test.rb +332 -0
  160. data/test/models/shipit/webhooks/handlers/pull_request/opened_handler_test.rb +238 -0
  161. data/test/models/shipit/webhooks/handlers/pull_request/reopened_handler_test.rb +282 -0
  162. data/test/models/shipit/webhooks/handlers/pull_request/review_stack_adapter_test.rb +83 -0
  163. data/test/models/shipit/webhooks/handlers/pull_request/unlabeled_handler_test.rb +324 -0
  164. data/test/models/shipit/{wehbooks → webhooks}/handlers_test.rb +0 -0
  165. data/test/models/tasks_test.rb +44 -3
  166. data/test/serializers/shipit/pull_request_serializer_test.rb +29 -0
  167. data/test/unit/command_test.rb +3 -3
  168. data/test/unit/github_url_helper_test.rb +5 -0
  169. data/test/unit/shipit_task_execution_strategy_test.rb +47 -0
  170. metadata +260 -154
  171. data/app/controllers/shipit/pull_requests_controller.rb +0 -31
  172. data/app/jobs/shipit/merge_pull_requests_job.rb +0 -32
  173. data/app/jobs/shipit/refresh_pull_request_job.rb +0 -11
  174. data/app/views/shipit/pull_requests/_pull_request.html.erb +0 -29
  175. data/test/fixtures/shipit/output_chunks.yml +0 -47
  176. data/test/models/output_chunk_test.rb +0 -21
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shipit
4
+ module ProvisioningHandler
5
+ class Base
6
+ def initialize(stack)
7
+ @stack = stack
8
+ end
9
+
10
+ def up
11
+ # Intentionally a noop
12
+ end
13
+
14
+ def down
15
+ # Intentionally a noop
16
+ end
17
+
18
+ # An (optional) guard to prevent provisioning. Intended to be
19
+ # use to set logic to determine if enough actual resources exist
20
+ # to complete the provisioning request.
21
+ def provision?
22
+ true
23
+ end
24
+
25
+ private
26
+
27
+ attr_accessor :stack
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shipit
4
+ module ProvisioningHandler
5
+ class UnregisteredProvisioningHandler < Shipit::ProvisioningHandler::Base
6
+ def up
7
+ lock_and_prevent_transition
8
+ end
9
+
10
+ def down
11
+ lock_and_prevent_transition
12
+ end
13
+
14
+ private
15
+
16
+ def lock_and_prevent_transition
17
+ stack.lock(
18
+ "Failed to find a provisioning handler named '#{stack.provisioning_handler_name}' in the " \
19
+ "ProvisioningHandler registry. Have you registered it via Provisioning::Handler.register?",
20
+ Shipit::AnonymousUser.new
21
+ )
22
+
23
+ # Prevent transition of the ReviewStack 'provision_status'
24
+ # state machine. This signals to the state_machines gem that
25
+ # the transition should be canceled.
26
+ #
27
+ # References:
28
+ #
29
+ # - https://github.com/state-machines/state_machines/blob/309668998449ca6c348de809f34660d822bc626e/lib/state_machines/callback.rb#L81-L89
30
+ # - https://github.com/state-machines/state_machines/blob/309668998449ca6c348de809f34660d822bc626e/lib/state_machines/transition_collection.rb#L63
31
+ throw(:halt)
32
+ end
33
+ end
34
+ end
35
+ end
@@ -1,299 +1,60 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Shipit
3
- class PullRequest < ApplicationRecord
4
+ class PullRequest < Record
4
5
  include DeferredTouch
5
6
 
6
- MERGE_REQUEST_FIELD = 'Merge-Requested-By'
7
-
8
- WAITING_STATUSES = %w(fetching pending).freeze
9
- QUEUED_STATUSES = %w(pending revalidating).freeze
10
- REJECTION_REASONS = %w(ci_missing ci_failing merge_conflict requires_rebase).freeze
11
- InvalidTransition = Class.new(StandardError)
12
- NotReady = Class.new(StandardError)
13
-
14
- class StatusChecker < Status::Group
15
- def initialize(commit, statuses, deploy_spec)
16
- @deploy_spec = deploy_spec
17
- super(commit, statuses)
18
- end
19
-
20
- private
21
-
22
- attr_reader :deploy_spec
23
-
24
- def reject_hidden(statuses)
25
- statuses.reject { |s| ignored_statuses.include?(s.context) }
26
- end
27
-
28
- def reject_allowed_to_fail(statuses)
29
- statuses.reject { |s| ignored_statuses.include?(s.context) }
30
- end
31
-
32
- def ignored_statuses
33
- deploy_spec&.pull_request_ignored_statuses || []
34
- end
35
-
36
- def required_statuses
37
- deploy_spec&.pull_request_required_statuses || []
38
- end
39
- end
40
-
41
7
  belongs_to :stack
8
+ belongs_to :user
42
9
  belongs_to :head, class_name: 'Shipit::Commit', optional: true
43
- belongs_to :base_commit, class_name: 'Shipit::Commit', optional: true
44
- belongs_to :merge_requested_by, class_name: 'Shipit::User', optional: true
45
- has_one :merge_commit, class_name: 'Shipit::Commit'
46
-
47
- deferred_touch stack: :updated_at
48
-
49
- validates :number, presence: true, uniqueness: { scope: :stack_id }
50
-
51
- scope :waiting, -> { where(merge_status: WAITING_STATUSES) }
52
- scope :pending, -> { where(merge_status: 'pending') }
53
- scope :to_be_merged, -> { pending.order(merge_requested_at: :asc) }
54
- scope :queued, -> { where(merge_status: QUEUED_STATUSES).order(merge_requested_at: :asc) }
55
-
56
- after_save :record_merge_status_change
57
- after_commit :emit_hooks
58
-
59
- state_machine :merge_status, initial: :fetching do
60
- state :fetching
61
- state :pending
62
- state :rejected
63
- state :canceled
64
- state :merged
65
- state :revalidating
66
10
 
67
- event :fetched do
68
- transition fetching: :pending
69
- end
70
-
71
- event :reject do
72
- transition pending: :rejected
73
- end
11
+ has_many :pull_request_assignments
12
+ has_many :assignees, class_name: :User, through: :pull_request_assignments, source: :user
74
13
 
75
- event :revalidate do
76
- transition pending: :revalidating
77
- end
78
-
79
- event :cancel do
80
- transition any => :canceled
81
- end
14
+ serialize :labels, Array
82
15
 
83
- event :complete do
84
- transition pending: :merged
85
- end
86
-
87
- event :retry do
88
- transition %i(rejected canceled revalidating) => :pending
89
- end
90
-
91
- before_transition rejected: any do |pr|
92
- pr.rejection_reason = nil
93
- end
16
+ after_create_commit :emit_create_hooks
17
+ after_update_commit :emit_update_hooks
18
+ after_destroy_commit :emit_destroy_hooks
94
19
 
95
- before_transition %i(fetching rejected canceled) => :pending do |pr|
96
- pr.merge_requested_at = Time.now.utc
97
- end
98
-
99
- before_transition any => :pending do |pr|
100
- pr.revalidated_at = Time.now.utc
101
- end
102
-
103
- before_transition %i(pending) => :merged do |pr|
104
- Stack.increment_counter(:undeployed_commits_count, pr.stack_id)
105
- end
20
+ def emit_destroy_hooks
21
+ emit_hooks(:destroyed)
106
22
  end
107
23
 
108
- def self.schedule_merges
109
- Shipit::Stack.where(merge_queue_enabled: true).find_each(&:schedule_merges)
24
+ def emit_create_hooks
25
+ emit_hooks(:created)
110
26
  end
111
27
 
112
- def self.extract_number(stack, number_or_url)
113
- case number_or_url
114
- when /\A#?(\d+)\z/
115
- $1.to_i
116
- when %r{\Ahttps://#{Regexp.escape(Shipit.github.domain)}/([^/]+)/([^/]+)/pull/(\d+)}
117
- return unless $1.downcase == stack.repo_owner.downcase
118
- return unless $2.downcase == stack.repo_name.downcase
119
- $3.to_i
120
- end
28
+ def emit_update_hooks
29
+ emit_hooks(:updated)
121
30
  end
122
31
 
123
- def self.request_merge!(stack, number, user)
124
- now = Time.now.utc
125
- pull_request = begin
126
- create_with(
127
- merge_requested_at: now,
128
- merge_requested_by: user.presence,
129
- ).find_or_create_by!(
130
- stack: stack,
131
- number: number,
132
- )
133
- rescue ActiveRecord::RecordNotUnique
134
- retry
135
- end
136
- pull_request.update!(merge_requested_by: user.presence)
137
- pull_request.retry! if pull_request.rejected? || pull_request.canceled? || pull_request.revalidating?
138
- pull_request.schedule_refresh!
139
- pull_request
140
- end
141
-
142
- def reject!(reason)
143
- unless REJECTION_REASONS.include?(reason)
144
- raise ArgumentError, "invalid reason: #{reason.inspect}, must be one of: #{REJECTION_REASONS.inspect}"
145
- end
146
- self.rejection_reason = reason.presence
147
- super()
148
- true
149
- end
150
-
151
- def reject_unless_mergeable!
152
- return reject!('merge_conflict') if merge_conflict?
153
- return reject!('ci_missing') if any_status_checks_missing?
154
- return reject!('ci_failing') if any_status_checks_failed?
155
- return reject!('requires_rebase') if stale?
156
- false
157
- end
158
-
159
- def merge!
160
- raise InvalidTransition unless pending?
161
-
162
- raise NotReady if not_mergeable_yet?
163
-
164
- Shipit.github.api.merge_pull_request(
165
- stack.github_repo_name,
166
- number,
167
- merge_message,
168
- sha: head.sha,
169
- commit_message: 'Merged by Shipit',
170
- merge_method: stack.merge_method,
171
- )
172
- begin
173
- if Shipit.github.api.pull_requests(stack.github_repo_name, base: branch).empty?
174
- Shipit.github.api.delete_branch(stack.github_repo_name, branch)
175
- end
176
- rescue Octokit::UnprocessableEntity
177
- # branch was already deleted somehow
178
- end
179
- complete!
180
- true
181
- rescue Octokit::MethodNotAllowed # merge conflict
182
- reject!('merge_conflict')
183
- false
184
- rescue Octokit::Conflict # shas didn't match, PR was updated.
185
- raise NotReady
186
- end
187
-
188
- def all_status_checks_passed?
189
- return false unless head
190
- StatusChecker.new(head, head.statuses_and_check_runs, stack.cached_deploy_spec).success?
191
- end
192
-
193
- def any_status_checks_failed?
194
- status = StatusChecker.new(head, head.statuses_and_check_runs, stack.cached_deploy_spec)
195
- status.failure? || status.error?
196
- end
197
-
198
- def any_status_checks_missing?
199
- StatusChecker.new(head, head.statuses_and_check_runs, stack.cached_deploy_spec).missing?
200
- end
201
-
202
- def waiting?
203
- WAITING_STATUSES.include?(merge_status)
204
- end
205
-
206
- def need_revalidation?
207
- timeout = stack.cached_deploy_spec&.revalidate_pull_requests_after
208
- return false unless timeout
209
- (revalidated_at + timeout).past?
210
- end
211
-
212
- def merge_conflict?
213
- mergeable == false
214
- end
215
-
216
- def not_mergeable_yet?
217
- mergeable.nil?
218
- end
219
-
220
- def schedule_refresh!
221
- RefreshPullRequestJob.perform_later(self)
222
- end
223
-
224
- def closed?
225
- state == "closed"
226
- end
227
-
228
- def merged_upstream?
229
- closed? && merged_at
230
- end
231
-
232
- def refresh!
233
- update!(github_pull_request: Shipit.github.api.pull_request(stack.github_repo_name, number))
234
- head.refresh_statuses!
235
- fetched! if fetching?
236
- @comparison = nil
32
+ def emit_hooks(reason)
33
+ Hook.emit('pull_request', stack, action: reason, pull_request: self, stack: stack)
237
34
  end
238
35
 
239
36
  def github_pull_request=(github_pull_request)
240
37
  self.github_id = github_pull_request.id
38
+ self.number = github_pull_request.number
241
39
  self.api_url = github_pull_request.url
242
40
  self.title = github_pull_request.title
243
41
  self.state = github_pull_request.state
244
- self.mergeable = github_pull_request.mergeable
245
42
  self.additions = github_pull_request.additions
246
43
  self.deletions = github_pull_request.deletions
247
- self.branch = github_pull_request.head.ref
248
- self.head = find_or_create_commit_from_github_by_sha!(github_pull_request.head.sha, detached: true)
249
- self.merged_at = github_pull_request.merged_at
250
- self.base_ref = github_pull_request.base.ref
251
- self.base_commit = find_or_create_commit_from_github_by_sha!(github_pull_request.base.sha, detached: true)
252
- end
253
-
254
- def merge_message
255
- return title unless merge_requested_by
256
- "#{title}\n\n#{MERGE_REQUEST_FIELD}: #{merge_requested_by.login}\n"
257
- end
258
-
259
- def stale?
260
- return false unless base_commit
261
- spec = stack.cached_deploy_spec
262
- if max_branch_age = spec.max_divergence_age
263
- return true if Time.now.utc - head.committed_at > max_branch_age
264
- end
265
- if commit_count_limit = spec.max_divergence_commits
266
- return true if comparison.behind_by > commit_count_limit
44
+ self.user = User.find_or_create_by_login!(github_pull_request.user.login)
45
+ self.assignees = github_pull_request.assignees.map do |github_user|
46
+ User.find_or_create_by_login!(github_user.login)
267
47
  end
268
- false
269
- end
270
-
271
- def comparison
272
- @comparison ||= Shipit.github.api.compare(
273
- stack.github_repo_name,
274
- base_ref,
275
- head.sha,
276
- )
277
- end
278
-
279
- private
280
-
281
- def record_merge_status_change
282
- @merge_status_changed ||= saved_change_to_attribute?(:merge_status)
283
- end
284
-
285
- def emit_hooks
286
- return unless @merge_status_changed
287
- @merge_status_changed = nil
288
- Hook.emit('merge', stack, pull_request: self, status: merge_status, stack: stack)
48
+ self.labels = github_pull_request.labels.map(&:name)
49
+ self.head = find_or_create_commit_from_github_by_sha!(github_pull_request.head.sha)
289
50
  end
290
51
 
291
- def find_or_create_commit_from_github_by_sha!(sha, attributes)
52
+ def find_or_create_commit_from_github_by_sha!(sha)
292
53
  if commit = stack.commits.by_sha(sha)
293
54
  commit
294
55
  else
295
56
  github_commit = Shipit.github.api.commit(stack.github_repo_name, sha)
296
- stack.commits.create_from_github!(github_commit, attributes)
57
+ stack.commits.create_from_github!(github_commit)
297
58
  end
298
59
  rescue ActiveRecord::RecordNotUnique
299
60
  retry
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shipit
4
+ class PullRequestAssignment < Record
5
+ belongs_to :pull_request, required: true
6
+ belongs_to :user, required: true
7
+
8
+ validates :user_id, uniqueness: { scope: :pull_request_id }
9
+ end
10
+ end
@@ -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
@@ -14,6 +44,10 @@ module Shipit
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,6 +62,10 @@ 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
70
  Shipit.github.url(full_name)
33
71
  end
@@ -39,5 +77,21 @@ module Shipit
39
77
  def git_url
40
78
  "https://#{Shipit.github.domain}/#{owner}/#{name}.git"
41
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
42
96
  end
43
97
  end