shipit-engine 0.15.0 → 0.16.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (111) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +34 -1
  3. data/app/assets/javascripts/shipit/page_updater.js.coffee +63 -0
  4. data/app/assets/javascripts/shipit/stacks.js.coffee +9 -21
  5. data/app/assets/stylesheets/_base/_base.scss +2 -2
  6. data/app/assets/stylesheets/_base/_colors.scss +0 -1
  7. data/app/assets/stylesheets/_base/_forms.scss +14 -0
  8. data/app/assets/stylesheets/_pages/_commits.scss +16 -6
  9. data/app/assets/stylesheets/_pages/_settings.scss +8 -0
  10. data/app/assets/stylesheets/_pages/_stacks.scss +1 -1
  11. data/app/controllers/shipit/api/base_controller.rb +7 -3
  12. data/app/controllers/shipit/api/ccmenu_controller.rb +33 -0
  13. data/app/controllers/shipit/api/pull_requests_controller.rb +36 -0
  14. data/app/controllers/shipit/api/stacks_controller.rb +1 -0
  15. data/app/controllers/shipit/ccmenu_url_controller.rb +22 -0
  16. data/app/controllers/shipit/pull_requests_controller.rb +30 -0
  17. data/app/controllers/shipit/stacks_controller.rb +7 -2
  18. data/app/controllers/shipit/webhooks_controller.rb +1 -2
  19. data/app/helpers/shipit/github_url_helper.rb +8 -2
  20. data/app/helpers/shipit/shipit_helper.rb +9 -0
  21. data/app/helpers/shipit/stacks_helper.rb +22 -7
  22. data/app/jobs/shipit/background_job/unique.rb +19 -1
  23. data/app/jobs/shipit/cache_deploy_spec_job.rb +1 -1
  24. data/app/jobs/shipit/merge_pull_requests_job.rb +26 -0
  25. data/app/jobs/shipit/perform_task_job.rb +1 -1
  26. data/app/jobs/shipit/refresh_pull_request_job.rb +8 -0
  27. data/app/models/concerns/shipit/deferred_touch.rb +6 -1
  28. data/app/models/shipit/anonymous_user.rb +4 -0
  29. data/app/models/shipit/application_record.rb +5 -0
  30. data/app/models/shipit/commit.rb +51 -49
  31. data/app/models/shipit/commit_message.rb +32 -0
  32. data/app/models/shipit/deploy.rb +5 -0
  33. data/app/models/shipit/deploy_spec.rb +26 -1
  34. data/app/models/shipit/deploy_spec/file_system.rb +6 -1
  35. data/app/models/shipit/deploy_spec/kubernetes_discovery.rb +10 -13
  36. data/app/models/shipit/deploy_spec/npm_discovery.rb +2 -1
  37. data/app/models/shipit/duration.rb +3 -1
  38. data/app/models/shipit/hook.rb +1 -0
  39. data/app/models/shipit/pull_request.rb +252 -0
  40. data/app/models/shipit/stack.rb +33 -17
  41. data/app/models/shipit/status.rb +1 -16
  42. data/app/models/shipit/status/common.rb +45 -0
  43. data/app/models/shipit/status/group.rb +82 -0
  44. data/app/models/shipit/status/missing.rb +30 -0
  45. data/app/models/shipit/status/unknown.rb +33 -0
  46. data/app/models/shipit/unlimited_api_client.rb +10 -0
  47. data/app/serializers/shipit/commit_serializer.rb +1 -1
  48. data/app/serializers/shipit/pull_request_serializer.rb +20 -0
  49. data/app/serializers/shipit/stack_serializer.rb +6 -2
  50. data/app/views/layouts/shipit.html.erb +41 -39
  51. data/app/views/shipit/ccmenu/project.xml.builder +13 -0
  52. data/app/views/shipit/commits/_commit.html.erb +1 -1
  53. data/app/views/shipit/deploys/_deploy.html.erb +1 -1
  54. data/app/views/shipit/pull_requests/_pull_request.html.erb +29 -0
  55. data/app/views/shipit/pull_requests/index.html.erb +20 -0
  56. data/app/views/shipit/shared/_author.html.erb +7 -0
  57. data/app/views/shipit/stacks/_header.html.erb +5 -0
  58. data/app/views/shipit/stacks/settings.html.erb +13 -0
  59. data/app/views/shipit/stacks/show.html.erb +3 -2
  60. data/app/views/shipit/statuses/_group.html.erb +1 -1
  61. data/app/views/shipit/tasks/_task.html.erb +1 -1
  62. data/config/initializers/inflections.rb +3 -0
  63. data/config/locales/en.yml +1 -3
  64. data/config/routes.rb +8 -0
  65. data/db/migrate/20170130113633_create_shipit_pull_requests.rb +25 -0
  66. data/db/migrate/20170208143657_add_pull_request_number_and_title_to_commits.rb +7 -0
  67. data/db/migrate/20170208154609_backfill_merge_commits.rb +13 -0
  68. data/db/migrate/20170209160355_add_branch_to_pull_requests.rb +5 -0
  69. data/db/migrate/20170215123538_add_merge_queue_enabled_to_stacks.rb +5 -0
  70. data/db/migrate/20170220152410_improve_users_indexing.rb +6 -0
  71. data/db/migrate/20170221102128_improve_tasks_indexing.rb +8 -0
  72. data/db/migrate/20170221130336_add_last_revalidated_at_on_pull_requests.rb +10 -0
  73. data/lib/shipit.rb +2 -0
  74. data/lib/shipit/version.rb +1 -1
  75. data/lib/tasks/cron.rake +1 -0
  76. data/test/controllers/api/ccmenu_controller_test.rb +57 -0
  77. data/test/controllers/api/commits_controller_test.rb +1 -1
  78. data/test/controllers/api/pull_requests_controller_test.rb +59 -0
  79. data/test/controllers/ccmenu_controller_test.rb +33 -0
  80. data/test/controllers/pull_requests_controller_test.rb +31 -0
  81. data/test/controllers/webhooks_controller_test.rb +3 -4
  82. data/test/dummy/config/environments/development.rb +3 -1
  83. data/test/dummy/data/stacks/shopify/junk/production/git/README.md +8 -0
  84. data/test/dummy/data/stacks/shopify/junk/production/git/circle.yml +4 -0
  85. data/test/dummy/data/stacks/shopify/junk/production/git/shipit.yml +4 -0
  86. data/test/dummy/db/development.sqlite3 +0 -0
  87. data/test/dummy/db/schema.rb +45 -11
  88. data/test/dummy/db/seeds.rb +33 -10
  89. data/test/dummy/db/test.sqlite3 +0 -0
  90. data/test/fixtures/shipit/commits.yml +14 -0
  91. data/test/fixtures/shipit/pull_requests.yml +56 -0
  92. data/test/fixtures/shipit/stacks.yml +5 -1
  93. data/test/fixtures/shipit/statuses.yml +8 -0
  94. data/test/helpers/json_helper.rb +16 -14
  95. data/test/jobs/merge_pull_requests_job_test.rb +59 -0
  96. data/test/models/commits_test.rb +104 -49
  97. data/test/{unit → models}/deploy_spec_test.rb +138 -12
  98. data/test/models/deploys_test.rb +10 -4
  99. data/test/models/pull_request_test.rb +197 -0
  100. data/test/models/stacks_test.rb +46 -53
  101. data/test/models/status/group_test.rb +44 -0
  102. data/test/models/status/missing_test.rb +23 -0
  103. data/test/models/status_test.rb +3 -6
  104. data/test/unit/csv_serializer_test.rb +10 -2
  105. metadata +57 -12
  106. data/app/models/shipit/missing_status.rb +0 -21
  107. data/app/models/shipit/status_group.rb +0 -35
  108. data/app/models/shipit/unknown_status.rb +0 -48
  109. data/app/views/shipit/commits/_commit_author.html.erb +0 -7
  110. data/test/models/missing_status_test.rb +0 -23
  111. data/test/models/status_group_test.rb +0 -26
