shipit-engine 0.35.1 → 0.37.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 +20 -7
- data/app/controllers/concerns/shipit/authentication.rb +5 -1
- data/app/controllers/shipit/api/base_controller.rb +13 -1
- data/app/controllers/shipit/api/rollbacks_controller.rb +1 -1
- data/app/controllers/shipit/api/stacks_controller.rb +10 -2
- data/app/controllers/shipit/api/tasks_controller.rb +19 -2
- data/app/controllers/shipit/rollbacks_controller.rb +5 -1
- data/app/helpers/shipit/stacks_helper.rb +11 -0
- data/app/models/concerns/shipit/deferred_touch.rb +3 -3
- data/app/models/shipit/anonymous_user.rb +4 -0
- data/app/models/shipit/api_client.rb +1 -1
- data/app/models/shipit/commit_checks.rb +3 -3
- data/app/models/shipit/delivery.rb +1 -1
- data/app/models/shipit/deploy.rb +1 -0
- data/app/models/shipit/deploy_spec/file_system.rb +32 -4
- data/app/models/shipit/pull_request.rb +1 -1
- data/app/models/shipit/stack.rb +10 -10
- data/app/models/shipit/task.rb +31 -4
- data/app/models/shipit/user.rb +23 -9
- data/app/serializers/shipit/stack_serializer.rb +1 -1
- data/app/views/shipit/deploys/_deploy.html.erb +1 -5
- data/app/views/shipit/stacks/_banners.html.erb +1 -1
- data/app/views/shipit/stacks/_settings_form.erb +55 -0
- data/app/views/shipit/stacks/settings.html.erb +1 -55
- data/app/views/shipit/stacks/show.html.erb +1 -1
- data/config/locales/en.yml +1 -1
- data/config/routes.rb +4 -0
- data/db/migrate/20211103154121_increase_github_team_slug_size.rb +5 -0
- data/lib/shipit/engine.rb +15 -5
- data/lib/shipit/stack_commands.rb +9 -2
- data/lib/shipit/task_commands.rb +8 -1
- data/lib/shipit/version.rb +1 -1
- data/lib/shipit.rb +55 -3
- data/lib/snippets/fetch-gem-version +1 -1
- data/test/controllers/api/hooks_controller_test.rb +1 -1
- data/test/controllers/api/rollback_controller_test.rb +1 -0
- data/test/controllers/api/stacks_controller_test.rb +34 -0
- data/test/controllers/api/tasks_controller_test.rb +56 -0
- data/test/controllers/stacks_controller_test.rb +11 -0
- data/test/dummy/config/application.rb +1 -2
- data/test/dummy/db/schema.rb +2 -2
- data/test/fixtures/shipit/check_runs.yml +3 -3
- data/test/fixtures/shipit/commits.yml +101 -101
- data/test/fixtures/shipit/deliveries.yml +1 -1
- data/test/fixtures/shipit/merge_requests.yml +19 -19
- data/test/fixtures/shipit/stacks.yml +28 -28
- data/test/fixtures/shipit/statuses.yml +16 -16
- data/test/fixtures/shipit/tasks.yml +77 -65
- data/test/fixtures/shipit/users.yml +2 -5
- data/test/models/commits_test.rb +6 -6
- data/test/models/deploy_spec_test.rb +0 -23
- data/test/models/deploys_test.rb +26 -0
- data/test/models/shipit/deploy_spec/file_system_test.rb +81 -0
- data/test/models/tasks_test.rb +14 -2
- data/test/models/team_test.rb +21 -2
- data/test/models/users_test.rb +29 -9
- data/test/unit/deploy_commands_test.rb +6 -2
- metadata +189 -185
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 174fee8bf3ed460fa137cbe666f639fec2218d0617b4860dcede08d38ed6d93d
|
4
|
+
data.tar.gz: 739d8f122ead25b8f1053f954686e4ddd574bc17b544de9b69dce5af7635425c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7b3118fb7bc39e0c8cddad0444d34c39e935bcc192010dec3b27b2bddd9947a770573a959b13fe26661eb8874963b10cdb8ab2382d6eec811ebd8cd87322cc41
|
7
|
+
data.tar.gz: cd173c7dc66f31a90e878ed9a2da9724132286c93f2a9c168a5593f81ffbfe3c6f25161095fafe7df1e9d7c2561339ca0c4051ae856c78d8698d382e8d65818c
|
data/README.md
CHANGED
@@ -134,6 +134,19 @@ Lastly, if you override the `app_name` configuration in your Shipit deployment,
|
|
134
134
|
|
135
135
|
* * *
|
136
136
|
|
137
|
+
<h3 id="respecting-bare-files">Respecting bare <code>shipit.yml</code> files</h3>
|
138
|
+
|
139
|
+
Shipit will, by default, respect the "bare" <code>shipit.yml</code> file as a fallback option if no more specifically-named file exists (such as <code>shipit.staging.yml</code>).
|
140
|
+
|
141
|
+
You can configure this behavior via the attribute <code>Shipit.respect_bare_shipit_file</code>.
|
142
|
+
|
143
|
+
- The value <code>false</code> will disable this behavior and instead cause Shipit to emit an error upon deploy if Shipit cannot find a more specifically-named file.
|
144
|
+
- Setting this attribute to any other value (**including <code>nil</code>**), or not setting this attribute, will cause Shipit to use the default behavior of respecting bare <code>shipit.yml</code> files.
|
145
|
+
|
146
|
+
You can determine if Shipit is configured to respect bare files using <code>Shipit.respect_bare_shipit_file?</code>.
|
147
|
+
|
148
|
+
* * *
|
149
|
+
|
137
150
|
<h3 id="installing-dependencies">Installing dependencies</h3>
|
138
151
|
|
139
152
|
The **<code>dependencies</code>** step allows you to install all the packages your deploy script needs.
|
@@ -390,7 +403,7 @@ machine:
|
|
390
403
|
|
391
404
|
<h3 id="ci">CI</h3>
|
392
405
|
|
393
|
-
**<code>ci.require</code>** contains an array of the [statuses context](https://
|
406
|
+
**<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
407
|
|
395
408
|
For example:
|
396
409
|
```yml
|
@@ -399,7 +412,7 @@ ci:
|
|
399
412
|
- ci/circleci
|
400
413
|
```
|
401
414
|
|
402
|
-
**<code>ci.hide</code>** contains an array of the [statuses context](https://
|
415
|
+
**<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
416
|
|
404
417
|
For example:
|
405
418
|
```yml
|
@@ -408,7 +421,7 @@ ci:
|
|
408
421
|
- ci/circleci
|
409
422
|
```
|
410
423
|
|
411
|
-
**<code>ci.allow_failures</code>** contains an array of the [statuses context](https://
|
424
|
+
**<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
425
|
|
413
426
|
For example:
|
414
427
|
```yml
|
@@ -417,7 +430,7 @@ ci:
|
|
417
430
|
- ci/circleci
|
418
431
|
```
|
419
432
|
|
420
|
-
**<code>ci.blocking</code>** contains an array of the [statuses context](https://
|
433
|
+
**<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
434
|
|
422
435
|
For example:
|
423
436
|
```yml
|
@@ -440,7 +453,7 @@ merge:
|
|
440
453
|
revalidate_after: 12m30s
|
441
454
|
```
|
442
455
|
|
443
|
-
**<code>merge.require</code>** contains an array of the [statuses context](https://
|
456
|
+
**<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
457
|
|
445
458
|
For example:
|
446
459
|
```yml
|
@@ -449,7 +462,7 @@ merge:
|
|
449
462
|
- continuous-integration/travis-ci/push
|
450
463
|
```
|
451
464
|
|
452
|
-
**<code>merge.ignore</code>** contains an array of the [statuses context](https://
|
465
|
+
**<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
466
|
|
454
467
|
For example:
|
455
468
|
```yml
|
@@ -458,7 +471,7 @@ merge:
|
|
458
471
|
- codeclimate
|
459
472
|
```
|
460
473
|
|
461
|
-
**<code>merge.method</code>** the [merge method](https://
|
474
|
+
**<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
475
|
|
463
476
|
For example:
|
464
477
|
```yml
|
@@ -17,7 +17,11 @@ module Shipit
|
|
17
17
|
private
|
18
18
|
|
19
19
|
def force_github_authentication
|
20
|
-
if
|
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
|
-
|
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,13 @@ module Shipit
|
|
60
61
|
head(:accepted)
|
61
62
|
end
|
62
63
|
|
64
|
+
def refresh
|
65
|
+
RefreshStatusesJob.perform_later(stack_id: stack.id)
|
66
|
+
RefreshCheckRunsJob.perform_later(stack_id: stack.id)
|
67
|
+
GithubSyncJob.perform_later(stack_id: stack.id)
|
68
|
+
render_resource(stack, status: :accepted)
|
69
|
+
end
|
70
|
+
|
63
71
|
private
|
64
72
|
|
65
73
|
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:
|
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(
|
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
|
@@ -5,7 +5,11 @@ module Shipit
|
|
5
5
|
before_action :load_deploy
|
6
6
|
|
7
7
|
def create
|
8
|
-
@rollback = @deploy.trigger_rollback(
|
8
|
+
@rollback = @deploy.trigger_rollback(
|
9
|
+
current_user,
|
10
|
+
env: rollback_params[:env]&.to_unsafe_hash,
|
11
|
+
force: params[:force].present?,
|
12
|
+
)
|
9
13
|
redirect_to(stack_deploy_path(@stack, @rollback))
|
10
14
|
rescue Task::ConcurrentTaskRunning
|
11
15
|
redirect_to(rollback_stack_deploy_path(@stack, @deploy))
|
@@ -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
|
-
|
54
|
-
|
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('|') }
|
@@ -44,9 +44,9 @@ module Shipit
|
|
44
44
|
end
|
45
45
|
|
46
46
|
def write(output)
|
47
|
-
Shipit.redis.pipelined do
|
48
|
-
|
49
|
-
|
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
|
|
@@ -9,7 +9,7 @@ module Shipit
|
|
9
9
|
validates :url, presence: true, url: { no_local: true, allow_blank: true }
|
10
10
|
validates :content_type, presence: true
|
11
11
|
|
12
|
-
serialize :response_headers,
|
12
|
+
serialize :response_headers, SafeJSON
|
13
13
|
|
14
14
|
after_commit :purge_old_deliveries, on: :create
|
15
15
|
|
data/app/models/shipit/deploy.rb
CHANGED
@@ -128,6 +128,7 @@ module Shipit
|
|
128
128
|
lock_reason = "A rollback for #{until_commit.sha} has been triggered. " \
|
129
129
|
"Please make sure the reason for the rollback has been addressed before deploying again."
|
130
130
|
stack.update!(lock_reason: lock_reason, lock_author_id: user_id)
|
131
|
+
stack.emit_lock_hooks
|
131
132
|
rollback
|
132
133
|
end
|
133
134
|
|
@@ -91,10 +91,30 @@ module Shipit
|
|
91
91
|
end
|
92
92
|
|
93
93
|
def load_config
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
94
|
+
return if config_file_path.nil?
|
95
|
+
|
96
|
+
if !Shipit.respect_bare_shipit_file? && config_file_path.to_s.end_with?(*bare_shipit_filenames)
|
97
|
+
return { 'deploy' => { 'pre' => [shipit_not_obeying_bare_file_echo_command, 'exit 1'] } }
|
98
|
+
end
|
99
|
+
|
100
|
+
read_config(config_file_path)
|
101
|
+
end
|
102
|
+
|
103
|
+
def shipit_file_names_in_priority_order
|
104
|
+
["#{app_name}.#{@env}.yml", "#{app_name}.yml", "shipit.#{@env}.yml", "shipit.yml"].uniq
|
105
|
+
end
|
106
|
+
|
107
|
+
def bare_shipit_filenames
|
108
|
+
["#{app_name}.yml", "shipit.yml"].uniq
|
109
|
+
end
|
110
|
+
|
111
|
+
def config_file_path
|
112
|
+
shipit_file_names_in_priority_order.each do |filename|
|
113
|
+
path = file(filename, root: true)
|
114
|
+
return path if path.exist?
|
115
|
+
end
|
116
|
+
|
117
|
+
nil
|
98
118
|
end
|
99
119
|
|
100
120
|
def app_name
|
@@ -104,6 +124,14 @@ module Shipit
|
|
104
124
|
def read_config(path)
|
105
125
|
SafeYAML.load(path.read) if path.exist?
|
106
126
|
end
|
127
|
+
|
128
|
+
def shipit_not_obeying_bare_file_echo_command
|
129
|
+
<<~EOM
|
130
|
+
echo \"\e[1;31mShipit is configured to ignore the bare '#{app_name}.yml' file.
|
131
|
+
Please rename this file to more specifically include the environment name.
|
132
|
+
Deployments will fail until a valid '#{app_name}.#{@env}.yml' file is found.\e[0m\"
|
133
|
+
EOM
|
134
|
+
end
|
107
135
|
end
|
108
136
|
end
|
109
137
|
end
|
@@ -11,7 +11,7 @@ module Shipit
|
|
11
11
|
has_many :pull_request_assignments
|
12
12
|
has_many :assignees, class_name: :User, through: :pull_request_assignments, source: :user
|
13
13
|
|
14
|
-
serialize :labels, Array
|
14
|
+
serialize :labels, Shipit.serialized_column(:labels, type: Array)
|
15
15
|
|
16
16
|
after_create_commit :emit_create_hooks
|
17
17
|
after_update_commit :emit_update_hooks
|
data/app/models/shipit/stack.rb
CHANGED
@@ -608,6 +608,16 @@ module Shipit
|
|
608
608
|
Shipit.deployment_checks.call(self)
|
609
609
|
end
|
610
610
|
|
611
|
+
def emit_lock_hooks
|
612
|
+
return unless previous_changes.include?('lock_reason')
|
613
|
+
|
614
|
+
lock_details = if previous_changes['lock_reason'].last.blank?
|
615
|
+
{ from: previous_changes['locked_since'].first, until: Time.zone.now }
|
616
|
+
end
|
617
|
+
|
618
|
+
Hook.emit(:lock, self, locked: locked?, lock_details: lock_details, stack: self)
|
619
|
+
end
|
620
|
+
|
611
621
|
private
|
612
622
|
|
613
623
|
def clear_cache
|
@@ -641,16 +651,6 @@ module Shipit
|
|
641
651
|
end
|
642
652
|
end
|
643
653
|
|
644
|
-
def emit_lock_hooks
|
645
|
-
return unless previous_changes.include?('lock_reason')
|
646
|
-
|
647
|
-
lock_details = if previous_changes['lock_reason'].last.blank?
|
648
|
-
{ from: previous_changes['locked_since'].first, until: Time.zone.now }
|
649
|
-
end
|
650
|
-
|
651
|
-
Hook.emit(:lock, self, locked: locked?, lock_details: lock_details, stack: self)
|
652
|
-
end
|
653
|
-
|
654
654
|
def emit_added_hooks
|
655
655
|
Hook.emit(:stack, self, action: :added, stack: self)
|
656
656
|
end
|
data/app/models/shipit/task.rb
CHANGED
@@ -27,8 +27,35 @@ module Shipit
|
|
27
27
|
|
28
28
|
deferred_touch stack: :updated_at
|
29
29
|
|
30
|
+
module EnvHash
|
31
|
+
class << self
|
32
|
+
def dump(hash)
|
33
|
+
raise TypeError, "Task#env should be a Hash[String => String]" unless hash.is_a?(Hash)
|
34
|
+
hash = hash.to_h.stringify_keys
|
35
|
+
hash.transform_values! do |value|
|
36
|
+
case value
|
37
|
+
when String, Symbol, Numeric
|
38
|
+
value.to_s
|
39
|
+
else
|
40
|
+
raise TypeError, "Task#env should be a Hash[String => String]" unless hash.is_a?(Hash)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
hash unless hash.empty?
|
45
|
+
end
|
46
|
+
|
47
|
+
def load(hash)
|
48
|
+
hash&.to_h || {} # cast back to a real hash
|
49
|
+
end
|
50
|
+
|
51
|
+
def new
|
52
|
+
nil
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
30
57
|
serialize :definition, TaskDefinition
|
31
|
-
serialize :env,
|
58
|
+
serialize :env, Shipit.serialized_column(:env, coder: EnvHash)
|
32
59
|
|
33
60
|
scope :success, -> { where(status: 'success') }
|
34
61
|
scope :completed, -> { where(status: COMPLETED_STATUSES) }
|
@@ -313,9 +340,9 @@ module Shipit
|
|
313
340
|
end
|
314
341
|
|
315
342
|
def request_abort
|
316
|
-
Shipit.redis.pipelined do
|
317
|
-
|
318
|
-
|
343
|
+
Shipit.redis.pipelined do |pipeline|
|
344
|
+
pipeline.incr(abort_key)
|
345
|
+
pipeline.expire(abort_key, 1.month.to_i)
|
319
346
|
end
|
320
347
|
end
|
321
348
|
|
data/app/models/shipit/user.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
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>
|