shipit-engine 0.20.1 → 0.21.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 +5 -5
- data/README.md +43 -6
- data/app/assets/stylesheets/_base/_base.scss +4 -0
- data/app/assets/stylesheets/_pages/_commits.scss +3 -1
- data/app/assets/stylesheets/_pages/_deploy.scss +4 -2
- data/app/controllers/concerns/shipit/authentication.rb +1 -1
- data/app/controllers/shipit/api/base_controller.rb +6 -1
- data/app/controllers/shipit/api/pull_requests_controller.rb +1 -1
- data/app/controllers/shipit/commit_checks_controller.rb +1 -1
- data/app/controllers/shipit/shipit_controller.rb +1 -5
- data/app/controllers/shipit/stacks_controller.rb +2 -0
- data/app/controllers/shipit/tasks_controller.rb +1 -1
- data/app/controllers/shipit/webhooks_controller.rb +2 -2
- data/app/helpers/shipit/deploys_helper.rb +9 -0
- data/app/helpers/shipit/shipit_helper.rb +17 -15
- data/app/helpers/shipit/stacks_helper.rb +6 -1
- data/app/jobs/shipit/destroy_stack_job.rb +4 -2
- data/app/jobs/shipit/fetch_deployed_revision_job.rb +1 -1
- data/app/jobs/shipit/github_sync_job.rb +1 -1
- data/app/jobs/shipit/merge_pull_requests_job.rb +3 -3
- data/app/jobs/shipit/perform_task_job.rb +3 -0
- data/app/jobs/shipit/purge_old_deliveries_job.rb +1 -0
- data/app/models/shipit/api_client.rb +1 -1
- data/app/models/shipit/commit.rb +29 -6
- data/app/models/shipit/commit_deployment.rb +1 -1
- data/app/models/shipit/commit_deployment_status.rb +1 -1
- data/app/models/shipit/deploy_spec.rb +19 -2
- data/app/models/shipit/deploy_spec/bundler_discovery.rb +1 -10
- data/app/models/shipit/deploy_spec/file_system.rb +6 -0
- data/app/models/shipit/deploy_spec/kubernetes_discovery.rb +1 -1
- data/app/models/shipit/deploy_spec/lerna_discovery.rb +85 -0
- data/app/models/shipit/deploy_spec/npm_discovery.rb +103 -5
- data/app/models/shipit/deploy_spec/pypi_discovery.rb +4 -2
- data/app/models/shipit/deploy_spec/rubygems_discovery.rb +4 -2
- data/app/models/shipit/duration.rb +1 -1
- data/app/models/shipit/github_status.rb +1 -1
- data/app/models/shipit/hook.rb +4 -5
- data/app/models/shipit/output_chunk.rb +1 -1
- data/app/models/shipit/pull_request.rb +36 -15
- data/app/models/shipit/stack.rb +15 -9
- data/app/models/shipit/status/common.rb +4 -0
- data/app/models/shipit/status/group.rb +4 -0
- data/app/models/shipit/task.rb +20 -8
- data/app/models/shipit/task_definition.rb +2 -2
- data/app/models/shipit/undeployed_commit.rb +13 -2
- data/app/models/shipit/user.rb +1 -1
- data/app/serializers/shipit/pull_request_serializer.rb +1 -1
- data/app/serializers/shipit/tail_task_serializer.rb +1 -1
- data/app/views/shipit/ccmenu/project.xml.builder +9 -8
- data/app/views/shipit/deploys/_deploy.html.erb +3 -2
- data/app/views/shipit/stacks/_banners.html.erb +4 -1
- data/app/views/shipit/stacks/settings.html.erb +4 -0
- data/app/views/shipit/statuses/_group.html.erb +1 -1
- data/app/views/shipit/statuses/_status.html.erb +1 -1
- data/app/views/shipit/tasks/_task.html.erb +1 -2
- data/config/locales/en.yml +2 -0
- data/config/secrets.development.example.yml +0 -4
- data/config/secrets.development.shopify.yml +1 -5
- data/db/migrate/20170904103242_reindex_deliveries.rb +7 -0
- data/db/migrate/20171120161420_add_base_info_to_pull_request.rb +7 -0
- data/db/migrate/20180202220850_add_aborted_by_to_tasks.rb +5 -0
- data/lib/shipit.rb +15 -23
- data/lib/shipit/command.rb +11 -3
- data/lib/shipit/engine.rb +0 -4
- data/lib/shipit/stack_commands.rb +3 -1
- data/lib/shipit/version.rb +1 -1
- data/lib/snippets/assert-lerna-fixed-version-tag +21 -0
- data/lib/snippets/assert-lerna-independent-version-tags +28 -0
- data/lib/snippets/generate-local-npmrc +19 -0
- data/lib/snippets/misconfigured-npm-publish-config +8 -0
- data/lib/snippets/publish-lerna-independent-packages +39 -0
- data/lib/snippets/push-to-heroku +5 -5
- data/lib/tasks/cron.rake +1 -1
- data/lib/tasks/dev.rake +1 -1
- data/test/controllers/api/deploys_controller_test.rb +19 -0
- data/test/controllers/api/stacks_controller_test.rb +1 -1
- data/test/controllers/github_authentication_controller_test.rb +1 -1
- data/test/controllers/stacks_controller_test.rb +10 -0
- data/test/controllers/tasks_controller_test.rb +2 -0
- data/test/controllers/webhooks_controller_test.rb +0 -7
- data/test/dummy/config/secrets.yml +0 -2
- data/test/dummy/db/development.sqlite3 +0 -0
- data/test/dummy/db/schema.rb +5 -3
- data/test/dummy/db/test.sqlite3 +0 -0
- data/test/fixtures/shipit/commits.yml +53 -0
- data/test/fixtures/shipit/pull_requests.yml +52 -0
- data/test/fixtures/shipit/stacks.yml +35 -0
- data/test/fixtures/shipit/statuses.yml +27 -0
- data/test/fixtures/shipit/tasks.yml +14 -0
- data/test/helpers/queries_helper.rb +1 -1
- data/test/jobs/merge_pull_requests_job_test.rb +19 -2
- data/test/jobs/perform_task_job_test.rb +26 -2
- data/test/models/commits_test.rb +55 -6
- data/test/models/deploy_spec_test.rb +288 -52
- data/test/models/deploys_test.rb +7 -7
- data/test/models/hook_test.rb +4 -3
- data/test/models/pull_request_test.rb +78 -24
- data/test/models/stacks_test.rb +21 -17
- data/test/models/status/group_test.rb +6 -0
- data/test/models/undeployed_commits_test.rb +9 -0
- data/test/models/users_test.rb +2 -2
- data/test/test_helper.rb +1 -1
- metadata +211 -222
- data/app/assets/javascripts/shipit_bs.js.coffee +0 -2
- data/app/assets/stylesheets/shipit_bs.scss +0 -22
- data/app/views/bootstrap/shipit/missing_settings.html.erb +0 -97
- data/app/views/bootstrap/shipit/stacks/new.html.erb +0 -44
- data/app/views/layouts/shipit_bootstrap.html.erb +0 -44
- data/lib/shipit/template_renderer_extension.rb +0 -16
|
@@ -22,7 +22,7 @@ module Shipit
|
|
|
22
22
|
|
|
23
23
|
response = begin
|
|
24
24
|
create_deployment_on_github(author.github_api)
|
|
25
|
-
rescue Octokit::
|
|
25
|
+
rescue Octokit::ClientError
|
|
26
26
|
raise if Shipit.github_api == author.github_api
|
|
27
27
|
# If the deploy author didn't gave us the permission to create the deployment we falback the the main shipit
|
|
28
28
|
# user.
|
|
@@ -10,7 +10,7 @@ module Shipit
|
|
|
10
10
|
return if github_id?
|
|
11
11
|
response = begin
|
|
12
12
|
create_status_on_github(author.github_api)
|
|
13
|
-
rescue Octokit::
|
|
13
|
+
rescue Octokit::ClientError
|
|
14
14
|
raise if Shipit.github_api == author.github_api
|
|
15
15
|
# If the deploy author didn't gave us the permission to create the deployment we falback the the main shipit
|
|
16
16
|
# user.
|
|
@@ -15,7 +15,7 @@ module Shipit
|
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
def bundle_path
|
|
18
|
-
Rails.root.join('data
|
|
18
|
+
Rails.root.join('data', 'bundler')
|
|
19
19
|
end
|
|
20
20
|
end
|
|
21
21
|
|
|
@@ -135,13 +135,17 @@ module Shipit
|
|
|
135
135
|
end
|
|
136
136
|
|
|
137
137
|
def required_statuses
|
|
138
|
-
Array.wrap(config('ci', 'require'))
|
|
138
|
+
(Array.wrap(config('ci', 'require')) + blocking_statuses).uniq
|
|
139
139
|
end
|
|
140
140
|
|
|
141
141
|
def soft_failing_statuses
|
|
142
142
|
Array.wrap(config('ci', 'allow_failures'))
|
|
143
143
|
end
|
|
144
144
|
|
|
145
|
+
def blocking_statuses
|
|
146
|
+
Array.wrap(config('ci', 'blocking'))
|
|
147
|
+
end
|
|
148
|
+
|
|
145
149
|
def pull_request_required_statuses
|
|
146
150
|
if config('merge', 'require') || config('merge', 'ignore')
|
|
147
151
|
Array.wrap(config('merge', 'require'))
|
|
@@ -167,6 +171,19 @@ module Shipit
|
|
|
167
171
|
end
|
|
168
172
|
end
|
|
169
173
|
|
|
174
|
+
def max_divergence_commits
|
|
175
|
+
config('merge', 'max_divergence', 'commits')
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def max_divergence_age
|
|
179
|
+
if timeout = config('merge', 'max_divergence', 'age')
|
|
180
|
+
begin
|
|
181
|
+
Duration.parse(timeout)
|
|
182
|
+
rescue Duration::ParseError
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
|
|
170
187
|
def review_checks
|
|
171
188
|
config('review', 'checks') || []
|
|
172
189
|
end
|
|
@@ -54,16 +54,7 @@ module Shipit
|
|
|
54
54
|
end
|
|
55
55
|
|
|
56
56
|
def coerce_task_definition(config)
|
|
57
|
-
|
|
58
|
-
should_prepend_bundle_exec?(command) ? bundle_exec(command) : command
|
|
59
|
-
end
|
|
60
|
-
config.merge('steps' => coerced_steps)
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
private
|
|
64
|
-
|
|
65
|
-
def should_prepend_bundle_exec?(command)
|
|
66
|
-
Shipit.automatically_prepend_bundle_exec && !command.start_with?('bundle exec')
|
|
57
|
+
config.merge('steps' => Array(config['steps']))
|
|
67
58
|
end
|
|
68
59
|
end
|
|
69
60
|
end
|
|
@@ -2,6 +2,7 @@ module Shipit
|
|
|
2
2
|
class DeploySpec
|
|
3
3
|
class FileSystem < DeploySpec
|
|
4
4
|
include NpmDiscovery
|
|
5
|
+
include LernaDiscovery
|
|
5
6
|
include PypiDiscovery
|
|
6
7
|
include RubygemsDiscovery
|
|
7
8
|
include CapistranoDiscovery
|
|
@@ -33,11 +34,16 @@ module Shipit
|
|
|
33
34
|
'require' => pull_request_required_statuses,
|
|
34
35
|
'ignore' => pull_request_ignored_statuses,
|
|
35
36
|
'revalidate_after' => revalidate_pull_requests_after.try!(:to_i),
|
|
37
|
+
'max_divergence' => {
|
|
38
|
+
'commits' => max_divergence_commits.try!(:to_i),
|
|
39
|
+
'age' => max_divergence_age.try!(:to_i),
|
|
40
|
+
},
|
|
36
41
|
},
|
|
37
42
|
'ci' => {
|
|
38
43
|
'hide' => hidden_statuses,
|
|
39
44
|
'allow_failures' => soft_failing_statuses,
|
|
40
45
|
'require' => required_statuses,
|
|
46
|
+
'blocking' => blocking_statuses,
|
|
41
47
|
},
|
|
42
48
|
'machine' => {
|
|
43
49
|
'environment' => discover_machine_env.merge(machine_env),
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
require 'json'
|
|
2
|
+
|
|
3
|
+
module Shipit
|
|
4
|
+
class DeploySpec
|
|
5
|
+
module LernaDiscovery
|
|
6
|
+
def discover_dependencies_steps
|
|
7
|
+
discover_lerna_json || super
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def discover_lerna_json
|
|
11
|
+
lerna_install if lerna?
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def lerna_install
|
|
15
|
+
[js_command('install --no-progress'), 'node_modules/.bin/lerna bootstrap']
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def discover_review_checklist
|
|
19
|
+
discover_lerna_checklist || super
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def discover_lerna_checklist
|
|
23
|
+
if lerna?
|
|
24
|
+
[%(
|
|
25
|
+
<strong>Don't forget version and tag before publishing!</strong>
|
|
26
|
+
You can do this with:<br/>
|
|
27
|
+
<pre>
|
|
28
|
+
lerna publish --skip-npm
|
|
29
|
+
&& git add -A
|
|
30
|
+
&& git push --follow-tags
|
|
31
|
+
</pre>
|
|
32
|
+
)]
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def lerna?
|
|
37
|
+
lerna_json.exist?
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def lerna_json
|
|
41
|
+
file('lerna.json')
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def lerna_version
|
|
45
|
+
lerna_config = lerna_json.read
|
|
46
|
+
JSON.parse(lerna_config)['version']
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def discover_lerna_packages
|
|
50
|
+
publish_lerna_packages if lerna?
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def discover_deploy_steps
|
|
54
|
+
discover_lerna_packages || super
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def publish_lerna_packages
|
|
58
|
+
return publish_independent_packages if lerna_version == 'independent'
|
|
59
|
+
publish_fixed_version_packages
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def publish_independent_packages
|
|
63
|
+
[
|
|
64
|
+
'assert-lerna-independent-version-tags',
|
|
65
|
+
'publish-lerna-independent-packages',
|
|
66
|
+
]
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def publish_fixed_version_packages
|
|
70
|
+
check_tags = 'assert-lerna-fixed-version-tag'
|
|
71
|
+
# `yarn publish` requires user input, so always use npm.
|
|
72
|
+
version = lerna_version
|
|
73
|
+
publish =
|
|
74
|
+
"node_modules/.bin/lerna publish " \
|
|
75
|
+
"--yes " \
|
|
76
|
+
"--skip-git " \
|
|
77
|
+
"--repo-version #{version} " \
|
|
78
|
+
"--force-publish=* " \
|
|
79
|
+
"--npm-tag #{dist_tag(version)}"
|
|
80
|
+
|
|
81
|
+
[check_tags, publish]
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
@@ -3,6 +3,12 @@ require 'json'
|
|
|
3
3
|
module Shipit
|
|
4
4
|
class DeploySpec
|
|
5
5
|
module NpmDiscovery
|
|
6
|
+
# https://docs.npmjs.com/cli/publish
|
|
7
|
+
PUBLIC = 'public'.freeze
|
|
8
|
+
PRIVATE = 'restricted'.freeze
|
|
9
|
+
VALID_ACCESS = [PUBLIC, PRIVATE].freeze
|
|
10
|
+
NPM_REGISTRY = "https://registry.npmjs.org/".freeze
|
|
11
|
+
|
|
6
12
|
def discover_dependencies_steps
|
|
7
13
|
discover_package_json || super
|
|
8
14
|
end
|
|
@@ -20,13 +26,19 @@ module Shipit
|
|
|
20
26
|
end
|
|
21
27
|
|
|
22
28
|
def discover_yarn_checklist
|
|
23
|
-
|
|
24
|
-
|
|
29
|
+
if yarn?
|
|
30
|
+
[%(<strong>Don't forget version and tag before publishing!</strong> You can do this with:<br/>
|
|
31
|
+
yarn version --new-version <strong><major|minor|patch></strong>
|
|
32
|
+
&& git push --follow-tags</pre>)]
|
|
33
|
+
end
|
|
25
34
|
end
|
|
26
35
|
|
|
27
36
|
def discover_npm_checklist
|
|
28
|
-
|
|
29
|
-
|
|
37
|
+
if npm?
|
|
38
|
+
[%(<strong>Don't forget version and tag before publishing!</strong> You can do this with:<br/>
|
|
39
|
+
npm version <strong><major|minor|patch></strong>
|
|
40
|
+
&& git push --follow-tags</pre>)]
|
|
41
|
+
end
|
|
30
42
|
end
|
|
31
43
|
|
|
32
44
|
def npm?
|
|
@@ -40,10 +52,23 @@ module Shipit
|
|
|
40
52
|
JSON.parse(file.read)['private'].blank?
|
|
41
53
|
end
|
|
42
54
|
|
|
55
|
+
def dist_tag(version)
|
|
56
|
+
# Pre-release SemVer tags such as 'beta', 'alpha', 'rc' and 'next'
|
|
57
|
+
# are treated as 'next' npm dist-tags.
|
|
58
|
+
# An 1.0.0-beta.1 would be installable using both:
|
|
59
|
+
# `yarn add package@1.0.0-beta.1` and `yarn add package@next`
|
|
60
|
+
return 'next' if ['-beta', '-alpha', '-rc', '-next'].any? { |tag| version.include? tag }
|
|
61
|
+
'latest'
|
|
62
|
+
end
|
|
63
|
+
|
|
43
64
|
def package_json
|
|
44
65
|
file('package.json')
|
|
45
66
|
end
|
|
46
67
|
|
|
68
|
+
def package_json_contents
|
|
69
|
+
@package_json_contents ||= JSON.parse(package_json.read)
|
|
70
|
+
end
|
|
71
|
+
|
|
47
72
|
def yarn?
|
|
48
73
|
yarn_lock.exist? && public?
|
|
49
74
|
end
|
|
@@ -60,11 +85,84 @@ module Shipit
|
|
|
60
85
|
discover_npm_package || super
|
|
61
86
|
end
|
|
62
87
|
|
|
88
|
+
def package_name
|
|
89
|
+
package_json_contents['name']
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def package_version
|
|
93
|
+
package_json_contents['version']
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def publish_config
|
|
97
|
+
package_json_contents['publishConfig']
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def publish_config_access
|
|
101
|
+
config = publish_config
|
|
102
|
+
|
|
103
|
+
# default to private deploy when we enforce a publishConfig
|
|
104
|
+
if enforce_publish_config?
|
|
105
|
+
return PRIVATE if config.blank?
|
|
106
|
+
config['access'] || PRIVATE
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
return PUBLIC if config.blank?
|
|
110
|
+
config['access'] || PUBLIC
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def scoped_package?
|
|
114
|
+
return false if Shipit.npm_org_scope.nil?
|
|
115
|
+
package_name.start_with?(Shipit.npm_org_scope)
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def enforce_publish_config?
|
|
119
|
+
enforce = Shipit.enforce_publish_config
|
|
120
|
+
return false if enforce.nil? || enforce.to_s == "0"
|
|
121
|
+
true
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def valid_publish_config?
|
|
125
|
+
return true unless enforce_publish_config?
|
|
126
|
+
return false if Shipit.private_npm_registry.nil?
|
|
127
|
+
return false if publish_config.blank?
|
|
128
|
+
return true if publish_config_access == PUBLIC
|
|
129
|
+
|
|
130
|
+
valid_publish_config_access? && private_scoped_package?
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def valid_publish_config_access?
|
|
134
|
+
VALID_ACCESS.include?(publish_config_access)
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# ensure private packages are scoped
|
|
138
|
+
def private_scoped_package?
|
|
139
|
+
publish_config_access == PRIVATE && scoped_package?
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def local_npmrc
|
|
143
|
+
file(".npmrc")
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def registry
|
|
147
|
+
scope = Shipit.npm_org_scope
|
|
148
|
+
prefix = scoped_package? ? "#{scope}:registry" : "registry"
|
|
149
|
+
|
|
150
|
+
if publish_config_access == PUBLIC
|
|
151
|
+
return "#{prefix}=#{NPM_REGISTRY}"
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
"#{prefix}=#{Shipit.private_npm_registry}"
|
|
155
|
+
end
|
|
156
|
+
|
|
63
157
|
def publish_npm_package
|
|
158
|
+
return ['misconfigured-npm-publish-config'] unless valid_publish_config?
|
|
159
|
+
|
|
160
|
+
generate_npmrc = "generate-local-npmrc \"#{registry}\""
|
|
64
161
|
check_tags = 'assert-npm-version-tag'
|
|
65
162
|
# `yarn publish` requires user input, so always use npm.
|
|
66
|
-
publish =
|
|
163
|
+
publish = "npm publish --tag #{dist_tag(package_version)} --access #{publish_config_access}"
|
|
67
164
|
|
|
165
|
+
return [check_tags, generate_npmrc, publish] if enforce_publish_config?
|
|
68
166
|
[check_tags, publish]
|
|
69
167
|
end
|
|
70
168
|
|
|
@@ -14,8 +14,10 @@ module Shipit
|
|
|
14
14
|
end
|
|
15
15
|
|
|
16
16
|
def discover_pypi_checklist
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
if egg?
|
|
18
|
+
[%(<strong>Don't forget to add a tag before deploying!</strong> You can do this with:
|
|
19
|
+
git tag -a -m "Version <strong>x.y.z</strong>" v<strong>x.y.z</strong> && git push --tags)]
|
|
20
|
+
end
|
|
19
21
|
end
|
|
20
22
|
|
|
21
23
|
def egg?
|
|
@@ -14,8 +14,10 @@ module Shipit
|
|
|
14
14
|
end
|
|
15
15
|
|
|
16
16
|
def discover_gem_checklist
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
if gem?
|
|
18
|
+
[%(<strong>Don't forget to add a tag before deploying!</strong> You can do this with:
|
|
19
|
+
git tag v<strong>x.y.z</strong> && git push --tags)]
|
|
20
|
+
end
|
|
19
21
|
end
|
|
20
22
|
|
|
21
23
|
def gem?
|
data/app/models/shipit/hook.rb
CHANGED
|
@@ -31,8 +31,8 @@ module Shipit
|
|
|
31
31
|
serialize :events, Shipit::CSVSerializer
|
|
32
32
|
|
|
33
33
|
scope :global, -> { where(stack_id: nil) }
|
|
34
|
-
scope :scoped_to, ->
|
|
35
|
-
scope :for_stack, ->
|
|
34
|
+
scope :scoped_to, ->(stack) { where(stack_id: stack.id) }
|
|
35
|
+
scope :for_stack, ->(stack_id) { where(stack_id: [nil, stack_id]) }
|
|
36
36
|
|
|
37
37
|
class << self
|
|
38
38
|
def emit(event, stack, payload)
|
|
@@ -80,9 +80,8 @@ module Shipit
|
|
|
80
80
|
end
|
|
81
81
|
|
|
82
82
|
def purge_old_deliveries!(keep: DELIVERIES_LOG_SIZE)
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
end
|
|
83
|
+
delivery_ids = deliveries.sent.order(id: :desc).offset(keep).pluck(:id)
|
|
84
|
+
deliveries.where(id: delivery_ids).delete_all
|
|
86
85
|
end
|
|
87
86
|
|
|
88
87
|
private
|
|
@@ -2,7 +2,7 @@ module Shipit
|
|
|
2
2
|
class OutputChunk < ActiveRecord::Base
|
|
3
3
|
belongs_to :task
|
|
4
4
|
|
|
5
|
-
scope :tail, ->
|
|
5
|
+
scope :tail, ->(start) { order(id: :asc).where('id > ?', start || 0) }
|
|
6
6
|
|
|
7
7
|
def text=(string)
|
|
8
8
|
super(string.force_encoding(Encoding::UTF_8).scrub)
|
|
@@ -4,7 +4,7 @@ module Shipit
|
|
|
4
4
|
|
|
5
5
|
WAITING_STATUSES = %w(fetching pending).freeze
|
|
6
6
|
QUEUED_STATUSES = %w(pending revalidating).freeze
|
|
7
|
-
REJECTION_REASONS = %w(ci_failing merge_conflict).freeze
|
|
7
|
+
REJECTION_REASONS = %w(ci_failing merge_conflict requires_rebase).freeze
|
|
8
8
|
InvalidTransition = Class.new(StandardError)
|
|
9
9
|
NotReady = Class.new(StandardError)
|
|
10
10
|
|
|
@@ -37,6 +37,7 @@ module Shipit
|
|
|
37
37
|
|
|
38
38
|
belongs_to :stack
|
|
39
39
|
belongs_to :head, class_name: 'Shipit::Commit', optional: true
|
|
40
|
+
belongs_to :base_commit, class_name: 'Shipit::Commit', optional: true
|
|
40
41
|
belongs_to :merge_requested_by, class_name: 'Shipit::User', optional: true
|
|
41
42
|
has_one :merge_commit, class_name: 'Shipit::Commit'
|
|
42
43
|
|
|
@@ -112,7 +113,7 @@ module Shipit
|
|
|
112
113
|
when %r{\Ahttps://#{Regexp.escape(Shipit.github_domain)}/([^/]+)/([^/]+)/pull/(\d+)}
|
|
113
114
|
return unless $1.downcase == stack.repo_owner.downcase
|
|
114
115
|
return unless $2.downcase == stack.repo_name.downcase
|
|
115
|
-
|
|
116
|
+
$3.to_i
|
|
116
117
|
end
|
|
117
118
|
end
|
|
118
119
|
|
|
@@ -146,7 +147,8 @@ module Shipit
|
|
|
146
147
|
|
|
147
148
|
def reject_unless_mergeable!
|
|
148
149
|
return reject!('merge_conflict') if merge_conflict?
|
|
149
|
-
return reject!('ci_failing')
|
|
150
|
+
return reject!('ci_failing') if any_status_checks_failed?
|
|
151
|
+
return reject!('requires_rebase') if stale?
|
|
150
152
|
false
|
|
151
153
|
end
|
|
152
154
|
|
|
@@ -154,10 +156,6 @@ module Shipit
|
|
|
154
156
|
raise InvalidTransition unless pending?
|
|
155
157
|
|
|
156
158
|
raise NotReady if not_mergeable_yet?
|
|
157
|
-
if need_revalidation?
|
|
158
|
-
revalidate!
|
|
159
|
-
return false
|
|
160
|
-
end
|
|
161
159
|
|
|
162
160
|
Shipit.github_api.merge_pull_request(
|
|
163
161
|
stack.github_repo_name,
|
|
@@ -184,9 +182,15 @@ module Shipit
|
|
|
184
182
|
end
|
|
185
183
|
|
|
186
184
|
def all_status_checks_passed?
|
|
185
|
+
return false unless head
|
|
187
186
|
StatusChecker.new(head, head.statuses, stack.cached_deploy_spec).success?
|
|
188
187
|
end
|
|
189
188
|
|
|
189
|
+
def any_status_checks_failed?
|
|
190
|
+
status = StatusChecker.new(head, head.statuses, stack.cached_deploy_spec)
|
|
191
|
+
status.failure? || status.error?
|
|
192
|
+
end
|
|
193
|
+
|
|
190
194
|
def waiting?
|
|
191
195
|
WAITING_STATUSES.include?(merge_status)
|
|
192
196
|
end
|
|
@@ -221,6 +225,7 @@ module Shipit
|
|
|
221
225
|
update!(github_pull_request: Shipit.github_api.pull_request(stack.github_repo_name, number))
|
|
222
226
|
head.refresh_statuses!
|
|
223
227
|
fetched! if fetching?
|
|
228
|
+
@comparison = nil
|
|
224
229
|
end
|
|
225
230
|
|
|
226
231
|
def github_pull_request=(github_pull_request)
|
|
@@ -234,6 +239,8 @@ module Shipit
|
|
|
234
239
|
self.branch = github_pull_request.head.ref
|
|
235
240
|
self.head = find_or_create_commit_from_github_by_sha!(github_pull_request.head.sha, detached: true)
|
|
236
241
|
self.merged_at = github_pull_request.merged_at
|
|
242
|
+
self.base_ref = github_pull_request.base.ref
|
|
243
|
+
self.base_commit = find_or_create_commit_from_github_by_sha!(github_pull_request.base.sha, detached: true)
|
|
237
244
|
end
|
|
238
245
|
|
|
239
246
|
def merge_message
|
|
@@ -241,16 +248,30 @@ module Shipit
|
|
|
241
248
|
"#{title}\n\nMerge-Requested-By: #{merge_requested_by.login}\n"
|
|
242
249
|
end
|
|
243
250
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
251
|
+
def stale?
|
|
252
|
+
return false unless base_commit
|
|
253
|
+
spec = stack.cached_deploy_spec
|
|
254
|
+
if max_branch_age = spec.max_divergence_age
|
|
255
|
+
return true if Time.now.utc - head.committed_at > max_branch_age
|
|
249
256
|
end
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
@merge_status_changed ||= merge_status_changed?
|
|
257
|
+
if commit_count_limit = spec.max_divergence_commits
|
|
258
|
+
return true if comparison.behind_by > commit_count_limit
|
|
253
259
|
end
|
|
260
|
+
false
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
def comparison
|
|
264
|
+
@comparison ||= Shipit.github_api.compare(
|
|
265
|
+
stack.github_repo_name,
|
|
266
|
+
base_ref,
|
|
267
|
+
head.sha,
|
|
268
|
+
)
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
private
|
|
272
|
+
|
|
273
|
+
def record_merge_status_change
|
|
274
|
+
@merge_status_changed ||= saved_change_to_attribute?(:merge_status)
|
|
254
275
|
end
|
|
255
276
|
|
|
256
277
|
def emit_hooks
|