@@ -27,8 +27,7 @@ module Shipit
27
27
  end
28
28
  end
29
29
  def state
30
- if params.branches.map(&:name).include?(stack.branch)
31
- commit = stack.commits.find_by_sha!(params.sha)
30
+ if commit = stack.commits.find_by_sha(params.sha)
32
31
  commit.create_status_from_github!(params)
33
32
  end
34
33
  head :ok
@@ -40,8 +40,14 @@ module Shipit
40
40
  github_repo_url(commit.stack.repo_owner, commit.stack.repo_name, 'commit', commit.sha)
41
41
  end
42
42
 
43
- def github_pull_request_url(commit)
44
- github_repo_url(commit.stack.repo_owner, commit.stack.repo_name, 'pull', commit.pull_request_number)
43
+ def github_pull_request_url(pull_request_or_commit)
44
+ stack = pull_request_or_commit.stack
45
+ number = if pull_request_or_commit.respond_to?(:pull_request_number)
46
+ pull_request_or_commit.pull_request_number
47
+ else
48
+ pull_request_or_commit.number
49
+ end
50
+ github_repo_url(stack.repo_owner, stack.repo_name, 'pull', number)
45
51
  end
46
52
 
47
53
  def link_to_github_deploy(deploy)
@@ -1,5 +1,14 @@
1
1
  module Shipit
