shipit-engine 0.26.0 → 0.27.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +5 -5
  2. data/app/assets/images/faulty.svg +9 -0
  3. data/app/assets/images/validating.svg +13 -0
  4. data/app/assets/stylesheets/_pages/_commits.scss +18 -0
  5. data/app/controllers/shipit/api/commits_controller.rb +6 -1
  6. data/app/controllers/shipit/api/deploys_controller.rb +4 -0
  7. data/app/controllers/shipit/release_statuses_controller.rb +2 -10
  8. data/app/jobs/shipit/mark_deploy_healty_job.rb +13 -0
  9. data/app/jobs/shipit/perform_task_job.rb +1 -1
  10. data/app/models/shipit/check_run.rb +8 -0
  11. data/app/models/shipit/deploy.rb +39 -16
  12. data/app/models/shipit/deploy_spec.rb +1 -1
  13. data/app/models/shipit/deploy_spec/lerna_discovery.rb +10 -7
  14. data/app/models/shipit/rollback.rb +10 -1
  15. data/app/models/shipit/stack.rb +7 -5
  16. data/app/models/shipit/task.rb +20 -6
  17. data/app/views/layouts/merge_status.html.erb +1 -1
  18. data/config/routes.rb +1 -1
  19. data/lib/shipit/version.rb +1 -1
  20. data/test/controllers/api/commits_controller_test.rb +10 -0
  21. data/test/controllers/api/deploys_controller_test.rb +11 -0
  22. data/test/controllers/merge_status_controller_test.rb +6 -1
  23. data/test/controllers/release_statuses_controller_test.rb +17 -3
  24. data/test/controllers/stacks_controller_test.rb +5 -0
  25. data/test/dummy/config/application.rb +1 -13
  26. data/test/dummy/config/initializers/0_load_development_secrets.rb +2 -2
  27. data/test/dummy/db/schema.rb +1 -1
  28. data/test/fixtures/shipit/commits.yml +65 -0
  29. data/test/fixtures/shipit/release_statuses.yml +4 -4
  30. data/test/fixtures/shipit/stacks.yml +57 -2
  31. data/test/fixtures/shipit/statuses.yml +9 -0
  32. data/test/fixtures/shipit/tasks.yml +48 -0
  33. data/test/jobs/mark_deploy_healthy_job_test.rb +23 -0
  34. data/test/jobs/perform_task_job_test.rb +30 -0
  35. data/test/models/commits_test.rb +1 -1
  36. data/test/models/deploy_spec_test.rb +2 -2
  37. data/test/models/deploys_test.rb +40 -14
  38. data/test/models/pull_request_test.rb +4 -4
  39. data/test/models/release_statuses_test.rb +2 -2
  40. data/test/models/stacks_test.rb +58 -0
  41. metadata +127 -125
  42. data/app/jobs/shipit/append_delayed_release_status_job.rb +0 -17
  43. data/test/jobs/append_delayed_release_status_job_test.rb +0 -25
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 84e2ecaebc907d7522d77553a552bafefa65cc7f
4
- data.tar.gz: 59cd29bbf69566d7a0c2fa82ed3ad0f0086d307b
2
+ SHA256:
3
+ metadata.gz: 762ae4d018877b6f41fb8da260308546bd12575052091eff89613ed2eec03c39
4
+ data.tar.gz: 16d840d7d162baf954b1c2df8c710c404af74e3963f98e9a3a65db92ad7e2e51
5
5
  SHA512:
