shipit-engine 0.24.0 → 0.25.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/shipit/stacks.js.coffee +15 -1
  3. data/app/assets/stylesheets/_base/_icons.scss +18 -0
  4. data/app/assets/stylesheets/_base/_status-items.scss +28 -0
  5. data/app/assets/stylesheets/_pages/_commits.scss +1 -5
  6. data/app/assets/stylesheets/_pages/_deploy.scss +60 -3
  7. data/app/controllers/concerns/shipit/authentication.rb +1 -1
  8. data/app/controllers/shipit/merge_status_controller.rb +2 -0
  9. data/app/controllers/shipit/release_statuses_controller.rb +36 -0
  10. data/app/jobs/shipit/append_delayed_release_status_job.rb +17 -0
  11. data/app/jobs/shipit/cache_deploy_spec_job.rb +2 -0
  12. data/app/jobs/shipit/clear_git_cache_job.rb +1 -1
  13. data/app/jobs/shipit/create_release_statuses_job.rb +11 -0
  14. data/app/jobs/shipit/deferred_touch_job.rb +2 -0
  15. data/app/jobs/shipit/deliver_hook_job.rb +1 -0
  16. data/app/jobs/shipit/merge_pull_requests_job.rb +2 -0
  17. data/app/jobs/shipit/perform_commit_checks_job.rb +2 -0
  18. data/app/jobs/shipit/perform_task_job.rb +2 -4
  19. data/app/jobs/shipit/refresh_pull_request_job.rb +2 -0
  20. data/app/models/shipit/anonymous_user.rb +1 -1
  21. data/app/models/shipit/commit.rb +36 -3
  22. data/app/models/shipit/deploy.rb +43 -0
  23. data/app/models/shipit/deploy_spec.rb +16 -2
  24. data/app/models/shipit/deploy_spec/bundler_discovery.rb +5 -1
  25. data/app/models/shipit/deploy_spec/file_system.rb +4 -0
  26. data/app/models/shipit/deploy_spec/kubernetes_discovery.rb +1 -1
  27. data/app/models/shipit/ephemeral_commit_checks.rb +2 -4
  28. data/app/models/shipit/hook.rb +36 -3
  29. data/app/models/shipit/pull_request.rb +4 -2
  30. data/app/models/shipit/release_status.rb +41 -0
  31. data/app/models/shipit/rollback.rb +9 -0
  32. data/app/models/shipit/stack.rb +4 -9
  33. data/app/models/shipit/status/common.rb +4 -0
  34. data/app/models/shipit/status/group.rb +2 -1
  35. data/app/models/shipit/status/missing.rb +4 -0
  36. data/app/models/shipit/status/unknown.rb +15 -0
  37. data/app/models/shipit/task.rb +4 -0
  38. data/app/models/shipit/user.rb +16 -3
  39. data/app/serializers/shipit/stack_serializer.rb +1 -1
  40. data/app/views/shipit/deploys/_deploy.html.erb +18 -2
  41. data/config/locales/en.yml +3 -0
  42. data/config/routes.rb +2 -0
  43. data/db/migrate/20180802172632_allow_commit_without_author.rb +6 -0
  44. data/db/migrate/20180906083930_create_release_statuses.rb +21 -0
  45. data/lib/shipit.rb +5 -0
  46. data/lib/shipit/command.rb +14 -18
  47. data/lib/shipit/deploy_commands.rb +0 -4
  48. data/lib/shipit/engine.rb +1 -1
  49. data/lib/shipit/first_parent_commits_iterator.rb +1 -1
  50. data/lib/shipit/flock.rb +43 -0
  51. data/lib/shipit/github_app.rb +5 -3
  52. data/lib/shipit/rollback_commands.rb +6 -0
  53. data/lib/shipit/task_commands.rb +1 -5
  54. data/lib/shipit/version.rb +1 -1
  55. data/test/controllers/release_statuses_controller_test.rb +23 -0
  56. data/test/dummy/db/schema.rb +18 -3
  57. data/test/dummy/db/seeds.rb +4 -0
  58. data/test/fixtures/shipit/commits.yml +13 -0
  59. data/test/fixtures/shipit/release_statuses.yml +16 -0
  60. data/test/fixtures/shipit/stacks.yml +4 -0
  61. data/test/jobs/append_delayed_release_status_job_test.rb +25 -0
  62. data/test/jobs/cache_deploy_spec_job_test.rb +1 -2
  63. data/test/jobs/emit_event_job_test.rb +1 -1
  64. data/test/jobs/github_sync_job_test.rb +1 -0
  65. data/test/models/commits_test.rb +54 -1
  66. data/test/models/deploy_spec_test.rb +83 -11
  67. data/test/models/deploys_test.rb +52 -0
  68. data/test/models/hook_test.rb +1 -28
  69. data/test/models/pull_request_test.rb +19 -0
  70. data/test/models/release_statuses_test.rb +28 -0
  71. data/test/models/rollbacks_test.rb +2 -0
  72. data/test/models/stacks_test.rb +1 -1
  73. data/test/test_helper.rb +5 -0
  74. data/test/unit/rollback_commands_test.rb +35 -0
  75. metadata +121 -104
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ef8f9d577b2985bc9e82fd48bcb930c12261aef6
4
- data.tar.gz: 4bf4282862504a06c96b5563750dc8d742e8c7ef
3
+ metadata.gz: 71f403cb4167fb521f7a2c190e2d31504dc0dea8
4
+ data.tar.gz: e1b1a94eefcc449a882ced01fa8036cd9df8e072
5
5
  SHA512:
6
- metadata.gz: 15cc3525496d566cc27b67cefde82a3833f2bac1801a026b3de73c59a2208dc43c6b563b231da39d61eab6d1cf97c9f959515db5e873f7e16c2dfa5021732703
7
- data.tar.gz: ec850e528fa5625ec20c3ebe81418381876e46ac2016ca55651284e3cabe58a641d29e304532290a096ca1e0237064308d1f8495537fc3ed278cf9e16a49c46a
6
+ metadata.gz: 0a04e776ddb132ab89a89b80ba5f5a78dfb69a53e73e7300b495e38deaa947cf6c69a6fd3b14dd9ca769ed5aa5d18c47d41a6e3a79de6f02ce2655f3cf305293
7
+ data.tar.gz: 5e71eaea76929fb232b98197018bc029e32d1f8b4d7743b775c72a6c549082fc0bdc7d212f930d66d657322f7fc15a2b0d736ee519bab026ecc18c16f0ae756a
@@ -1,4 +1,6 @@
1
- $(document).on 'click', '.commit-lock a', (event) ->
1
+ $document = $(document)
2
+
3
+ $document.on 'click', '.commit-lock a', (event) ->
2
4
  event.preventDefault()
3
5
  $commit = $(event.target).closest('.commit')
4
6
  $link = $(event.target).closest('a')
@@ -8,6 +10,18 @@ $(document).on 'click', '.commit-lock a', (event) ->
8
10
 
9
11
  $.ajax($link.attr('href'), method: 'PATCH', data: {commit: {locked: !locked}})
10
12
 
13
+ $document.on 'click', '.action-set-release-status', (event) ->
14
+ event.preventDefault()
15
+ $link = $(event.target).closest('a')
16
+ $deploy = $link.closest('.deploy')
17
+ newStatus = $link.data('status')
18
+
19
+ return if $deploy.attr('data-release-status') == newStatus
20
+
21
+ $.ajax($link.attr('href'), method: 'POST', data: {status: newStatus}).success((last_status) ->
22
+ $deploy.attr('data-release-status', last_status.state)
23
+ )
24
+
11
25
  jQuery ($) ->
12
26
  displayIgnoreCiMessage = ->
13
27
  ignoreCiMessage = $(".ignoring-ci")
@@ -6,3 +6,21 @@
6
6
  height: 15px;
7
7
  width: 12px;
8
8
  }
9
+
10
+ .icon--validate {
11
+ display: inline-block;
12
+ background-color: #000;
13
+ mask: asset-data-url("success-small.svg") no-repeat 50% 50%;
14
+ // background: asset-data-url("lock.svg") center center no-repeat;
15
+ height: 15px;
16
+ width: 12px;
17
+ }
18
+
19
+ .icon--reject {
20
+ display: inline-block;
21
+ background-color: #000;
22
+ mask: asset-data-url("error-small.svg") no-repeat 50% 50%;
23
+ // background: asset-data-url("lock.svg") center center no-repeat;
24
+ height: 15px;
25
+ width: 12px;
26
+ }
@@ -136,3 +136,31 @@
136
136
  background-image: asset-data-url('failure-small.svg');