2
2
  module ShipitHelper
3
+ def subscribe(url, *selectors)
4
+ content_for(:update_subscription) do
5
+ [
6
+ tag('meta', name: 'subscription-channel', content: url),
7
+ *selectors.map { |s| tag('meta', name: 'subscription-selector', content: s) },
8
+ ].join("\n").html_safe
9
+ end
10
+ end
11
+
3
12
  def emojify(content)
4
13
  h(content).to_str.gsub(/:([\w+-]+):/) do |match|
5
14
  if emoji = Emoji.find_by_alias($1)
@@ -33,16 +33,26 @@ module Shipit
33
33
  end
34
34
 
35
35
  def github_change_url(commit)
36
- commit.pull_request_url || github_commit_url(commit)
36
+ if commit.pull_request?
37
+ github_pull_request_url(commit)
38
+ else
39
+ github_commit_url(commit)
40
+ end
37
41
  end
38
42
 
39
- def render_commit_message(commit)
40
- message = commit.pull_request_title || commit.message
41
- content_tag(:span, emojify(message.truncate(COMMIT_TITLE_LENGTH)), class: 'event-message')
43
+ def render_commit_message(pull_request_or_commit)
44
+ message = pull_request_or_commit.title.to_s.truncate(COMMIT_TITLE_LENGTH)
45
+ content_tag(:span, emojify(message), class: 'event-message')
46
+ end
47
+
48
+ def render_pull_request_title_with_link(pull_request)
49
+ message = render_commit_message(pull_request)
50
+ link_to(message, github_pull_request_url(pull_request), target: '_blank')
42
51
  end
43
52
 
44
53
  def render_commit_message_with_link(commit)
45
- link_to(render_commit_message(commit), github_change_url(commit), target: '_blank')
54
+ message = render_commit_message(commit)
55
+ link_to(message, github_change_url(commit), target: '_blank')
46
56
  end
47
57
 
48
58
  def render_commit_id_link(commit)
@@ -53,8 +63,13 @@ module Shipit
53
63
  end
54
64
  end
55
65
 
56
- def pull_request_link(commit)
57
- link_to("##{commit.pull_request_number}", commit.pull_request_url, target: '_blank', class: 'number')
66
+ def pull_request_link(pull_request_or_commit)
67
+ number = if pull_request_or_commit.respond_to?(:pull_request_number)
68
+ pull_request_or_commit.pull_request_number
69
+ else
70
+ pull_request_or_commit.number
71
+ end
72
+ link_to("##{number}", github_pull_request_url(pull_request_or_commit), target: '_blank', class: 'number')
58
73
  end
59
74
 
60
75
  def render_raw_commit_id_link(commit)
@@ -2,12 +2,12 @@ module Shipit
2
2
  class BackgroundJob
3
3
  module Unique
4
4
  extend ActiveSupport::Concern
5
-
6
5
  DEFAULT_TIMEOUT = 10
7
6
 
8
7
  included do
9
8
  around_perform { |job, block| job.acquire_lock(&block) }
10
9
  cattr_accessor :lock_timeout
10
+ on_duplicate :retry
11
11
  end
12
12
 
13
13
  def acquire_lock(&block)
@@ -18,11 +18,29 @@ module Shipit
18
18
  timeout: self.class.lock_timeout || 0,
19
19
  )
20
20
  mutex.lock(&block)
21
+ rescue Redis::Lock::LockTimeout
22
+ raise unless self.class.drop_duplicate_jobs?
21
23
  end
22
24
 
23
25
  def lock_key(*args)
24
26
  ActiveJob::Arguments.serialize([self.class.name] + args).join('-')
25
27
  end
28
+
29
+ module ClassMethods
30
+ ACTIONS = %i(retry drop).freeze
31
+ ACTIONS_LIST = ACTIONS.map(&:inspect).join(', ').freeze
32
+ def on_duplicate(action)
33
+ unless ACTIONS.include?(action)
34
+ raise ArgumentsError, "invalid action: #{action.inspect}, should be one of #{ACTIONS_LIST}"
35
+ end
36
+
37
+ @on_duplicate = action
38
+ end
39
+
40
+ def drop_duplicate_jobs?
41
+ @on_duplicate == :drop
42
+ end
43
+ end
26
44
  end
