shipit-engine 0.35.1 → 0.36.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +7 -7
  3. data/app/controllers/concerns/shipit/authentication.rb +5 -1
  4. data/app/controllers/shipit/api/base_controller.rb +13 -1
  5. data/app/controllers/shipit/api/rollbacks_controller.rb +1 -1
  6. data/app/controllers/shipit/api/stacks_controller.rb +8 -2
  7. data/app/controllers/shipit/api/tasks_controller.rb +19 -2
  8. data/app/helpers/shipit/stacks_helper.rb +11 -0
  9. data/app/models/concerns/shipit/deferred_touch.rb +3 -3
  10. data/app/models/shipit/anonymous_user.rb +4 -0
  11. data/app/models/shipit/commit_checks.rb +3 -3
  12. data/app/models/shipit/task.rb +3 -3
  13. data/app/models/shipit/user.rb +23 -9
  14. data/app/serializers/shipit/stack_serializer.rb +1 -1
  15. data/app/views/shipit/deploys/_deploy.html.erb +1 -5
  16. data/app/views/shipit/stacks/_banners.html.erb +1 -1
  17. data/app/views/shipit/stacks/_settings_form.erb +55 -0
  18. data/app/views/shipit/stacks/settings.html.erb +1 -55
  19. data/app/views/shipit/stacks/show.html.erb +1 -1
  20. data/config/locales/en.yml +1 -1
  21. data/config/routes.rb +4 -0
  22. data/db/migrate/20211103154121_increase_github_team_slug_size.rb +5 -0
  23. data/lib/shipit/engine.rb +13 -5
  24. data/lib/shipit/stack_commands.rb +1 -1
  25. data/lib/shipit/version.rb +1 -1
  26. data/lib/shipit.rb +5 -2
  27. data/test/controllers/api/hooks_controller_test.rb +1 -1
  28. data/test/controllers/api/rollback_controller_test.rb +1 -0
  29. data/test/controllers/api/stacks_controller_test.rb +25 -0
  30. data/test/controllers/api/tasks_controller_test.rb +56 -0
  31. data/test/controllers/stacks_controller_test.rb +11 -0
  32. data/test/dummy/config/application.rb +1 -2
  33. data/test/dummy/db/schema.rb +2 -2
  34. data/test/fixtures/shipit/check_runs.yml +3 -3
  35. data/test/fixtures/shipit/commits.yml +101 -101
  36. data/test/fixtures/shipit/deliveries.yml +1 -1
  37. data/test/fixtures/shipit/merge_requests.yml +19 -19
  38. data/test/fixtures/shipit/stacks.yml +28 -28
  39. data/test/fixtures/shipit/statuses.yml +16 -16
  40. data/test/fixtures/shipit/tasks.yml +65 -65
  41. data/test/fixtures/shipit/users.yml +2 -5
  42. data/test/models/commits_test.rb +6 -6
  43. data/test/models/tasks_test.rb +2 -2
  44. data/test/models/team_test.rb +21 -2
  45. data/test/models/users_test.rb +29 -9
  46. data/test/unit/deploy_commands_test.rb +1 -1
  47. metadata +175 -173
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7ab32590ea528100fc22999f40a17d9ffcefb72313672eb4858befdb9a6932e1
4
- data.tar.gz: fe6fe3d4b026e0e2d0ecb067639d97027649d26fd785c90b9e198ce0e478c2a9
3
+ metadata.gz: 3336765264c2c554f5dd879ac8ed409b08e4f5b281bbd9127132b688d23184ee
4
+ data.tar.gz: ac55d9a82c007326c9a231b784d887be1a826ba11cc71c581888a0018ffaed7b
5
5
  SHA512:
6
- metadata.gz: a51d622ab862751d118d2d0995361366d8035481f090ddfcaa09f01b672c326ed1708c4085831a195899500762cd29b6247c01710e08260b5baf263d2363cc33
7
- data.tar.gz: 327aac9271b84975c388c0dbb42c380f99c00d15b1ce6930bba6877066d0333b3c60efcaf8ab56e925d17e90ac1462c48cbccb9ec5da1537c04f45fe6149c49b
6
+ metadata.gz: a770a63ffadea62d25d8244265d5ea9552930fee64951d6c4b1e5be4a518271d54d34161b83a8760c9331c6f2758995e61114000bfcf5675b0353a955cc41bad
7
+ data.tar.gz: 7e7d3629476bab8aa1ab7655e099e6218b511fe728ef9161a2591835ae2c369cd22724e7c193243fd29779574ea1148b2adb97119ce8a04def1a46df0168d62c
data/README.md CHANGED
@@ -390,7 +390,7 @@ machine:
390
390
 
391
391
  <h3 id="ci">CI</h3>
392
392
 
393
- **<code>ci.require</code>** contains an array of the [statuses context](https://developer.github.com/v3/repos/statuses/) you want Shipit to disallow deploys if any of them is missing on the commit being deployed.
393
+ **<code>ci.require</code>** contains an array of the [statuses context](https://docs.github.com/en/rest/reference/commits#commit-statuses) you want Shipit to disallow deploys if any of them is missing on the commit being deployed.
394
394
 
395
395
  For example:
396
396
  ```yml
@@ -399,7 +399,7 @@ ci:
399
399
  - ci/circleci
400
400
  ```
401
401
 
402
- **<code>ci.hide</code>** contains an array of the [statuses context](https://developer.github.com/v3/repos/statuses/) you want Shipit to ignore.
402
+ **<code>ci.hide</code>** contains an array of the [statuses context](https://docs.github.com/en/rest/reference/commits#commit-statuses) you want Shipit to ignore.
403
403
 
404
404
  For example:
405
405
  ```yml
@@ -408,7 +408,7 @@ ci:
408
408
  - ci/circleci
409
409
  ```
410
410
 
411
- **<code>ci.allow_failures</code>** contains an array of the [statuses context](https://developer.github.com/v3/repos/statuses/) you want to be visible but not to required for deploy.
411
+ **<code>ci.allow_failures</code>** contains an array of the [statuses context](https://docs.github.com/en/rest/reference/commits#commit-statuses) you want to be visible but not to required for deploy.
412
412
 
413
413
  For example:
414
414
  ```yml
@@ -417,7 +417,7 @@ ci:
417
417
  - ci/circleci
418
418
  ```
419
419
 
420
- **<code>ci.blocking</code>** contains an array of the [statuses context](https://developer.github.com/v3/repos/statuses/) you want to disallow deploys if any of them is missing or failing on any of the commits being deployed.
420
+ **<code>ci.blocking</code>** contains an array of the [statuses context](https://docs.github.com/en/rest/reference/commits#commit-statuses) you want to disallow deploys if any of them is missing or failing on any of the commits being deployed.
421
421
 
422
422
  For example:
423
423
  ```yml
@@ -440,7 +440,7 @@ merge:
440
440
  revalidate_after: 12m30s
441
441
  ```
442
442
 
443
- **<code>merge.require</code>** contains an array of the [statuses context](https://developer.github.com/v3/repos/statuses/) that you want Shipit to consider as failing if they aren't present on the pull request. Defaults to `ci.require` if present, or empty otherwise.
443
+ **<code>merge.require</code>** contains an array of the [statuses context](https://docs.github.com/en/rest/reference/commits#commit-statuses) that you want Shipit to consider as failing if they aren't present on the pull request. Defaults to `ci.require` if present, or empty otherwise.
444
444
 
445
445
  For example:
446
446
  ```yml
@@ -449,7 +449,7 @@ merge:
449
449
  - continuous-integration/travis-ci/push
450
450
  ```
451
451
 
452
- **<code>merge.ignore</code>** contains an array of the [statuses context](https://developer.github.com/v3/repos/statuses/) that you want Shipit not to consider when merging pull requests. Defaults to the union of `ci.allow_failures` and `ci.hide` if any is present or empty otherwise.
452
+ **<code>merge.ignore</code>** contains an array of the [statuses context](https://docs.github.com/en/rest/reference/commits#commit-statuses) that you want Shipit not to consider when merging pull requests. Defaults to the union of `ci.allow_failures` and `ci.hide` if any is present or empty otherwise.
453
453
 
454
454
  For example:
455
455
  ```yml
@@ -458,7 +458,7 @@ merge:
458
458
  - codeclimate
459
459
  ```
460
460
 
461
- **<code>merge.method</code>** the [merge method](https://developer.github.com/v3/pulls/#merge-a-pull-request-merge-button) to use for this stack. If it's not set the default merge method will be used. Can be either `merge`, `squash` or `rebase`.
461
+ **<code>merge.method</code>** the [merge method](https://docs.github.com/en/rest/reference/pulls#merge-a-pull-request--parameters) to use for this stack. If it's not set the default merge method will be used. Can be either `merge`, `squash` or `rebase`.
462
462
 
463
463
  For example:
464
464
  ```yml
@@ -17,7 +17,11 @@ module Shipit
17
17
  private
18
18
 
19
19
  def force_github_authentication
20
- if Shipit.authentication_disabled? || current_user.logged_in?
20
+ if current_user.logged_in? && current_user.requires_fresh_login?
21
+ Rails.logger.warn("User #{current_user.id} requires a fresh login, logging out...")
22
+ reset_session
23
+ redirect_to(Shipit::Engine.routes.url_helpers.github_authentication_path(origin: request.original_url))
24
+ elsif Shipit.authentication_disabled? || current_user.logged_in?
21
25
  unless current_user.authorized?
22
26
  team_handles = Shipit.github_teams.map(&:handle)
23
27
  team_list = team_handles.to_sentence(two_words_connector: ' or ', last_word_connector: ', or ')
@@ -28,6 +28,18 @@ module Shipit
28
28
 
29
29
  private
30
30
 
31
+ module BasicAuth
32
+ # Workaround for https://github.com/rails/rails/pull/44610
33
+ extend ActionController::HttpAuthentication::Basic
34
+ extend self
35
+
36
+ private
37
+
38
+ def has_basic_credentials?(request)
39
+ request.authorization.present? && (auth_scheme(request).downcase == "basic")
40
+ end
41
+ end
42
+
31
43
  def namespace_for_serializer
32
44
  nil
33
45
  end
@@ -36,7 +48,7 @@ module Shipit
36
48
  @current_api_client = if Shipit.disable_api_authentication
37
49
  UnlimitedApiClient.new
38
50
  else
39
- authenticate_with_http_basic do |*parts|
51
+ BasicAuth.authenticate(request) do |*parts|
40
52
  token = parts.select(&:present?).join('--')
41
53
  ApiClient.authenticate(token)
42
54
  end
@@ -21,7 +21,7 @@ module Shipit
21
21
  param_error!(:force, "Can't rollback, deploy in progress")
22
22
  elsif stack.active_task?
23
23
  active_task = stack.active_task
24
- active_task.abort!(aborted_by: current_user, rollback_once_aborted_to: deploy)
24
+ active_task.abort!(aborted_by: current_user, rollback_once_aborted_to: deploy, rollback_once_aborted: true)
25
25
  response = active_task
26
26
  else
27
27
  response = deploy.trigger_rollback(current_user, env: deploy_env, force: params.force, lock: params.lock)
@@ -27,7 +27,7 @@ module Shipit
27
27
  requires :repo_name, String
28
28
  accepts :environment, String
29
29
  accepts :branch, String
30
- accepts :deploy_url, String
30
+ accepts :deploy_url, String, allow_nil: true
31
31
  accepts :ignore_ci, Boolean
32
32
  accepts :merge_queue_enabled, Boolean
33
33
  accepts :continuous_deployment, Boolean
@@ -40,8 +40,9 @@ module Shipit
40
40
  end
41
41
 
42
42
  params do
43
+ accepts :environment, String
43
44
  accepts :branch, String
44
- accepts :deploy_url, String
45
+ accepts :deploy_url, String, allow_nil: true
45
46
  accepts :ignore_ci, Boolean
46
47
  accepts :merge_queue_enabled, Boolean
47
48
  accepts :continuous_deployment, Boolean
@@ -60,6 +61,11 @@ module Shipit
60
61
  head(:accepted)
61
62
  end
62
63
 
64
+ def refresh
65
+ GithubSyncJob.perform_later(id: stack.id)
66
+ render_resource(stack, status: :accepted)
67
+ end
68
+
63
69
  private
64
70
 
65
71
  def create_params
@@ -3,14 +3,14 @@ module Shipit
3
3
  module Api
4
4
  class TasksController < BaseController
5
5
  require_permission :read, :stack
6
- require_permission :deploy, :stack, only: :trigger
6
+ require_permission :deploy, :stack, only: %i(trigger abort)
7
7
 
8
8
  def index
9
9
  render_resources(stack.tasks)
10
10
  end
11
11
 
12
12
  def show
13
- render_resource(stack.tasks.find(params[:id]))
13
+ render_resource(task)
14
14
  end
15
15
 
16
16
  params do
@@ -23,6 +23,23 @@ module Shipit
23
23
  message: 'A task is already running.',
24
24
  })
25
25
  end
26
+
27
+ def abort
28
+ if task.active?
29
+ task.abort!(aborted_by: current_user)
30
+ head(:accepted)
31
+ else
32
+ render(status: :method_not_allowed, json: {
33
+ message: "This task is not currently running.",
34
+ })
35
+ end
36
+ end
37
+
38
+ private
39
+
40
+ def task
41
+ stack.tasks.find(params[:id])
42
+ end
26
43
  end
27
44
  end
28
45
  end
@@ -36,6 +36,17 @@ module Shipit
36
36
  link_to(t("deploy_button.caption.#{deploy_state}"), url, class: classes, data: data)
37
37
  end
38
38
 
39
+ def rollback_button(deploy)
40
+ if deploy.stack.active_task?
41
+ link_to('Deploy in progress...', '#', class: 'btn disabled deploy-action')
42
+ else
43
+ url = rollback_stack_deploy_path(deploy.stack, deploy)
44
+ classes = %w(btn btn--delete deploy-action rollback-action)
45
+
46
+ link_to('Rollback to this deploy...', url, class: classes)
47
+ end
48
+ end
49
+
39
50
  def github_change_url(commit)
40
51
  if commit.pull_request?
41
52
  github_pull_request_url(commit)
@@ -49,9 +49,9 @@ module Shipit
49
49
  end
50
50
 
51
51
  def fetch_members
52
- Shipit.redis.multi do
53
- Shipit.redis.sunionstore(TMP_KEY, SET_KEY)
54
- Shipit.redis.del(SET_KEY)
52
+ Shipit.redis.multi do |transaction|
53
+ transaction.sunionstore(TMP_KEY, SET_KEY)
54
+ transaction.del(SET_KEY)
55
55
  end
56
56
 
57
57
  yield Shipit.redis.smembers(TMP_KEY).map { |r| r.split('|') }
@@ -31,6 +31,10 @@ module Shipit
31
31
  false
32
32
  end
33
33
 
34
+ def requires_fresh_login?
35
+ false
36
+ end
37
+
34
38
  def authorized?
35
39
  Shipit.authentication_disabled?
36
40
  end
@@ -44,9 +44,9 @@ module Shipit
44
44
  end
45
45
 
46
46
  def write(output)
47
- Shipit.redis.pipelined do
48
- Shipit.redis.append(key('output'), output)
49
- Shipit.redis.expire(key('output'), OUTPUT_TTL)
47
+ Shipit.redis.pipelined do |pipeline|
48
+ pipeline.append(key('output'), output)
49
+ pipeline.expire(key('output'), OUTPUT_TTL)
50
50
  end
51
51
  end
52
52
 
@@ -313,9 +313,9 @@ module Shipit
313
313
  end
314
314
 
315
315
  def request_abort
316
- Shipit.redis.pipelined do
317
- Shipit.redis.incr(abort_key)
318
- Shipit.redis.expire(abort_key, 1.month.to_i)
316
+ Shipit.redis.pipelined do |pipeline|
317
+ pipeline.incr(abort_key)
318
+ pipeline.expire(abort_key, 1.month.to_i)
319
319
  end
320
320
  end
321
321
 
@@ -3,6 +3,8 @@ module Shipit
3
3
  class User < Record
4
4
  DEFAULT_AVATAR = URI.parse('https://avatars.githubusercontent.com/u/583231?')
5
5
 
6
+ self.ignored_columns = %w(encrypted_github_access_token_iv)
7
+
6
8
  has_many :memberships
7
9
  has_many :teams, through: :memberships
8
10
  has_many :authored_commits, class_name: :Commit, foreign_key: :author_id, inverse_of: :author
@@ -11,7 +13,10 @@ module Shipit
11
13
 
12
14
  validates :name, presence: true
13
15
 
14
- attr_encrypted :github_access_token, key: Shipit.user_access_tokens_key
16
+ encrypts :encrypted_github_access_token
17
+ alias_attribute :github_access_token, :encrypted_github_access_token
18
+
19
+ after_find :discard_outdated_credentials!
15
20
 
16
21
  def self.find_or_create_by_login!(login)
17
22
  find_or_create_by!(login: login) do |user|
@@ -56,14 +61,6 @@ module Shipit
56
61
  end
57
62
  end
58
63
 
59
- alias_method :original_github_access_token, :github_access_token
60
- def github_access_token
61
- original_github_access_token
62
- rescue OpenSSL::Cipher::CipherError
63
- update_columns(encrypted_github_access_token: nil, encrypted_github_access_token_iv: nil)
64
- nil
65
- end
66
-
67
64
  def github_api
68
65
  return Shipit.github.api unless github_access_token
69
66
 
@@ -123,8 +120,25 @@ module Shipit
123
120
  DEFAULT_AVATAR.dup
124
121
  end
125
122
 
123
+ # https://github.blog/2021-04-05-behind-githubs-new-authentication-token-formats
124
+ GITHUB_TOKEN_FORMAT = /^gh[a-z]_/
125
+
126
+ def requires_fresh_login?
127
+ github_access_token.present? && !github_access_token.match(GITHUB_TOKEN_FORMAT)
128
+ end
129
+
126
130
  private
127
131
 
132
+ def discard_outdated_credentials!
133
+ if encrypted_github_access_token_before_type_cast.present?
134
+ begin
135
+ encrypted_github_access_token
136
+ rescue ActiveRecord::Encryption::Errors::Decryption
137
+ update_column(:encrypted_github_access_token, nil)
138
+ end
139
+ end
140
+ end
141
+
128
142
  def identify_renamed_user!
129
143
  last_commit = commits.last
130
144
  return unless last_commit
@@ -8,7 +8,7 @@ module Shipit
8
8
  attributes :id, :repo_owner, :repo_name, :environment, :html_url, :url, :tasks_url, :deploy_url,
9
9
  :merge_requests_url, :deploy_spec, :undeployed_commits_count, :is_locked, :lock_reason, :continuous_deployment,
10
10
  :created_at, :updated_at, :locked_since, :last_deployed_at, :branch, :merge_queue_enabled, :is_archived,
11
- :archived_since
11
+ :archived_since, :ignore_ci
12
12
 
13
13
  def url
14
14
  api_stack_url(object)
@@ -55,11 +55,7 @@
55
55
  <% unless read_only %>
56
56
  <div class="deploy-actions">
57
57
  <% if deploy.rollbackable? %>
58
- <% if deploy.stack.active_task? %>
59
- <%= link_to 'Deploy in progress...', '#', class: 'btn disabled deploy-action' %>
60
- <% else %>
61
- <%= link_to 'Rollback to this deploy...', rollback_stack_deploy_path(@stack, deploy), class: 'btn btn--delete deploy-action rollback-action' %>
62
- <% end %>
58
+ <%= rollback_button(deploy) %>
63
59
  <% elsif deploy.currently_deployed? && !deploy.stack.active_task? %>
64
60
  <%= redeploy_button(deploy.until_commit) %>
65
61
  <% end %>
@@ -23,7 +23,7 @@
23
23
  <%= link_to stack.github_repo_name, github_repo_url(stack.repo_owner, stack.repo_name) %>
24
24
  has been inaccessible for <%= time_ago_in_words(stack.inaccessible_since) %>.
25
25
 
26
- This could be a permission issue, or the repository have been deleted on GitHub.
26
+ This could be a permission issue, or the repo could have changed on GitHub.
27
27
  </p>
28
28
  </div>
29
29
  </div>
@@ -0,0 +1,55 @@
1
+ <div class="setting-section">
2
+ <%= form_with scope: :stack, url: stack_path(stack), method: :patch do |f| %>
3
+ <div class="field-wrapper">
4
+ <%= f.label :environment %>
5
+ <%= f.text_field :environment, placeholder: 'production' %>
6
+ </div>
7
+
8
+ <div class="field-wrapper">
9
+ <span>Branch: <%= stack.branch %></span>
10
+ </div>
11
+
12
+ <div class="field-wrapper">
13
+ <%= f.label :deploy_url, 'Deploy URL (Where is this stack deployed to?)' %>
14
+ <%= f.text_field :deploy_url, placeholder: 'https://' %>
15
+ </div>
16
+
17
+ <div class="field-wrapper">
18
+ <%= f.check_box :continuous_deployment %>
19
+ <%= f.label :continuous_deployment, 'Enable continuous deployment' %>
20
+ </div>
21
+
22
+ <div class="field-wrapper">
23
+ <%= f.check_box :merge_queue_enabled %>
24
+ <%= f.label :merge_queue_enabled, 'Enable merge queue' %>
25
+ </div>
26
+
27
+ <div class="field-wrapper">
28
+ <%= f.check_box :ignore_ci %>
29
+ <%= f.label :ignore_ci, "Don't require CI to deploy" %>
30
+ </div>
31
+
32
+ <%= f.submit class: "btn", value: "Save" %>
33
+ <% end %>
34
+ </div>
35
+
36
+ <div class="setting-section">
37
+ <h5>Lock deploys</h5>
38
+ <%= form_with scope: :stack, url: stack_path(@stack), method: :patch do |f| %>
39
+ <div class="field-wrapper">
40
+ <%= f.label :lock_reason, 'Reason for lock' %>
41
+ <%= f.text_area :lock_reason %>
42
+ </div>
43
+ <% if @stack.locked? %>
44
+ <%= f.submit class: "btn", value: "Update Reason" %>
45
+ <% else %>
46
+ <%= f.submit class: "btn", value: "Lock" %>
47
+ <% end %>
48
+ <% end %>
49
+ <% if @stack.locked? %>
50
+ <%= form_with scope: :stack, url: stack_path(@stack), method: :patch do |f| %>
51
+ <%= f.hidden_field :lock_reason, value: nil %>
52
+ <%= f.submit class: "btn btn--primary", value: "Unlock" %>
53
+ <%- end -%>
54
+ <% end %>
55
+ </div>
@@ -6,61 +6,7 @@
6
6
  <h2>Settings (Stack #<%= @stack.id %>)</h2>
7
7
  </header>
8
8
 
9
- <div class="setting-section">
10
- <%= form_with scope: :stack, url: stack_path(@stack), method: :patch do |f| %>
11
- <div class="field-wrapper">
12
- <%= f.label :environment %>
13
- <%= f.text_field :environment, placeholder: 'production' %>
14
- </div>
15
-
16
- <div class="field-wrapper">
17
- <span>Branch: <%= @stack.branch %></span>
18
- </div>
19
-
20
- <div class="field-wrapper">
21
- <%= f.label :deploy_url, 'Deploy URL (Where is this stack deployed to?)' %>
22
- <%= f.text_field :deploy_url, placeholder: 'https://' %>
23
- </div>
24
-
25
- <div class="field-wrapper">
26
- <%= f.check_box :continuous_deployment %>
27
- <%= f.label :continuous_deployment, 'Enable continuous deployment' %>
28
- </div>
29
-
30
- <div class="field-wrapper">
31
- <%= f.check_box :merge_queue_enabled %>
32
- <%= f.label :merge_queue_enabled, 'Enable merge queue' %>
33
- </div>
34
-
35
- <div class="field-wrapper">
36
- <%= f.check_box :ignore_ci %>
37
- <%= f.label :ignore_ci, "Don't require CI to deploy" %>
38
- </div>
39
-
40
- <%= f.submit class: "btn", value: "Save" %>
41
- <% end %>
42
- </div>
43
-
44
- <div class="setting-section">
45
- <h5>Lock deploys</h5>
46
- <%= form_with scope: :stack, url: stack_path(@stack), method: :patch do |f| %>
47
- <div class="field-wrapper">
48
- <%= f.label :lock_reason, 'Reason for lock' %>
49
- <%= f.text_area :lock_reason %>
50
- </div>
51
- <% if @stack.locked? %>
52
- <%= f.submit class: "btn", value: "Update Reason" %>
53
- <% else %>
54
- <%= f.submit class: "btn", value: "Lock" %>
55
- <% end %>
56
- <% end %>
57
- <% if @stack.locked? %>
58
- <%= form_with scope: :stack, url: stack_path(@stack), method: :patch do |f| %>
59
- <%= f.hidden_field :lock_reason, value: nil %>
60
- <%= f.submit class: "btn btn--primary", value: "Unlock" %>
61
- <%- end -%>
62
- <% end %>
63
- </div>
9
+ <%= render partial: 'shipit/stacks/settings_form', locals: { stack: @stack } %>
64
10
 
65
11
  <div class="setting-section">
66
12
  <h5>Resynchronize this stack</h5>
@@ -30,7 +30,7 @@
30
30
  </ul>
31
31
  </section>
32
32
 
33
- <% cache @stack do %>
33
+ <% cache [@stack, params[:force]] do %>
34
34
  <section>
35
35
  <header class="section-header">
36
36
  <h2>Previous Deploys</h2>
@@ -41,7 +41,7 @@ en:
41
41
  reject: Mark the release as faulty
42
42
  deploy_button:
43
43
  hint:
44
- max_commits: It is recommended not to deploy more than %{maximum} commits at once.
44
+ max_commits: Use caution when deploying more than %{maximum} commits at once.
45
45
  blocked: This commit range includes a commit that can't be deployed.
46
46
  caption:
47
47
  pending: Pending CI
data/config/routes.rb CHANGED
@@ -20,6 +20,7 @@ Shipit::Engine.routes.draw do
20
20
  get '/' => 'stacks#show'
21
21
  delete '/' => 'stacks#destroy'
22
22
  patch '/' => 'stacks#update'
23
+ post '/refresh' => 'stacks#refresh'
23
24
  end
24
25
 
25
26
  scope '/stacks/*stack_id', stack_id: stack_id_format, as: :stack do
@@ -27,6 +28,9 @@ Shipit::Engine.routes.draw do
27
28
  resource :lock, only: %i(create update destroy)
28
29
  resources :tasks, only: %i(index show) do
29
30
  resource :output, only: :show
31
+ member do
32
+ put :abort
33
+ end
30
34
  end
31
35
  resources :deploys, only: %i(index create) do
32
36
  resources :release_statuses, only: %i(create)
@@ -0,0 +1,5 @@
1
+ class IncreaseGithubTeamSlugSize < ActiveRecord::Migration[6.1]
2
+ def change
3
+ change_column :teams, :slug, :string, limit: 255, null: true
4
+ end
5
+ end
data/lib/shipit/engine.rb CHANGED
@@ -5,7 +5,7 @@ module Shipit
5
5
 
6
6
  paths['app/models'] << 'app/serializers' << 'app/serializers/concerns'
7
7
 
8
- initializer 'shipit.config' do |app|
8
+ initializer 'shipit.config', before: 'active_record_encryption.configuration' do |app|
9
9
  Rails.application.routes.default_url_options[:host] = Shipit.host
10
10
  Shipit::Engine.routes.default_url_options[:host] = Shipit.host
11
11
  Pubsubstub.redis_url = Shipit.redis_url.to_s
@@ -28,8 +28,6 @@ module Shipit
28
28
  path.end_with?('.svg') || (path.start_with?('emoji/') && path.end_with?('.png'))
29
29
  end
30
30
 
31
- ActionDispatch::ExceptionWrapper.rescue_responses[Shipit::TaskDefinition::NotFound.name] = :not_found
32
-
33
31
  ActiveModel::Serializer._root = false
34
32
  ActiveModel::ArraySerializer._root = false
35
33
  ActiveModel::Serializer.include(Engine.routes.url_helpers)
@@ -45,9 +43,19 @@ module Shipit
45
43
  app.config.middleware.insert_after(::Rack::Runtime, Shipit::SameSiteCookieMiddleware)
46
44
  end
47
45
 
48
- app.config.after_initialize do
49
- ActionController::Base.include(Shipit::ActiveModelSerializersPatch)
46
+ if app.credentials.active_record_encryption.blank? && Shipit.user_access_tokens_key.present?
47
+ # For ease of upgrade, we derive an Active Record encryption config automatically.
48
+ # But if AR Encryption is already configured, we just use that
49
+ app.credentials[:active_record_encryption] = {
50
+ primary_key: Shipit.user_access_tokens_key,
51
+ key_derivation_salt: Digest::SHA256.digest("salt:".b + Shipit.user_access_tokens_key),
52
+ }
50
53
  end
51
54
  end
55
+
56
+ config.after_initialize do
57
+ ActionDispatch::ExceptionWrapper.rescue_responses[Shipit::TaskDefinition::NotFound.name] = :not_found
58
+ ActionController::Base.include(Shipit::ActiveModelSerializersPatch)
59
+ end
52
60
  end
53
61
  end
@@ -16,7 +16,7 @@ module Shipit
16
16
  def fetch
17
17
  create_directories
18
18
  if valid_git_repository?(@stack.git_path)
19
- git('fetch', 'origin', '--tags', @stack.branch, env: env, chdir: @stack.git_path)
19
+ git('fetch', 'origin', '--quiet', '--tags', @stack.branch, env: env, chdir: @stack.git_path)
20
20
  else
21
21
  @stack.clear_git_cache!
22
22
  git_clone(@stack.repo_git_url, @stack.git_path, branch: @stack.branch, env: env, chdir: @stack.deploys_path)
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module Shipit
3
- VERSION = '0.35.1'
3
+ VERSION = '0.36.0'
4
4
  end
data/lib/shipit.rb CHANGED
@@ -5,7 +5,6 @@ require 'state_machines-activerecord'
5
5
  require 'validate_url'
6
6
  require 'responders'
7
7
  require 'explicit-parameters'
8
- require 'attr_encrypted'
9
8
 
10
9
  require 'sass-rails'
11
10
  require 'coffee-rails'
@@ -153,7 +152,11 @@ module Shipit
153
152
  end
154
153
 
155
154
  def user_access_tokens_key
156
- (secrets.user_access_tokens_key.presence || secrets.secret_key_base).byteslice(0, 32)
155
+ if secrets.user_access_tokens_key.present?
156
+ secrets.user_access_tokens_key
157
+ elsif secrets.secret_key_base
158
+ Digest::SHA256.digest("user_access_tokens_key" + secrets.secret_key_base)
159
+ end
157
160
  end
158
161
 
159
162
  def host
@@ -61,7 +61,7 @@ module Shipit
61
61
  post :create, params: {
62
62
  delivery_url: 'https://example.com/hook',
63
63
  events: %w(deploy rollback),
64
- created_at: 2.months.ago.to_s(:db),
64
+ created_at: 2.months.ago.to_formatted_s(:db),
65
65
  }
66
66
  Hook.last.created_at > 2.seconds.ago
67
67
  end
@@ -107,6 +107,7 @@ module Shipit
107
107
  assert_response :accepted
108
108
  refute_predicate last_deploy, :active?
109
109
  assert_json 'rollback_once_aborted_to.revision.sha', @commit.sha
110
+ assert last_deploy.rollback_once_aborted?
110
111
  end
111
112
  end
112
113
  end