137
137
  }
138
138
  }
139
+
140
+ // DEPLOY STATUS ICON
141
+ // -----------------------------------------------------------------------------
142
+
143
+ .deploy-status__icon {
144
+ width: 12px;
145
+ height: 12px;
146
+ display: inline-block;
147
+ background: transparent no-repeat center center;
148
+ vertical-align: -2px;
149
+
150
+ .deploy[data-release-status=success] & {
151
+ background-image: asset-data-url('success-small.svg');
152
+ }
153
+
154
+ .deploy[data-release-status=pending] &,
155
+ .deploy[data-release-status=unknown] & {
156
+ background-image: asset-data-url('pending-small.svg');
157
+ }
158
+
159
+ .deploy[data-release-status=error] & {
160
+ background-image: asset-data-url('error-small.svg');
161
+ }
162
+
163
+ .deploy[data-release-status=failure] & {
164
+ background-image: asset-data-url('failure-small.svg');
165
+ }
166
+ }
@@ -136,10 +136,6 @@
136
136
  color: $grey;
137
137
  margin: 0;
138
138
 
139
- @include media(desktop) {
140
- @include truncate;
141
- }
142
-
143
139
  .warning {
144
140
  color: $orange;
145
141
  }
@@ -166,7 +162,7 @@
166
162
 