27
45
  end
28
46
  end
@@ -6,7 +6,7 @@ module Shipit
6
6
  return if stack.inaccessible?
7
7
 
8
8
  commands = Commands.for(stack)
9
- commands.with_temporary_working_directory(commit: stack.commits.last) do |path|
9
+ commands.with_temporary_working_directory(commit: stack.commits.reachable.last) do |path|
10
10
  stack.update!(cached_deploy_spec: DeploySpec::FileSystem.new(path, stack.environment))
11
11
  end
12
12
  end
@@ -0,0 +1,26 @@
1
+ module Shipit
2
+ class MergePullRequestsJob < BackgroundJob
3
+ include BackgroundJob::Unique
4
+ on_duplicate :drop
5
+
6
+ def perform(stack)
7
+ pull_requests = stack.pull_requests.to_be_merged.to_a
8
+ pull_requests.each do |pull_request|
9
+ pull_request.refresh!
10
+ pull_request.reject_unless_mergeable!
11
+ end
12
+
13
+ return false unless stack.allows_merges?
14
+
15
+ pull_requests.select(&:pending?).each do |pull_request|
16
+ pull_request.refresh!
17
+ begin
18
+ pull_request.merge!
19
+ rescue PullRequest::NotReady
20
+ MergePullRequestsJob.set(wait: 10.seconds).perform_later(stack)
21
+ return false
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -52,7 +52,7 @@ module Shipit
52
52
  end
53
53
 
54
54
  def perform_task
55
- Bundler.with_original_env do
55
+ Bundler.with_clean_env do
56
56
  capture_all! @commands.install_dependencies
57
57
  capture_all! @commands.perform
58
58
  end
@@ -0,0 +1,8 @@
1
+ module Shipit
2
+ class RefreshPullRequestJob < BackgroundJob
3
+ def perform(pull_request)
4
+ pull_request.refresh!
5
+ MergePullRequestsJob.perform_later(pull_request.stack)
6
+ end
7
+ end
8
+ end
@@ -77,7 +77,12 @@ module Shipit
77
77
 
78
78
  def schedule_touches
79
79
  return unless self.class.deferred_touches
80
- touches = self.class.deferred_touches.map { |m, fk, a| [m, self[fk], a].join('|') }
80
+ deferred_touches = self.class.deferred_touches.reject do |m, _fk, _a|
81
+ ActiveRecord::NoTouching.applied_to?(m.constantize)
82
+ end
83
+ return if deferred_touches.empty?
84
+
85
+ touches = deferred_touches.map { |m, fk, a| [m, self[fk], a].join('|') }
81
86
  Shipit.redis.sadd(SET_KEY, touches)
82
87
  if DeferredTouch.enabled
83
88
  Rails.cache.fetch(CACHE_KEY, expires_in: THROTTLE_TTL) do
@@ -1,5 +1,9 @@
1
1
  module Shipit
2
2
  class AnonymousUser
3
+ def present?
4
+ false
5
+ end
6
+
3
7
  def email
4
8
  'anonymous@example.com'
5
9
  end
@@ -0,0 +1,5 @@
1
+ module Shipit
2
+ class ApplicationRecord < ActiveRecord::Base
3
+ self.abstract_class = true
4
+ end
5
+ end
@@ -8,9 +8,11 @@ module Shipit
8
8
  has_many :deploys
9
9
  has_many :statuses, -> { order(created_at: :desc) }, dependent: :destroy
10
10
  has_many :commit_deployments, dependent: :destroy
11
+ belongs_to :pull_request, inverse_of: :merge_commit
11
12
 
12
13
  deferred_touch stack: :updated_at
13
14
 
15
+ before_create :identify_pull_request
14
16
  after_commit { broadcast_update }
15
17
  after_create { stack.update_undeployed_commits_count }
16
18
 
@@ -21,7 +23,8 @@ module Shipit
21
23
 
22
24
  scope :reachable, -> { where(detached: false) }
23
25
 
24
- delegate :broadcast_update, :github_repo_name, to: :stack
26
+ delegate :broadcast_update, :github_repo_name, :hidden_statuses, :required_statuses,
27
+ :soft_failing_statuses, to: :stack
25
28
 
26
29
  def self.newer_than(commit)
27
30
  return all unless commit
@@ -69,12 +72,14 @@ module Shipit
69
72
  end