6
- metadata.gz: fa96c8e445ac42b2b3138d6fbc00b3f61a290f06d491547ee6e1a83c09bf5f322a716af4539cf138bbc586d31e19944fc43438338722fc144ec0ce4113c11ae3
7
- data.tar.gz: dab317ea37e1211b7cc765a2e30521bc7ca2054880f3df11402570d86fcc0326baf1e832e7182d647dc9c2f7f56f52f85ddc1e1b317546170862e077b4ae0eaa
6
+ metadata.gz: 15d549a32fafc05268f2f3a07d4794d76804ba1e3c5349a6ff5340579460b01f048ee9535a026dbc03fb8893734563b451ef7f2e0dbd16b3d0f18ec39c5c1505
7
+ data.tar.gz: 60abb9fdf8e2257b6dc7aaa5c1b13a804242cc795fd3173ce55ece79ea328db1eb885e02b99af6d3484bf76eaf05a3f0d5ec500f87a3e546e49cd0b859dcf1f5
@@ -0,0 +1,9 @@
1
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2
+ <svg width="19px" height="14px" viewBox="0 0 19 14" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
3
+ <defs></defs>
4
+ <g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
5
+ <g stroke-width="2" stroke="#FFC66C">
6
+ <path d="M0.699,6.254 L6.369,11.79 L17.737,0.716"></path>
7
+ </g>
8
+ </g>
9
+ </svg>
@@ -0,0 +1,13 @@
1
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2
+ <svg width="40px" height="40px" viewBox="0 0 40 40" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
3
+ <!-- Generator: Sketch 3.0.2 (7799) - http://www.bohemiancoding.com/sketch -->
4
+ <title>unknown</title>
5
+ <description>Created with Sketch.</description>
6
+ <defs></defs>
7
+ <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
8
+ <g id="unknown" sketch:type="MSArtboardGroup" fill="#25C351">
9
+ <path d="M15.0013334,17.28 L16.8713334,17.28 C16.8713334,16.7666641 16.9299994,16.2900022 17.0473334,15.85 C17.1646673,15.4099978 17.3516654,15.0286683 17.6083334,14.706 C17.8650013,14.3833317 18.1839981,14.1266676 18.5653334,13.936 C18.9466686,13.7453324 19.4013307,13.65 19.9293334,13.65 C20.7213373,13.65 21.348331,13.8773311 21.8103334,14.332 C22.2723357,14.7866689 22.5326664,15.4173293 22.5913334,16.224 C22.6206668,16.7666694 22.5546675,17.2286648 22.3933334,17.61 C22.2319992,17.9913352 22.015668,18.3396651 21.7443334,18.655 C21.4729987,18.9703349 21.1796683,19.2709986 20.8643334,19.557 C20.5489984,19.8430014 20.2483348,20.154665 19.9623334,20.492 C19.6763319,20.829335 19.4343343,21.2143312 19.2363334,21.647 C19.0383324,22.0796688 18.9246668,22.6039969 18.8953334,23.22 L18.8953334,24.254 L20.7653334,24.254 L20.7653334,23.396 C20.7653334,23.0146648 20.8203328,22.6736682 20.9303334,22.373 C21.0403339,22.0723318 21.1869991,21.7936679 21.3703334,21.537 C21.5536676,21.280332 21.7589989,21.0383345 21.9863334,20.811 C22.2136678,20.5836655 22.4446655,20.3600011 22.6793334,20.14 C22.9140012,19.9053322 23.1449989,19.6633346 23.3723334,19.414 C23.5996678,19.1646654 23.8013325,18.8933348 23.9773334,18.6 C24.1533342,18.3066652 24.2963328,17.9803351 24.4063334,17.621 C24.5163339,17.2616649 24.5713334,16.8546689 24.5713334,16.4 C24.5713334,15.6959965 24.4576678,15.0726694 24.2303334,14.53 C24.0029989,13.9873306 23.6840021,13.5290019 23.2733334,13.155 C22.8626646,12.7809981 22.3750028,12.495001 21.8103334,12.297 C21.2456639,12.098999 20.6186701,12 19.9293334,12 C19.1666629,12 18.4773364,12.1319987 17.8613334,12.396 C17.2453303,12.6600013 16.7246688,13.030331 16.2993334,13.507 C15.8739979,13.9836691 15.5476678,14.5446634 15.3203334,15.19 C15.0929989,15.8353366 14.9866666,16.5319963 15.0013334,17.28 L15.0013334,17.28 Z" id="?" sketch:type="MSShapeGroup"></path>
10
+ <circle id="Oval-4" stroke="#CCCCCC" sketch:type="MSShapeGroup" cx="20" cy="28" r="1"></circle>
11
+ </g>
12
+ </g>
13
+ </svg>
@@ -256,6 +256,24 @@
256
256
  }