167
163
  @include media(desktop) {
168
164
  margin-left: 1rem;
169
- min-width: 10rem;
165
+ min-width: 12rem;
170
166
 
171
167
  .btn {
172
168
  float: right;
@@ -35,7 +35,11 @@
35
35
  margin: 0 0.5rem;
36
36
 
37
37
  display: none;
38
- &[data-status="running"], &[data-status="aborting"] { display: inline-block; }
38
+ &[data-status="running"],
39
+ &[data-status="aborting"],
40
+ &[data-status="pending"] {
41
+ display: inline-block;
42
+ }
39
43
 
40
44
  .caption--pending {
41
45
  display: none;
@@ -114,6 +118,7 @@
114
118
  width: 100%;
115
119
  }
116
120
 
121
+ &[data-status="pending"] .deploy-banner-status,
117
122
  &[data-status="running"] .deploy-banner-status {
118
123
  background-color: $blue;
119
124
  width: 0%;
@@ -202,7 +207,7 @@
202
207
  border-color: $bright-red;
203
208
  }
204
209
 
205
- &[data-status="scheduled"],
210
+ &[data-status="pending"],
206
211
  &[data-status="running"] {
207
212
  border-color: $dark-yellow;
208
213
  }
@@ -217,4 +222,56 @@
217
222
 
218
223
  .ignored-safeties {
219
224
  color: $orange;
220
- }
225
+ }
226
+
227
+ .deploy-actions {
228
+ flex-shrink: 0;
229
+
230
+ @include media(desktop) {
231
+ margin-left: 1rem;
232
+ min-width: 12rem;
233
+
234
+ .btn {
235
+ float: right;
236
+ }
237
+ }
238
+ }
239
+
240
+ .release-validation {
241
+ display: inline-block;
242
+ .icon {
243
+ background-color: #ddd;
244
+ }
245
+
246
+ &:hover .icon {
247
+ background-color: darken(#ddd, 20%);
248
+ }
249
+ }
250
+
251
+ .deploy[data-release-status="success"] .release-validation .action-validate-release,
252
+ .deploy[data-release-status="failure"] .release-validation .action-reject-release {
253
+ &:before, &:after {
254
+ display: none; // Hide tooltips
255
+ }
256
+ .icon {
257
+ background-color: #ddd;
258
+ }
259
+ }
260
+
261
+ .deploy .commit-lock {
262
+ .icon {
263
+ background-color: $bright-red;
264
+ }
265
+
266
+ &:hover .icon {
267
+ background-color: darken($bright-red, 20%);
268
+ }
269
+
270
+ .action-lock-commit {
271
+ display: none;
272
+ }
273
+
274
+ .action-unlock-commit {
275
+ display: inline-block;
276
+ }
277
+ }
@@ -16,7 +16,7 @@ module Shipit
16
16
  private
17
17
 
18
18
  def force_github_authentication
19
- if current_user.logged_in?
19
+ if Shipit.authentication_disabled? || current_user.logged_in?
20
20
  unless current_user.authorized?
21
21
  team_handles = Shipit.github_teams.map(&:handle)
22
22
  team_list = team_handles.to_sentence(two_words_connector: ' or ', last_word_connector: ', or ')
@@ -17,6 +17,8 @@ module Shipit
17
17
  else
18
18
  render html: ''
19
19
  end
20
+ rescue ArgumentError
21
+ render html: ''
20
22
  end
21
23
 
22
24
  def enqueue
@@ -0,0 +1,36 @@
1
+ module Shipit
2
+ class ReleaseStatusesController < ShipitController
3
+ before_action :load_stack
4
+ before_action :load_deploy
5
+
6
+ def create
7
+ case params[:status]
8
+ when 'success'
9
+ @deploy.append_release_status(
10
+ 'success',
11
+ "@#{current_user.login} signaled this release as healthy.",
12
+ user: current_user,
13
+ )
14
+ when 'failure'
15
+ @deploy.append_release_status(
16
+ 'failure',
17
+ "@#{current_user.login} signaled this release as faulty.",
18
+ user: current_user,
19
+ )
20
+ else
21
+ render status: :unprocessable_entity, json: {message: "Invalid `status` parameter"}
22
+ end
23
+ render status: :created, json: @deploy.last_release_status
24
+ end
25
+
26
+ private
27
+
28
+ def load_deploy
29
+ @deploy = @stack.deploys_and_rollbacks.find(params[:deploy_id])
30
+ end
31
+
32
+ def load_stack
33
+ @stack ||= Stack.from_param!(params[:stack_id])
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,17 @@
1
+ module Shipit
2
+ class AppendDelayedReleaseStatusJob < BackgroundJob
3
+ include BackgroundJob::Unique
4
+
5
+ queue_as :default
6
+
7
+ def lock_key(deploy, *)
8
+ super(deploy)
9
+ end
10
+
11
+ def perform(deploy, cursor:, status:, description:)
12
+ return unless cursor == deploy.until_commit.release_statuses.last
13
+
14
+ deploy.append_release_status(status, description)
15
+ end
16
+ end
17
+ end
@@ -2,6 +2,8 @@ module Shipit
2
2
  class CacheDeploySpecJob < BackgroundJob
3
3
  include BackgroundJob::Unique
4
4
 
5
+ queue_as :deploys
6
+
5
7
  def perform(stack)
6
8
  return if stack.inaccessible?
7
9
 
@@ -1,6 +1,6 @@
1
1
  module Shipit
2
2
  class ClearGitCacheJob < BackgroundJob
3
- queue_as :default
3
+ queue_as :deploys
4
4
 
5
5
  def perform(stack)
6
6
  stack.clear_git_cache!
@@ -0,0 +1,11 @@
1
+ module Shipit
2
+ class CreateReleaseStatusesJob < BackgroundJob
3
+ include BackgroundJob::Unique
4
+
5
+ queue_as :default
6
+
7
+ def perform(commit)
8
+ commit.release_statuses.to_be_created.each(&:create_status_on_github!)
9
+ end
10
+ end
11
+ end
@@ -2,6 +2,8 @@ module Shipit
2
2
  class DeferredTouchJob < BackgroundJob
3
3
  include BackgroundJob::Unique
4
4
 
5
+ queue_as :default
6
+
5
7
  def perform
6
8
  DeferredTouch.touch_now!
7
9
  end
@@ -3,6 +3,7 @@ module Shipit
3
3
  queue_as :hooks
4
4
 
5
5
  def perform(delivery)
6
+ delivery = Hook::DeliverySpec.new(delivery) if delivery.is_a?(Hash)
6
7
  delivery.send!
7
8
  end
8
9
  end
@@ -3,6 +3,8 @@ module Shipit
3
3
  include BackgroundJob::Unique
4
4
  on_duplicate :drop
5
5
 
6
+ queue_as :default
7
+
6
8
  def perform(stack)
7
9
  pull_requests = stack.pull_requests.to_be_merged.to_a
8
10
  pull_requests.each do |pull_request|
@@ -2,6 +2,8 @@ module Shipit
2
2
  class PerformCommitChecksJob < BackgroundJob
3
3
  include BackgroundJob::Unique
4
4
 
5
+ queue_as :deploys
6
+
5
7
  def perform(commit:)
6
8
  commit.checks.run
7
9
  end
@@ -55,10 +55,8 @@ module Shipit
55
55
  end
56
56
 
57
57
  def perform_task
58
- Bundler.with_clean_env do
59
- capture_all! @commands.install_dependencies
60
- capture_all! @commands.perform
61
- end
58
+ capture_all! @commands.install_dependencies
59
+ capture_all! @commands.perform
62
60
  end
63
61
 
64
62
  def checkout_repository
@@ -1,5 +1,7 @@
1
1
  module Shipit
2
2
  class RefreshPullRequestJob < BackgroundJob
3
+ queue_as :default
4
+
3
5
  def perform(pull_request)
4
6
  pull_request.refresh!
5
7
  MergePullRequestsJob.perform_later(pull_request.stack)
@@ -31,7 +31,7 @@ module Shipit
31
31
  end
32
32
 
33
33
  def authorized?
34
- false
34
+ Shipit.authentication_disabled?
35
35
  end
36
36
 
37
37
  def stacks_contributed_to
@@ -8,6 +8,7 @@ module Shipit
8
8
  has_many :deploys
9
9
  has_many :statuses, -> { order(created_at: :desc) }, dependent: :destroy, inverse_of: :commit
10
10
  has_many :commit_deployments, dependent: :destroy
11
+ has_many :release_statuses, dependent: :destroy
11
12
  belongs_to :pull_request, inverse_of: :merge_commit, optional: true
12
13
 
13
14
  deferred_touch stack: :updated_at
@@ -21,6 +22,14 @@ module Shipit
21
22
  belongs_to :author, class_name: 'User', inverse_of: :authored_commits
22
23
  belongs_to :committer, class_name: 'User', inverse_of: :commits
23
24
 
25
+ def author
26
+ super || AnonymousUser.new
27
+ end
28
+
29
+ def committer
30
+ super || AnonymousUser.new
31
+ end
32
+
24
33
  scope :reachable, -> { where(detached: false) }
25
34
 
26
35
  delegate :broadcast_update, :github_repo_name, :hidden_statuses, :required_statuses, :blocking_statuses,
@@ -64,11 +73,16 @@ module Shipit
64
73
  end
65
74
 
66
75
  def self.from_github(commit)
76
+ author = User.find_or_create_author_from_github_commit(commit)
77
+ author ||= Anonymous.new
78
+ committer = User.find_or_create_committer_from_github_commit(commit)
79
+ committer ||= Anonymous.new
80
+
67
81
  new(
68
82
  sha: commit.sha,
69
83
  message: commit.commit.message,
70
- author: User.find_or_create_from_github(commit.author || commit.commit.author),
71
- committer: User.find_or_create_from_github(commit.committer || commit.commit.committer),
84
+ author: author,
85
+ committer: committer,
72
86
  committed_at: commit.commit.committer.date,
73
87
  authored_at: commit.commit.author.date,
74
88
  additions: commit.stats&.additions,
@@ -104,6 +118,23 @@ module Shipit
104
118
  end
105
119
  end
106
120
 
121
+ def last_release_status
122
+ @last_release_status ||= release_statuses.last || Status::Unknown.new(self)
123
+ end
124
+
125
+ def create_release_status!(state, user: nil, target_url: nil, description: nil)
126
+ return unless stack.release_status?
127
+
128
+ @last_release_status = nil
129
+ release_statuses.create!(
130
+ stack: stack,
131
+ user: user,
132
+ state: state,
133
+ target_url: target_url,
134
+ description: description,
135
+ )
136
+ end
137
+
107
138
  def checks
108
139
  @checks ||= CommitChecks.new(self)
109
140
  end
@@ -233,7 +264,9 @@ module Shipit
233
264
 
234
265
  unless already_deployed
235
266
  payload = {commit: self, stack: stack, status: new_status.state}
236
- Hook.emit(:commit_status, stack, payload.merge(commit_status: new_status)) if previous_status != new_status
267
+ if previous_status != new_status
268
+ Hook.emit(:commit_status, stack, payload.merge(commit_status: new_status))
269
+ end
237
270
  end
238
271
 
239
272
  if previous_status.simple_state != new_status.simple_state