70
73
 
71
74
  def reload(*)
72
- @last_statuses = nil
75
+ @status = nil
73
76
  super
74
77
  end
75
78
 
76
- def self.create_from_github!(commit)
77
- from_github(commit).save!
79
+ def self.create_from_github!(commit, extra_attributes = {})
80
+ record = from_github(commit)
81
+ record.update!(extra_attributes)
82
+ record
78
83
  end
79
84
 
80
85
  def schedule_refresh_statuses!
@@ -112,30 +117,26 @@ module Shipit
112
117
  children.detach!
113
118
  end
114
119
 
115
- def pull_request_url
116
- parsed && Shipit.github_url("/#{stack.repo_owner}/#{stack.repo_name}/pull/#{pull_request_number}")
120
+ def pull_request?
121
+ pull_request_number.present?
117
122
  end
118
123
 
119
- def pull_request_number
120
- parsed && parsed['pr_id'].to_i
124
+ def pull_request_number # TODO: remove in a few versions when it is assumed the commits table was backfilled
125
+ super || message_parser.pull_request_number
121
126
  end
122
127
 
123
- def pull_request_title
124
- parsed && parsed['pr_title']
128
+ def title
129
+ pull_request_title || message
125
130
  end
126
131
 
127
- def pull_request?
128
- !!parsed
132
+ def pull_request_title # TODO: remove in a few versions when it is assumed the commits table was backfilled
133
+ super || message_parser.pull_request_title
129
134
  end
130
135
 
131
136
  def short_sha
132
137
  sha[0..9]
133
138
  end
134
139
 
135
- def parsed
136
- @parsed ||= message.match(/\AMerge pull request #(?<pr_id>\d+) from [\w\-.\/]+\n\n(?<pr_title>.*)/)
137
- end
138
-
139
140
  def schedule_continuous_delivery
140
141
  return unless deployable? && stack.continuous_deployment? && stack.deployable?
141
142
  ContinuousDeliveryJob.perform_later(stack)
@@ -156,30 +157,8 @@ module Shipit
156
157
  )
157
158
  end
158
159
 
159
- def visible_statuses
160
- stack.filter_visible_statuses(last_statuses).presence || [UnknownStatus.new(self)]
161
- end
162
-
163
- def meaningful_statuses
164
- stack.filter_meaningful_statuses(last_statuses).presence || [UnknownStatus.new(self)]
165
- end
166
-
167
- def last_statuses
168
- @last_statuses ||= statuses.to_a.uniq(&:context).sort_by(&:context).presence || [UnknownStatus.new(self)]
169
- end
170
-
171
160
  def status
172
- visibles = visible_statuses
173
- status = visibles.size > 1 ? StatusGroup.new(significant_status, visibles) : visibles.first
174
- missing_statuses.empty? ? status : MissingStatus.new(status, missing_statuses)
175
- end
176
-
177
- def significant_status
178
- statuses = meaningful_statuses
179
- return UnknownStatus.new(self) if statuses.empty?
180
- return statuses.first if statuses.all?(&:success?)
181
- non_success_statuses = statuses.reject(&:success?)
182
- non_success_statuses.reject(&:pending?).first || non_success_statuses.first || UnknownStatus.new(self)
161
+ @status ||= Status::Group.compact(self, statuses)
183
162
  end
184
163
 
185
164
  def deployed?
@@ -190,24 +169,47 @@ module Shipit
190
169
  stack.deploys.unsuccessful.where(until_commit_id: id).any?
191
170
  end
192
171
 
172
+ def identify_pull_request
173
+ return unless message_parser.pull_request?
174
+ if pull_request = stack.pull_requests.find_by_number(message_parser.pull_request_number)
175
+ self.pull_request = pull_request
176
+ self.pull_request_number = pull_request.number
177
+ self.pull_request_title = pull_request.title
178
+ self.author = pull_request.merge_requested_by if pull_request.merge_requested_by
179
+ end
180
+
181
+ self.pull_request_number = message_parser.pull_request_number unless self[:pull_request_number]
182
+ self.pull_request_title = message_parser.pull_request_title unless self[:pull_request_title]
183
+ end
184
+
193
185
  private
194
186
 
187
+ def message_parser
188
+ @message_parser ||= CommitMessage.new(message)
189
+ end
190
+
195
191
  def add_status
196
- previous_status = significant_status
192
+ already_deployed = deployed?
193
+
194
+ previous_status = status
197
195
  yield
198
196
  reload # to get the statuses into the right order (since sorted :desc)