257
257
  }
258
258
 
259
+ .status--validating,
260
+ [data-deploy-status='validating'] {
261
+ border-color: $green;
262
+
263
+ .status__icon {
264
+ background-image: asset-data-url("validating.svg");
265
+ }
266
+ }
267
+
268
+ .status--faulty,
269
+ [data-deploy-status='faulty'] {
270
+ border-color: $yellow;
271
+
272
+ .status__icon {
273
+ background-image: asset-data-url("faulty.svg");
274
+ }
275
+ }
276
+
259
277
  .status--success,
260
278
  [data-deploy-status='success'] {
261
279
  border-color: $green;
@@ -4,7 +4,12 @@ module Shipit
4
4
  require_permission :read, :stack
5
5
 
6
6
  def index
7
- render_resources stack.commits.reachable.includes(:statuses)
7
+ commits = stack.commits.reachable.includes(:statuses)
8
+ if params[:undeployed]
9
+ commits = commits.newer_than(stack.last_deployed_commit)
10
+ end
11
+
12
+ render_resources commits
8
13
  end
9
14
  end
10
15
  end
@@ -3,6 +3,10 @@ module Shipit
3
3
  class DeploysController < BaseController
4
4
  require_permission :deploy, :stack
5
5
 
6
+ def index
7
+ render_resources stack.deploys_and_rollbacks
8
+ end
9
+
6
10
  params do
7
11
  requires :sha, String, length: {in: 6..40}
8
12
  accepts :force, Boolean, default: false
@@ -6,17 +6,9 @@ module Shipit
6
6
  def create
7
7
  case params[:status]
8
8
  when 'success'
9
- @deploy.append_release_status(
10
- 'success',
11
- "@#{current_user.login} signaled this release as healthy.",
12
- user: current_user,
13
- )
9
+ @deploy.report_healthy!(user: current_user)
14
10
  when 'failure'
15
- @deploy.append_release_status(
16
- 'failure',
17
- "@#{current_user.login} signaled this release as faulty.",
18
- user: current_user,
19
- )
11
+ @deploy.report_faulty!(user: current_user)
20
12
  else
21
13
  render status: :unprocessable_entity, json: {message: "Invalid `status` parameter"}
22
14
  end
@@ -0,0 +1,13 @@
1
+ module Shipit
2
+ class MarkDeployHealthyJob < BackgroundJob
3
+ include BackgroundJob::Unique
4
+
5
+ queue_as :default
6
+
7
+ def perform(deploy)
8
+ return unless deploy.validating?
9
+
10
+ deploy.report_healthy!(description: "No issues were signalled after #{deploy.stack.release_status_delay}")
11
+ end
12
+ end
13
+ end
@@ -18,7 +18,7 @@ module Shipit
18
18
  @task.run!
19
19
  checkout_repository
20
20
  perform_task
21
- @task.complete!
21
+ @task.report_complete!
22
22
  rescue Command::TimedOut => error
23
23
  @task.write("\n#{error.message}\n")
24
24
  @task.report_timeout!(error)
@@ -11,6 +11,8 @@ module Shipit
11
11
 
12
12
  validates :conclusion, inclusion: {in: CONCLUSIONS, allow_nil: true}
13
13
 
14
+ after_create :enable_ci_on_stack
15
+
14
16
  class << self
15
17
  def create_or_update_by!(selector:, attributes: {})
16
18
  create!(selector.merge(attributes))
@@ -67,5 +69,11 @@ module Shipit
67
69
  def to_partial_path
68
70
  'shipit/statuses/status'
69
71
  end
72
+
73
+ private
74
+
75
+ def enable_ci_on_stack
76
+ commit.stack.enable_ci!
77
+ end
70
78
  end
71
79
  end
@@ -66,13 +66,14 @@ module Shipit
66
66
  end
67
67
 
68
68
  # Rolls the stack back to the **previous** deploy
69
- def trigger_revert
69
+ def trigger_revert(force: false)
70
70
  rollback = Rollback.create!(
71
71
  user_id: user_id,
72
72
  stack_id: stack_id,
73
73
  parent_id: id,
74
74
  since_commit: until_commit,
75
75
  until_commit: since_commit,
76
+ allow_concurrency: force,
76
77
  )
77
78
  rollback.enqueue
78
79
  lock_reason = "A rollback for #{until_commit.sha} has been triggered. " \
@@ -160,6 +161,36 @@ module Shipit
160
161
  Shipit::Engine.routes.url_helpers.stack_deploy_url(stack, self)
161
162
  end
162
163
 
164
+ def report_complete!
165
+ if stack.release_status? && stack.release_status_delay.positive?
166
+ enter_validation!
167
+ else
168
+ super
169
+ end
170
+ end
171
+
172
+ def report_healthy!(user: self.user, description: "@#{user.login} signaled this release as healthy.")
173
+ transaction do
174
+ complete! if can_complete?
175
+ append_release_status(
176
+ 'success',
177
+ description,
178
+ user: user,
179
+ )
180
+ end
181
+ end
182
+
183
+ def report_faulty!(user: self.user, description: "@#{user.login} signaled this release as faulty.")
184
+ transaction do
185
+ mark_faulty! if can_mark_faulty?
186
+ append_release_status(
187
+ 'failure',
188
+ description,
189
+ user: user,
190
+ )
191
+ end
192
+ end
193
+
163
194
  private
164
195
 
165
196
  def create_commit_deployments
@@ -178,18 +209,14 @@ module Shipit
178
209
  append_release_status('error', "The deploy on #{stack.environment} did not succeed (#{status})")
179
210
  when 'aborted', 'aborting'
180
211
  append_release_status('failure', "The deploy on #{stack.environment} was canceled")
212
+ when 'validating'
213
+ if stack.release_status_delay.positive?
214
+ append_release_status('pending', "The deploy on #{stack.environment} succeeded")
215
+ MarkDeployHealthyJob.set(wait: stack.release_status_delay).perform_later(self)
216
+ end
181
217
  when 'success'
182
- delay = stack.release_status_delay
183
- if delay.zero?
218
+ if stack.release_status_delay.zero?
184
219
  append_release_status('success', "The deploy on #{stack.environment} succeeded")
185
- elsif delay.positive?
186
- append_release_status('pending', "The deploy on #{stack.environment} succeeded")
187
- AppendDelayedReleaseStatusJob.set(wait: delay).perform_later(
188
- self,
189
- cursor: until_commit.release_statuses.last,
190
- status: 'success',
191
- description: "No issue were signaled after #{delay}",
192
- )
193
220
  end
194
221
  end
195
222
  end
@@ -206,7 +233,7 @@ module Shipit
206
233
 
207
234
  def default_since_commit_id
208
235
  return unless stack
209
- @default_since_commit_id ||= last_successful_deploy&.until_commit_id
236
+ @default_since_commit_id ||= stack.last_completed_deploy&.until_commit_id
210
237
  end
211
238
 
212
239
  def denormalize_commit_stats
@@ -223,10 +250,6 @@ module Shipit
223
250
  ContinuousDeliveryJob.perform_later(stack)
224
251
  end
225
252
 
226
- def last_successful_deploy
227
- stack.deploys.where(status: "success").last
228
- end
229
-
230
253
  def update_undeployed_commits_count
231
254
  stack.update_undeployed_commits_count(until_commit)
232
255
  end
@@ -76,7 +76,7 @@ module Shipit
76
76
  end
77
77
 
78
78
  def release_status_delay
79
- if delay = config('status', 'delay') { config('deploy', 'interval') }
79
+ if delay = config('status', 'delay') { config('deploy', 'interval') { 0 } }
80
80
  Duration.parse(delay)
81
81
  end
82
82
  end
@@ -70,13 +70,16 @@ module Shipit
70
70
  check_tags = 'assert-lerna-fixed-version-tag'
71
71
  # `yarn publish` requires user input, so always use npm.
72
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)}"
73
+ publish = %W(
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
+ --npm-client=npm
81
+ --skip-npm=false
82
+ ).join(" ")
80
83
 
