shipit-engine 0.33.0 → 0.34.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.
- checksums.yaml +4 -4
- data/README.md +13 -2
- data/app/assets/stylesheets/_pages/_deploy.scss +0 -2
- data/app/controllers/shipit/api/ccmenu_controller.rb +1 -1
- data/app/controllers/shipit/api/deploys_controller.rb +2 -0
- data/app/controllers/shipit/api/rollbacks_controller.rb +2 -1
- data/app/controllers/shipit/api/stacks_controller.rb +1 -0
- data/app/controllers/shipit/deploys_controller.rb +1 -1
- data/app/controllers/shipit/stacks_controller.rb +2 -2
- data/app/controllers/shipit/tasks_controller.rb +2 -2
- data/app/controllers/shipit/webhooks_controller.rb +23 -4
- data/app/helpers/shipit/shipit_helper.rb +0 -1
- data/app/jobs/shipit/deliver_hook_job.rb +1 -1
- data/app/jobs/shipit/github_sync_job.rb +13 -9
- data/app/jobs/shipit/update_github_last_deployed_ref_job.rb +1 -1
- data/app/models/shipit/anonymous_user.rb +6 -2
- data/app/models/shipit/check_run.rb +36 -0
- data/app/models/shipit/commit.rb +20 -9
- data/app/models/shipit/commit_checks.rb +13 -13
- data/app/models/shipit/commit_deployment.rb +3 -3
- data/app/models/shipit/commit_deployment_status.rb +3 -3
- data/app/models/shipit/deploy.rb +16 -11
- data/app/models/shipit/deploy_spec/lerna_discovery.rb +12 -4
- data/app/models/shipit/duration.rb +2 -0
- data/app/models/shipit/hook.rb +26 -2
- data/app/models/shipit/merge_request.rb +9 -7
- data/app/models/shipit/pull_request.rb +1 -1
- data/app/models/shipit/release_status.rb +1 -1
- data/app/models/shipit/repository.rb +9 -3
- data/app/models/shipit/review_stack.rb +16 -2
- data/app/models/shipit/stack.rb +59 -25
- data/app/models/shipit/status/group.rb +1 -1
- data/app/models/shipit/task.rb +6 -2
- data/app/models/shipit/task_execution_strategy/default.rb +4 -5
- data/app/models/shipit/team.rb +4 -2
- data/app/models/shipit/user.rb +4 -0
- data/app/models/shipit/webhooks/handlers/pull_request/review_stack_adapter.rb +1 -1
- data/app/models/shipit/webhooks/handlers/push_handler.rb +4 -1
- data/app/serializers/shipit/merge_request_serializer.rb +1 -1
- data/app/validators/subset_validator.rb +1 -1
- data/app/views/layouts/merge_status.html.erb +1 -1
- data/app/views/shipit/stacks/_banners.html.erb +2 -1
- data/app/views/shipit/stacks/new.html.erb +1 -1
- data/config/secrets.development.example.yml +24 -0
- data/config/secrets.development.shopify.yml +20 -9
- data/db/migrate/20210325194053_remove_stacks_branch_default.rb +5 -0
- data/db/migrate/20210504200438_add_github_updated_at_to_check_runs.rb +5 -0
- data/lib/shipit.rb +39 -15
- data/lib/shipit/command.rb +7 -6
- data/lib/shipit/commands.rb +9 -2
- data/lib/shipit/engine.rb +2 -0
- data/lib/shipit/flock.rb +8 -1
- data/lib/shipit/github_app.rb +7 -5
- data/lib/shipit/octokit_iterator.rb +3 -3
- data/lib/shipit/simple_message_verifier.rb +2 -2
- data/lib/shipit/stack_commands.rb +28 -4
- data/lib/shipit/task_commands.rb +6 -0
- data/lib/shipit/version.rb +1 -1
- data/lib/snippets/publish-lerna-independent-packages +35 -34
- data/lib/snippets/publish-lerna-independent-packages-legacy +39 -0
- data/test/controllers/api/ccmenu_controller_test.rb +1 -1
- data/test/controllers/api/deploys_controller_test.rb +17 -0
- data/test/controllers/api/stacks_controller_test.rb +21 -7
- data/test/controllers/webhooks_controller_test.rb +26 -11
- data/test/dummy/app/assets/config/manifest.js +3 -0
- data/test/dummy/config/application.rb +1 -1
- data/test/dummy/config/database.yml +9 -0
- data/test/dummy/config/environments/development.rb +1 -1
- data/test/dummy/config/secrets_double_github_app.yml +79 -0
- data/test/dummy/db/schema.rb +5 -4
- data/test/dummy/db/seeds.rb +1 -0
- data/test/fixtures/payloads/check_suite_master.json +2 -30
- data/test/fixtures/payloads/push_master.json +1 -1
- data/test/fixtures/payloads/push_not_master.json +1 -1
- data/test/fixtures/shipit/commits.yml +2 -2
- data/test/fixtures/shipit/hooks.yml +1 -0
- data/test/fixtures/shipit/tasks.yml +1 -1
- data/test/helpers/json_helper.rb +5 -1
- data/test/jobs/github_sync_job_test.rb +2 -1
- data/test/models/commit_deployment_status_test.rb +3 -3
- data/test/models/commits_test.rb +2 -0
- data/test/models/deploy_spec_test.rb +7 -0
- data/test/models/deploys_test.rb +18 -0
- data/test/models/hook_test.rb +30 -1
- data/test/models/merge_request_test.rb +19 -4
- data/test/models/shipit/check_run_test.rb +124 -5
- data/test/models/shipit/review_stack_test.rb +38 -6
- data/test/models/shipit/stacks_test.rb +42 -4
- data/test/models/shipit/webhooks/handlers/pull_request/review_stack_adapter_test.rb +24 -0
- data/test/models/tasks_test.rb +22 -0
- data/test/test_helper.rb +15 -0
- data/test/unit/anonymous_user_serializer_test.rb +1 -1
- data/test/unit/command_test.rb +5 -0
- data/test/unit/commit_serializer_test.rb +1 -1
- data/test/unit/deploy_commands_test.rb +70 -14
- data/test/unit/deploy_serializer_test.rb +1 -1
- data/test/unit/github_app_test.rb +2 -3
- data/test/unit/github_apps_test.rb +416 -0
- data/test/unit/shipit_deployment_checks_test.rb +77 -0
- data/test/unit/shipit_test.rb +14 -0
- data/test/unit/user_serializer_test.rb +1 -1
- metadata +202 -191
|
@@ -10,14 +10,14 @@ module Shipit
|
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
def synchronize(&block)
|
|
13
|
-
@lock ||= Redis::Lock.new('lock', redis, expiration: 1, timeout: 2)
|
|
13
|
+
@lock ||= Redis::Lock.new(key('lock'), Shipit.redis, expiration: 1, timeout: 2)
|
|
14
14
|
@lock.lock(&block)
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
def schedule
|
|
18
|
-
return false if redis.get('status').present?
|
|
18
|
+
return false if Shipit.redis.get(key('status')).present?
|
|
19
19
|
synchronize do
|
|
20
|
-
return false if redis.get('status').present?
|
|
20
|
+
return false if Shipit.redis.get(key('status')).present?
|
|
21
21
|
|
|
22
22
|
initialize_redis_state
|
|
23
23
|
end
|
|
@@ -26,34 +26,34 @@ module Shipit
|
|
|
26
26
|
end
|
|
27
27
|
|
|
28
28
|
def initialize_redis_state
|
|
29
|
-
redis.
|
|
30
|
-
redis.set('output', '', ex: OUTPUT_TTL)
|
|
31
|
-
redis.set('status', 'scheduled', ex: OUTPUT_TTL)
|
|
32
|
-
end
|
|
29
|
+
Shipit.redis.set(key('status'), 'scheduled', ex: OUTPUT_TTL)
|
|
33
30
|
@status = 'scheduled'
|
|
34
31
|
end
|
|
35
32
|
|
|
36
33
|
def status
|
|
37
|
-
@status ||= redis.get('status')
|
|
34
|
+
@status ||= Shipit.redis.get(key('status'))
|
|
38
35
|
end
|
|
39
36
|
|
|
40
37
|
def status=(status)
|
|
41
|
-
redis.set('status', status)
|
|
38
|
+
Shipit.redis.set(key('status'), status)
|
|
42
39
|
@status = status
|
|
43
40
|
end
|
|
44
41
|
|
|
45
42
|
def output(since: 0)
|
|
46
|
-
redis.getrange('output', since, -1)
|
|
43
|
+
Shipit.redis.getrange(key('output'), since, -1)
|
|
47
44
|
end
|
|
48
45
|
|
|
49
46
|
def write(output)
|
|
50
|
-
redis.
|
|
47
|
+
Shipit.redis.pipelined do
|
|
48
|
+
Shipit.redis.append(key('output'), output)
|
|
49
|
+
Shipit.redis.expire(key('output'), OUTPUT_TTL)
|
|
50
|
+
end
|
|
51
51
|
end
|
|
52
52
|
|
|
53
53
|
private
|
|
54
54
|
|
|
55
|
-
def
|
|
56
|
-
|
|
55
|
+
def key(key)
|
|
56
|
+
"commit:#{commit.id}:checks:#{key}"
|
|
57
57
|
end
|
|
58
58
|
end
|
|
59
59
|
end
|
|
@@ -20,15 +20,15 @@ module Shipit
|
|
|
20
20
|
return if github_id?
|
|
21
21
|
|
|
22
22
|
response = begin
|
|
23
|
-
create_deployment_on_github(
|
|
23
|
+
create_deployment_on_github(stack.github_api)
|
|
24
24
|
rescue Octokit::ClientError
|
|
25
|
-
raise if Shipit.github.api ==
|
|
25
|
+
raise if Shipit.github(organization: stack.repository.owner).api == stack.github_api
|
|
26
26
|
# If the deploy author didn't gave us the permission to create the deployment we falback the the main shipit
|
|
27
27
|
# user.
|
|
28
28
|
#
|
|
29
29
|
# Octokit currently raise NotFound, but I'm convinced it should be Forbidden if the user can see the repository.
|
|
30
30
|
# So to be future proof I catch boths.
|
|
31
|
-
create_deployment_on_github(
|
|
31
|
+
create_deployment_on_github(stack.github_api)
|
|
32
32
|
end
|
|
33
33
|
update!(github_id: response.id, api_url: response.url)
|
|
34
34
|
end
|
|
@@ -12,15 +12,15 @@ module Shipit
|
|
|
12
12
|
def create_on_github!
|
|
13
13
|
return if github_id?
|
|
14
14
|
response = begin
|
|
15
|
-
create_status_on_github(
|
|
15
|
+
create_status_on_github(stack.github_api)
|
|
16
16
|
rescue Octokit::ClientError
|
|
17
|
-
raise if Shipit.github.api ==
|
|
17
|
+
raise if Shipit.github(organization: stack.repository.owner).api == stack.github_api
|
|
18
18
|
# If the deploy author didn't gave us the permission to create the deployment we falback the the main shipit
|
|
19
19
|
# user.
|
|
20
20
|
#
|
|
21
21
|
# Octokit currently raise NotFound, but I'm convinced it should be Forbidden if the user can see the repository.
|
|
22
22
|
# So to be future proof I catch boths.
|
|
23
|
-
create_status_on_github(
|
|
23
|
+
create_status_on_github(stack.github_api)
|
|
24
24
|
end
|
|
25
25
|
update!(github_id: response.id, api_url: response.url)
|
|
26
26
|
end
|
data/app/models/shipit/deploy.rb
CHANGED
|
@@ -15,8 +15,8 @@ module Shipit
|
|
|
15
15
|
after_transition any => any, do: :update_last_deploy_time
|
|
16
16
|
end
|
|
17
17
|
|
|
18
|
-
belongs_to :until_commit, class_name: 'Commit', required: true
|
|
19
|
-
belongs_to :since_commit, class_name: 'Commit', required: true
|
|
18
|
+
belongs_to :until_commit, class_name: 'Commit', required: true
|
|
19
|
+
belongs_to :since_commit, class_name: 'Commit', required: true
|
|
20
20
|
has_many :commit_deployments, dependent: :destroy, inverse_of: :task, foreign_key: :task_id do
|
|
21
21
|
GITHUB_STATUSES = {
|
|
22
22
|
'pending' => 'pending',
|
|
@@ -97,14 +97,16 @@ module Shipit
|
|
|
97
97
|
end
|
|
98
98
|
|
|
99
99
|
# Rolls the stack back to this deploy
|
|
100
|
-
def trigger_rollback(user = AnonymousUser.new, env: nil, force: false)
|
|
100
|
+
def trigger_rollback(user = AnonymousUser.new, env: nil, force: false, lock: true)
|
|
101
101
|
rollback = build_rollback(user, env: env, force: force)
|
|
102
102
|
rollback.save!
|
|
103
103
|
rollback.enqueue
|
|
104
104
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
105
|
+
if lock
|
|
106
|
+
lock_reason = "A rollback for #{rollback.since_commit.sha} has been triggered. " \
|
|
107
|
+
"Please make sure the reason for the rollback has been addressed before deploying again."
|
|
108
|
+
stack.update!(lock_reason: lock_reason, lock_author_id: user.id)
|
|
109
|
+
end
|
|
108
110
|
|
|
109
111
|
rollback
|
|
110
112
|
end
|
|
@@ -209,7 +211,7 @@ module Shipit
|
|
|
209
211
|
end
|
|
210
212
|
|
|
211
213
|
def report_complete!
|
|
212
|
-
if stack.release_status? && stack.release_status_delay.
|
|
214
|
+
if stack.release_status? && !stack.release_status_delay.zero?
|
|
213
215
|
enter_validation!
|
|
214
216
|
else
|
|
215
217
|
super
|
|
@@ -269,10 +271,13 @@ module Shipit
|
|
|
269
271
|
when 'aborted', 'aborting'
|
|
270
272
|
append_release_status('failure', "The deploy on #{stack.environment} was canceled")
|
|
271
273
|
when 'validating'
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
274
|
+
append_release_status(
|
|
275
|
+
'pending',
|
|
276
|
+
"The deploy on #{stack.environment} succeeded"
|
|
277
|
+
) unless stack.release_status_delay.zero?
|
|
278
|
+
|
|
279
|
+
MarkDeployHealthyJob.set(wait: stack.release_status_delay)
|
|
280
|
+
.perform_later(self) if stack.release_status_delay.positive?
|
|
276
281
|
when 'success'
|
|
277
282
|
if stack.release_status_delay.zero?
|
|
278
283
|
append_release_status('success', "The deploy on #{stack.environment} succeeded")
|
|
@@ -76,10 +76,18 @@ module Shipit
|
|
|
76
76
|
end
|
|
77
77
|
|
|
78
78
|
def publish_independent_packages
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
79
|
+
command = if lerna_lerna >= LATEST_MAJOR_VERSION
|
|
80
|
+
[
|
|
81
|
+
'assert-lerna-independent-version-tags',
|
|
82
|
+
'publish-lerna-independent-packages',
|
|
83
|
+
]
|
|
84
|
+
else
|
|
85
|
+
[
|
|
86
|
+
'assert-lerna-independent-version-tags',
|
|
87
|
+
'publish-lerna-independent-packages-legacy',
|
|
88
|
+
]
|
|
89
|
+
end
|
|
90
|
+
command
|
|
83
91
|
end
|
|
84
92
|
|
|
85
93
|
def publish_fixed_version_packages
|
data/app/models/shipit/hook.rb
CHANGED
|
@@ -1,12 +1,28 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
module Shipit
|
|
3
3
|
class Hook < Record
|
|
4
|
+
class DeliverySigner
|
|
5
|
+
attr_reader :secret
|
|
6
|
+
|
|
7
|
+
ALGORITHM = 'sha256'
|
|
8
|
+
|
|
9
|
+
def initialize(secret)
|
|
10
|
+
@secret = secret
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def sign(payload)
|
|
14
|
+
hmac = OpenSSL::HMAC.hexdigest(ALGORITHM, secret, payload)
|
|
15
|
+
"#{ALGORITHM}=#{hmac}"
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
4
19
|
class DeliverySpec
|
|
5
|
-
def initialize(event:, url:, content_type:, payload:)
|
|
20
|
+
def initialize(event:, url:, content_type:, payload:, secret:)
|
|
6
21
|
@event = event
|
|
7
22
|
@url = url
|
|
8
23
|
@content_type = content_type
|
|
9
24
|
@payload = payload
|
|
25
|
+
@secret = secret
|
|
10
26
|
end
|
|
11
27
|
|
|
12
28
|
def send!
|
|
@@ -15,7 +31,7 @@ module Shipit
|
|
|
15
31
|
|
|
16
32
|
private
|
|
17
33
|
|
|
18
|
-
attr_reader :event, :url, :content_type, :payload
|
|
34
|
+
attr_reader :event, :url, :content_type, :payload, :secret
|
|
19
35
|
|
|
20
36
|
def http
|
|
21
37
|
Faraday::Connection.new do |connection|
|
|
@@ -29,9 +45,16 @@ module Shipit
|
|
|
29
45
|
'User-Agent' => 'Shipit Webhook',
|
|
30
46
|
'Content-Type' => content_type,
|
|
31
47
|
'X-Shipit-Event' => event,
|
|
48
|
+
'X-Shipit-Signature' => signature,
|
|
32
49
|
'Accept' => '*/*',
|
|
33
50
|
}
|
|
34
51
|
end
|
|
52
|
+
|
|
53
|
+
def signature
|
|
54
|
+
return nil if secret.blank?
|
|
55
|
+
|
|
56
|
+
DeliverySigner.new(secret).sign(payload)
|
|
57
|
+
end
|
|
35
58
|
end
|
|
36
59
|
|
|
37
60
|
default_scope { order :id }
|
|
@@ -119,6 +142,7 @@ module Shipit
|
|
|
119
142
|
url: delivery_url,
|
|
120
143
|
content_type: CONTENT_TYPES[content_type],
|
|
121
144
|
payload: serialize_payload(payload),
|
|
145
|
+
secret: secret,
|
|
122
146
|
)
|
|
123
147
|
end
|
|
124
148
|
|
|
@@ -110,10 +110,11 @@ module Shipit
|
|
|
110
110
|
end
|
|
111
111
|
|
|
112
112
|
def self.extract_number(stack, number_or_url)
|
|
113
|
+
org = stack.repository.owner
|
|
113
114
|
case number_or_url
|
|
114
115
|
when /\A#?(\d+)\z/
|
|
115
116
|
$1.to_i
|
|
116
|
-
when %r{\Ahttps://#{Regexp.escape(Shipit.github.domain)}/([^/]+)/([^/]+)/pull/(\d+)}
|
|
117
|
+
when %r{\Ahttps://#{Regexp.escape(Shipit.github(organization: org).domain)}/([^/]+)/([^/]+)/pull/(\d+)}
|
|
117
118
|
return unless $1.downcase == stack.repo_owner.downcase
|
|
118
119
|
return unless $2.downcase == stack.repo_name.downcase
|
|
119
120
|
$3.to_i
|
|
@@ -161,7 +162,7 @@ module Shipit
|
|
|
161
162
|
|
|
162
163
|
raise NotReady if not_mergeable_yet?
|
|
163
164
|
|
|
164
|
-
|
|
165
|
+
stack.github_api.merge_pull_request(
|
|
165
166
|
stack.github_repo_name,
|
|
166
167
|
number,
|
|
167
168
|
merge_message,
|
|
@@ -170,8 +171,8 @@ module Shipit
|
|
|
170
171
|
merge_method: stack.merge_method,
|
|
171
172
|
)
|
|
172
173
|
begin
|
|
173
|
-
if
|
|
174
|
-
|
|
174
|
+
if stack.github_api.pull_requests(stack.github_repo_name, base: branch).empty?
|
|
175
|
+
stack.github_api.delete_branch(stack.github_repo_name, branch)
|
|
175
176
|
end
|
|
176
177
|
rescue Octokit::UnprocessableEntity
|
|
177
178
|
# branch was already deleted somehow
|
|
@@ -230,8 +231,9 @@ module Shipit
|
|
|
230
231
|
end
|
|
231
232
|
|
|
232
233
|
def refresh!
|
|
233
|
-
update!(github_pull_request:
|
|
234
|
+
update!(github_pull_request: stack.github_api.pull_request(stack.github_repo_name, number))
|
|
234
235
|
head.refresh_statuses!
|
|
236
|
+
head.refresh_check_runs!
|
|
235
237
|
fetched! if fetching?
|
|
236
238
|
@comparison = nil
|
|
237
239
|
end
|
|
@@ -269,7 +271,7 @@ module Shipit
|
|
|
269
271
|
end
|
|
270
272
|
|
|
271
273
|
def comparison
|
|
272
|
-
@comparison ||=
|
|
274
|
+
@comparison ||= stack.github_api.compare(
|
|
273
275
|
stack.github_repo_name,
|
|
274
276
|
base_ref,
|
|
275
277
|
head.sha,
|
|
@@ -292,7 +294,7 @@ module Shipit
|
|
|
292
294
|
if commit = stack.commits.by_sha(sha)
|
|
293
295
|
commit
|
|
294
296
|
else
|
|
295
|
-
github_commit =
|
|
297
|
+
github_commit = stack.github_api.commit(stack.github_repo_name, sha)
|
|
296
298
|
stack.commits.create_from_github!(github_commit, attributes)
|
|
297
299
|
end
|
|
298
300
|
rescue ActiveRecord::RecordNotUnique
|
|
@@ -53,7 +53,7 @@ module Shipit
|
|
|
53
53
|
if commit = stack.commits.by_sha(sha)
|
|
54
54
|
commit
|
|
55
55
|
else
|
|
56
|
-
github_commit =
|
|
56
|
+
github_commit = stack.github_api.commit(stack.github_repo_name, sha)
|
|
57
57
|
stack.commits.create_from_github!(github_commit)
|
|
58
58
|
end
|
|
59
59
|
rescue ActiveRecord::RecordNotUnique
|
|
@@ -38,7 +38,7 @@ module Shipit
|
|
|
38
38
|
private_constant :NAME_MAX_SIZE
|
|
39
39
|
|
|
40
40
|
validates :name, uniqueness: { scope: %i(owner), case_sensitive: false,
|
|
41
|
-
message: 'cannot be used more than once' }
|
|
41
|
+
message: 'cannot be used more than once', }
|
|
42
42
|
validates :owner, :name, presence: true, ascii_only: true
|
|
43
43
|
validates :owner, format: { with: /\A[a-z0-9_\-\.]+\z/ }, length: { maximum: OWNER_MAX_SIZE }
|
|
44
44
|
validates :name, format: { with: /\A[a-z0-9_\-\.]+\z/ }, length: { maximum: NAME_MAX_SIZE }
|
|
@@ -67,7 +67,7 @@ module Shipit
|
|
|
67
67
|
end
|
|
68
68
|
|
|
69
69
|
def http_url
|
|
70
|
-
|
|
70
|
+
github_app.url(full_name)
|
|
71
71
|
end
|
|
72
72
|
|
|
73
73
|
def full_name
|
|
@@ -75,7 +75,7 @@ module Shipit
|
|
|
75
75
|
end
|
|
76
76
|
|
|
77
77
|
def git_url
|
|
78
|
-
"https://#{
|
|
78
|
+
"https://#{github_app.domain}/#{owner}/#{name}.git"
|
|
79
79
|
end
|
|
80
80
|
|
|
81
81
|
def schedule_for_destroy!
|
|
@@ -93,5 +93,11 @@ module Shipit
|
|
|
93
93
|
name: repo_name.downcase,
|
|
94
94
|
).first!
|
|
95
95
|
end
|
|
96
|
+
|
|
97
|
+
protected
|
|
98
|
+
|
|
99
|
+
def github_app
|
|
100
|
+
Shipit.github(organization: owner)
|
|
101
|
+
end
|
|
96
102
|
end
|
|
97
103
|
end
|
|
@@ -7,8 +7,8 @@ module Shipit
|
|
|
7
7
|
"archived_since > :earliest AND archived_since < :latest",
|
|
8
8
|
earliest: 1.day.ago,
|
|
9
9
|
latest: 1.hour.ago
|
|
10
|
-
).
|
|
11
|
-
|
|
10
|
+
).find_each do |review_stack|
|
|
11
|
+
review_stack.clear_local_files
|
|
12
12
|
end
|
|
13
13
|
end
|
|
14
14
|
|
|
@@ -22,6 +22,20 @@ module Shipit
|
|
|
22
22
|
end
|
|
23
23
|
end
|
|
24
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
|
+
|
|
25
39
|
has_one :pull_request, foreign_key: :stack_id
|
|
26
40
|
|
|
27
41
|
after_commit :emit_added_hooks, on: :create
|
data/app/models/shipit/stack.rb
CHANGED
|
@@ -32,9 +32,9 @@ module Shipit
|
|
|
32
32
|
has_many :deploys
|
|
33
33
|
has_many :rollbacks
|
|
34
34
|
has_many :deploys_and_rollbacks,
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
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
|
|
@@ -83,13 +83,21 @@ module Shipit
|
|
|
83
83
|
after_commit :emit_merge_status_hooks, on: :update
|
|
84
84
|
after_commit :sync_github, on: :create
|
|
85
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
|
|
86
93
|
|
|
87
94
|
validates :repository, uniqueness: {
|
|
88
95
|
scope: %i(environment), case_sensitive: false,
|
|
89
|
-
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.',
|
|
90
97
|
}
|
|
91
98
|
validates :environment, format: { with: /\A[a-z0-9\-_\:]+\z/ }, length: { maximum: ENVIRONMENT_MAX_SIZE }
|
|
92
99
|
validates :deploy_url, format: { with: URI.regexp(%w(http https ssh)) }, allow_blank: true
|
|
100
|
+
validates :branch, presence: true
|
|
93
101
|
|
|
94
102
|
validates :lock_reason, length: { maximum: 4096 }
|
|
95
103
|
|
|
@@ -184,7 +192,7 @@ module Shipit
|
|
|
184
192
|
end
|
|
185
193
|
|
|
186
194
|
def continuous_delivery_delayed?
|
|
187
|
-
continuous_delivery_delayed_since? && continuous_deployment? && checks?
|
|
195
|
+
continuous_delivery_delayed_since? && continuous_deployment? && (checks? || deployment_checks?)
|
|
188
196
|
end
|
|
189
197
|
|
|
190
198
|
def continuous_delivery_delayed!
|
|
@@ -353,7 +361,7 @@ module Shipit
|
|
|
353
361
|
end
|
|
354
362
|
|
|
355
363
|
def deployable?
|
|
356
|
-
!locked? && !active_task? && !awaiting_provision?
|
|
364
|
+
!locked? && !active_task? && !awaiting_provision? && deployment_checks_passed?
|
|
357
365
|
end
|
|
358
366
|
|
|
359
367
|
def allows_merges?
|
|
@@ -372,26 +380,27 @@ module Shipit
|
|
|
372
380
|
delegate :git_url, to: :repository, prefix: :repo
|
|
373
381
|
|
|
374
382
|
def base_path
|
|
375
|
-
Rails.root.join('data', 'stacks', repo_owner, repo_name, environment)
|
|
383
|
+
@base_path ||= Rails.root.join('data', 'stacks', repo_owner, repo_name, environment)
|
|
376
384
|
end
|
|
377
385
|
|
|
378
386
|
def deploys_path
|
|
379
|
-
|
|
387
|
+
@deploys_path ||= base_path.join("deploys")
|
|
380
388
|
end
|
|
381
389
|
|
|
382
390
|
def git_path
|
|
383
|
-
|
|
391
|
+
@git_path ||= base_path.join("git")
|
|
384
392
|
end
|
|
385
393
|
|
|
386
394
|
def acquire_git_cache_lock(timeout: 15, &block)
|
|
387
|
-
Flock.new(git_path.to_s + '.lock')
|
|
395
|
+
@git_cache_lock ||= Flock.new(git_path.to_s + '.lock')
|
|
396
|
+
@git_cache_lock.lock(timeout: timeout, &block)
|
|
388
397
|
end
|
|
389
398
|
|
|
390
399
|
def clear_git_cache!
|
|
391
400
|
tmp_path = "#{git_path}-#{SecureRandom.hex}"
|
|
392
|
-
return unless
|
|
401
|
+
return unless git_path.exist?
|
|
393
402
|
acquire_git_cache_lock do
|
|
394
|
-
|
|
403
|
+
git_path.rename(tmp_path)
|
|
395
404
|
end
|
|
396
405
|
FileUtils.rm_rf(tmp_path)
|
|
397
406
|
end
|
|
@@ -402,12 +411,20 @@ module Shipit
|
|
|
402
411
|
|
|
403
412
|
def github_commits
|
|
404
413
|
handle_github_redirections do
|
|
405
|
-
|
|
414
|
+
github_api.commits(github_repo_name, sha: branch)
|
|
406
415
|
end
|
|
407
416
|
rescue Octokit::Conflict
|
|
408
417
|
[] # Repository is empty...
|
|
409
418
|
end
|
|
410
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
|
+
|
|
411
428
|
def handle_github_redirections
|
|
412
429
|
# https://developer.github.com/v3/#http-redirects
|
|
413
430
|
resource = yield
|
|
@@ -420,9 +437,9 @@ module Shipit
|
|
|
420
437
|
end
|
|
421
438
|
|
|
422
439
|
def refresh_repository!
|
|
423
|
-
resource =
|
|
440
|
+
resource = github_api.repo(github_repo_name)
|
|
424
441
|
if resource.try(:message) == 'Moved Permanently'
|
|
425
|
-
resource =
|
|
442
|
+
resource = github_api.get(resource.url)
|
|
426
443
|
end
|
|
427
444
|
repository.update!(owner: resource.owner.login, name: resource.name)
|
|
428
445
|
end
|
|
@@ -487,9 +504,9 @@ module Shipit
|
|
|
487
504
|
end
|
|
488
505
|
|
|
489
506
|
delegate :plugins, :task_definitions, :hidden_statuses, :required_statuses, :soft_failing_statuses,
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
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
|
|
493
510
|
|
|
494
511
|
def monitoring?
|
|
495
512
|
monitoring.present?
|
|
@@ -581,19 +598,31 @@ module Shipit
|
|
|
581
598
|
links_spec.transform_values { |url| context.interpolate(url) }
|
|
582
599
|
end
|
|
583
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
|
+
|
|
584
611
|
private
|
|
585
612
|
|
|
586
613
|
def clear_cache
|
|
587
614
|
remove_instance_variable(:@active_task) if defined?(@active_task)
|
|
588
615
|
end
|
|
589
616
|
|
|
590
|
-
def clear_local_files
|
|
591
|
-
FileUtils.rm_rf(base_path.to_s)
|
|
592
|
-
end
|
|
593
|
-
|
|
594
617
|
def update_defaults
|
|
595
618
|
self.environment = 'production' if environment.blank?
|
|
596
|
-
self.branch =
|
|
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
|
|
597
626
|
end
|
|
598
627
|
|
|
599
628
|
def set_locked_since
|
|
@@ -607,7 +636,7 @@ module Shipit
|
|
|
607
636
|
end
|
|
608
637
|
|
|
609
638
|
def schedule_merges_if_necessary
|
|
610
|
-
if
|
|
639
|
+
if lock_reason_previously_changed? && lock_reason.blank?
|
|
611
640
|
schedule_merges
|
|
612
641
|
end
|
|
613
642
|
end
|
|
@@ -644,7 +673,7 @@ module Shipit
|
|
|
644
673
|
end
|
|
645
674
|
|
|
646
675
|
def should_resume_continuous_delivery?(commit)
|
|
647
|
-
!deployable? ||
|
|
676
|
+
(deployment_checks_passed? && !deployable?) ||
|
|
648
677
|
deployed_too_recently? ||
|
|
649
678
|
commit.nil? ||
|
|
650
679
|
commit.deployed?
|
|
@@ -653,7 +682,12 @@ module Shipit
|
|
|
653
682
|
def should_delay_continuous_delivery?(commit)
|
|
654
683
|
commit.deploy_failed? ||
|
|
655
684
|
(checks? && !EphemeralCommitChecks.new(commit).run.success?) ||
|
|
685
|
+
!deployment_checks_passed? ||
|
|
656
686
|
commit.recently_pushed?
|
|
657
687
|
end
|
|
688
|
+
|
|
689
|
+
def deployment_checks?
|
|
690
|
+
Shipit.deployment_checks.present?
|
|
691
|
+
end
|
|
658
692
|
end
|
|
659
693
|
end
|