199
- new_status = significant_status
197
+ new_status = status
200
198
 
201
- payload = {commit: self, stack: stack, status: new_status.state}
202
- Hook.emit(:commit_status, stack, payload.merge(commit_status: new_status)) if previous_status != new_status
203
- if previous_status.simple_state != new_status.simple_state && (!new_status.pending? || previous_status.unknown?)
204
- Hook.emit(:deployable_status, stack, payload.merge(deployable_status: new_status))
199
+ unless already_deployed
200
+ payload = {commit: self, stack: stack, status: new_status.state}
201
+ Hook.emit(:commit_status, stack, payload.merge(commit_status: new_status)) if previous_status != new_status
205
202
  end
206
- new_status
207
- end
208
203
 
209
- def missing_statuses
210
- stack.required_statuses - last_statuses.map(&:context)
204
+ if previous_status.simple_state != new_status.simple_state
205
+ if !already_deployed && (!new_status.pending? || previous_status.unknown?)
206
+ Hook.emit(:deployable_status, stack, payload.merge(deployable_status: new_status))
207
+ end
208
+ if new_status.pending? || new_status.success?
209
+ stack.schedule_merges
210
+ end
211
+ end
212
+ new_status
211
213
  end
212
214
  end
213
215
  end
@@ -0,0 +1,32 @@
1
+ module Shipit
2
+ class CommitMessage
3
+ GITHUB_MERGE_COMMIT_PATTERN = %r{\AMerge pull request #(?<pr_id>\d+) from [\w\-./]+\n\n(?<pr_title>.*)}
4
+
5
+ def initialize(text)
6
+ @text = text
7
+ end
8
+
9
+ def pull_request?
10
+ !!parsed
11
+ end
12
+
13
+ def pull_request_number
14
+ parsed && parsed['pr_id'].to_i
15
+ end
16
+
17
+ def pull_request_title
18
+ parsed && parsed['pr_title']
19
+ end
20
+
21
+ def to_s
22
+ @text
23
+ end
24
+
25
+ private
26
+
27
+ def parsed
28
+ return @parsed if defined?(@parsed)
29
+ @parsed = to_s.match(GITHUB_MERGE_COMMIT_PATTERN)
30
+ end
31
+ end
32
+ end
@@ -6,6 +6,7 @@ module Shipit
6
6
 
7
7
  state_machine :status do
8
8
  after_transition to: :success, do: :schedule_continuous_delivery
9
+ after_transition to: :success, do: :schedule_merges
9
10
  after_transition to: :success, do: :update_undeployed_commits_count
10
11
  after_transition to: :aborted, do: :trigger_revert_if_required
11
12
  after_transition any => any, do: :update_commit_deployments
@@ -163,6 +164,10 @@ module Shipit
163
164
  self.deletions = commits.map(&:deletions).compact.sum
164
165
  end
165
166
 
167
+ def schedule_merges
168
+ stack.schedule_merges
169
+ end
170
+
166
171
  def schedule_continuous_delivery
167
172
  return unless stack.continuous_deployment?
168
173
  ContinuousDeliveryJob.perform_later(stack)
@@ -64,7 +64,7 @@ module Shipit
64
64
  alias_method :dependencies_steps!, :dependencies_steps
65
65
 
66
66
  def maximum_commits_per_deploy
67
- config('deploy', 'max_commits')
67
+ config('deploy', 'max_commits') { 8 }
68
68
  end
69
69
 
70
70
  def pause_between_deploys
@@ -143,6 +143,31 @@ module Shipit
143
143
  Array.wrap(config('ci', 'allow_failures'))
144
144
  end
145
145
 
146
+ def pull_request_required_statuses
147
+ if config('merge', 'require') || config('merge', 'ignore')
148
+ Array.wrap(config('merge', 'require'))
149
+ else
150
+ required_statuses
151
+ end
152
+ end
153
+
154
+ def pull_request_ignored_statuses
155
+ if config('merge', 'require') || config('merge', 'ignore')
156
+ Array.wrap(config('merge', 'ignore'))
157
+ else
158
+ soft_failing_statuses | hidden_statuses
159
+ end
160
+ end
161
+
162
+ def revalidate_pull_requests_after
163
+ if timeout = config('merge', 'revalidate_after')
164
+ begin
165
+ Duration.parse(timeout)
166
+ rescue Duration::ParseError
167
+ end
168
+ end
169
+ end
170
+
146
171
  def review_checks
147
172
  config('review', 'checks') || []
148
173
  end