81
84
  [check_tags, publish]
82
85
  end
@@ -39,7 +39,16 @@ module Shipit
39
39
 
40
40
  case status
41
41
  when 'pending'
42
- deploy.append_release_status('failure', "A rollback #{stack.to_param} was triggered")
42
+ if deploy.rollback_once_aborted?
43
+ deploy.report_faulty!(description: "A rollback of #{stack.to_param} was triggered")
44
+ else
45
+ since_commit.create_release_status!(
46
+ 'failure',
47
+ user: user.presence,
48
+ target_url: permalink,
49
+ description: "A rollback of #{stack.to_param} was triggered",
50
+ )
51
+ end
43
52
  end
44
53
  end
45
54
 
@@ -141,7 +141,7 @@ module Shipit
141
141
  end
142
142
 
143
143
  def continuous_delivery_delayed!
144
- touch(:continuous_delivery_delayed_since, :updated_at) unless continuous_delivery_delayed?
144
+ touch(:continuous_delivery_delayed_since) unless continuous_delivery_delayed?
145
145
  end
146
146
 
147
147
  def trigger_continuous_delivery
@@ -175,6 +175,8 @@ module Shipit
175
175
 
176
176
  def deployed_too_recently?
177
177
  if task = last_active_task
178
+ return true if task.validating?
179
+
178
180
  task.ended_at? && (task.ended_at + pause_between_deploys).future?
179
181
  end
180
182
  end
@@ -255,8 +257,8 @@ module Shipit
255
257
  scope.map.with_index { |c, i| UndeployedCommit.new(c, i) }.reverse
256
258
  end
257
259
 
258
- def last_successful_deploy
259
- deploys_and_rollbacks.last_successful
260
+ def last_completed_deploy
261
+ deploys_and_rollbacks.last_completed
260
262
  end
261
263
 
262
264
  def last_active_task
@@ -264,7 +266,7 @@ module Shipit
264
266
  end
265
267
 
266
268
  def last_deployed_commit
267
- last_successful_deploy&.until_commit || NoDeployedCommit
269
+ last_completed_deploy&.until_commit || NoDeployedCommit
268
270
  end
269
271
 
270
272
  def deployable?
@@ -426,7 +428,7 @@ module Shipit
426
428
 
427
429
  def ci_enabled?
428
430
  Rails.cache.fetch(ci_enabled_cache_key) do
429
- commits.joins(:statuses).any?
431
+ commits.joins(:statuses).any? || commits.joins(:check_runs).any?
430
432
  end
431
433
  end
432
434
 
@@ -6,8 +6,8 @@ module Shipit
6
6
 
7
7
  PRESENCE_CHECK_TIMEOUT = 15
8
8
  ACTIVE_STATUSES = %w(pending running aborting).freeze
9
- COMPLETED_STATUSES = %w(success error failed flapping aborted).freeze
10
- UNSUCCESSFUL_STATUSES = %w(error failed aborted flapping timedout).freeze
9
+ COMPLETED_STATUSES = %w(success flapping faulty validating).freeze
10
+ UNSUCCESSFUL_STATUSES = %w(error failed aborted flapping timedout faulty).freeze
11
11
 
12
12
  attr_accessor :pid
13
13
 
@@ -43,8 +43,8 @@ module Shipit
43
43
  pluck(:started_at, :ended_at).select { |s, e| s && e }.map { |s, e| e - s }
44
44
  end
45
45
 
46
- def last_successful
47
- success.last
46
+ def last_completed
47
+ completed.last
48
48
  end
49
49
 
50
50
  def current
@@ -57,7 +57,7 @@ module Shipit
57
57
  task.started_at ||= Time.now.utc
58
58
  end
59
59
 
60
- before_transition any => %i(success failed error timedout) do |task|
60
+ before_transition any => %i(success failed error timedout validating) do |task|
61
61
  task.ended_at ||= Time.now.utc
62
62
  end
63
63
 
@@ -82,7 +82,15 @@ module Shipit
82
82
  end
83
83
 
84
84
  event :complete do
85
- transition %i(running flapping) => :success
85
+ transition %i(running flapping validating faulty) => :success
86
+ end
87
+
88
+ event :enter_validation do
89
+ transition %i(running flapping) => :validating
90
+ end
91
+
92
+ event :mark_faulty do
93
+ transition %i(validating success) => :faulty
86
94
  end
87
95
 
88
96
  event :error do
@@ -107,6 +115,8 @@ module Shipit
107
115
 
108
116
  state :pending
109
117
  state :running
118
+ state :validating
119
+ state :faulty
110
120
  state :failed
111
121
  state :success
112
122
  state :error
@@ -120,6 +130,10 @@ module Shipit
120
130
  status.in?(ACTIVE_STATUSES)
121
131
  end
122
132
 
133
+ def report_complete!
134
+ complete!
135
+ end
136
+
123
137
  def report_failure!(error)
124
138
  reload
125
139
  if aborting?
@@ -1,7 +1,7 @@
1
1
  <!DOCTYPE html>
2
2
  <html>
3
3
  <head>
4
- <%= stylesheet_link_tag *(params[:stylesheets] || []).select { |url| url.start_with?('https://assets-cdn.github.com/') } %>
4
+ <%= stylesheet_link_tag *(params[:stylesheets] || []).select { |url| url.start_with?('https://assets-cdn.github.com/', 'https://github.githubassets.com/') } %>
5
5
  <%= stylesheet_link_tag 'merge_status' %>
6
6
  </head>
7
7
  <body>
@@ -24,7 +24,7 @@ Shipit::Engine.routes.draw do
24
24
  resources :tasks, only: %i(index show) do
25
25
  resource :output, only: :show
26
26
  end
27
- resources :deploys, only: %i(create)
27
+ resources :deploys, only: %i(index create)
28
28
  resources :commits, only: %i(index)
29
29
  resources :pull_requests, only: %i(index show update destroy)
30
30
  post '/task/:task_name' => 'tasks#trigger', as: :trigger_task
@@ -1,3 +1,3 @@
1
1
  module Shipit
2
- VERSION = '0.26.0'.freeze
2
+ VERSION = '0.27.0'.freeze
3
3
  end
@@ -15,6 +15,16 @@ module Shipit
15
15
  assert_response :ok
16
16
  assert_json '0.sha', commit.sha
17
17
  end
18
+
19
+ test "#index with undeployed=1 returns a list of undeployed commits" do
20
+ commits = @stack.undeployed_commits.pluck(:sha)
21
+
22
+ get :index, params: {stack_id: @stack.to_param, undeployed: 1}
23
+ assert_response :ok
24
+ JSON.parse(response.body).each do |commit|
25
+ assert commits.include?(commit.fetch("sha"))
26
+ end
27
+ end
18
28
  end
19
29
  end
20
30
  end