shipit-engine 0.32.0 → 0.35.1
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 +13 -2
- data/app/assets/images/magic-solid.svg +1 -0
- data/app/assets/javascripts/shipit/repositories_search.js.coffee +60 -0
- data/app/assets/javascripts/shipit/{search.js.coffee → stack_search.js.coffee} +0 -0
- data/app/assets/stylesheets/_pages/_deploy.scss +2 -3
- data/app/assets/stylesheets/_pages/_repositories.scss +148 -0
- data/app/assets/stylesheets/_pages/_stacks.scss +19 -0
- data/app/assets/stylesheets/shipit.scss +1 -0
- data/app/controllers/shipit/api/ccmenu_controller.rb +1 -1
- data/app/controllers/shipit/api/deploys_controller.rb +2 -0
- data/app/controllers/shipit/api/{pull_requests_controller.rb → merge_requests_controller.rb} +8 -8
- data/app/controllers/shipit/api/rollbacks_controller.rb +2 -1
- data/app/controllers/shipit/api/stacks_controller.rb +15 -1
- data/app/controllers/shipit/deploys_controller.rb +1 -1
- data/app/controllers/shipit/merge_requests_controller.rb +31 -0
- data/app/controllers/shipit/merge_status_controller.rb +15 -15
- data/app/controllers/shipit/repositories_controller.rb +74 -0
- data/app/controllers/shipit/stacks_controller.rb +2 -2
- data/app/controllers/shipit/tasks_controller.rb +2 -2
- data/app/controllers/shipit/webhooks_controller.rb +23 -4
- data/app/helpers/shipit/chunks_helper.rb +2 -2
- data/app/helpers/shipit/github_url_helper.rb +8 -0
- data/app/helpers/shipit/shipit_helper.rb +0 -1
- data/app/helpers/shipit/stacks_helper.rb +4 -0
- data/app/jobs/shipit/create_on_github_job.rb +1 -0
- data/app/jobs/shipit/deliver_hook_job.rb +1 -1
- data/app/jobs/shipit/destroy_repository_job.rb +24 -0
- data/app/jobs/shipit/destroy_stack_job.rb +2 -2
- data/app/jobs/shipit/github_sync_job.rb +13 -9
- data/app/jobs/shipit/perform_task_job.rb +4 -98
- data/app/jobs/shipit/process_merge_requests_job.rb +32 -0
- data/app/jobs/shipit/refresh_merge_request_job.rb +11 -0
- data/app/jobs/shipit/update_github_last_deployed_ref_job.rb +1 -1
- data/app/models/shipit/anonymous_user.rb +10 -2
- data/app/models/shipit/check_run.rb +38 -2
- data/app/models/shipit/command_line_user.rb +4 -0
- data/app/models/shipit/commit.rb +31 -20
- data/app/models/shipit/commit_checks.rb +14 -13
- data/app/models/shipit/commit_deployment.rb +3 -3
- data/app/models/shipit/commit_deployment_status.rb +3 -3
- data/app/models/shipit/deploy.rb +17 -11
- data/app/models/shipit/deploy_spec/file_system.rb +11 -5
- data/app/models/shipit/deploy_spec/lerna_discovery.rb +12 -4
- data/app/models/shipit/deploy_spec.rb +16 -4
- data/app/models/shipit/duration.rb +2 -0
- data/app/models/shipit/hook.rb +28 -2
- data/app/models/shipit/merge_request.rb +304 -0
- data/app/models/shipit/provisioning_handler/base.rb +30 -0
- data/app/models/shipit/provisioning_handler/unregistered_provisioning_handler.rb +35 -0
- data/app/models/shipit/provisioning_handler.rb +32 -0
- data/app/models/shipit/pull_request.rb +26 -265
- data/app/models/shipit/pull_request_assignment.rb +10 -0
- data/app/models/shipit/release_status.rb +1 -1
- data/app/models/shipit/repository.rb +63 -3
- data/app/models/shipit/review_stack.rb +130 -0
- data/app/models/shipit/review_stack_provisioning_queue.rb +39 -0
- data/app/models/shipit/rollback.rb +5 -0
- data/app/models/shipit/stack.rb +78 -30
- data/app/models/shipit/status/group.rb +1 -1
- data/app/models/shipit/task.rb +62 -9
- data/app/models/shipit/task_execution_strategy/base.rb +20 -0
- data/app/models/shipit/task_execution_strategy/default.rb +109 -0
- data/app/models/shipit/team.rb +4 -2
- data/app/models/shipit/user.rb +10 -1
- data/app/models/shipit/webhooks/handlers/pull_request/assigned_handler.rb +74 -0
- data/app/models/shipit/webhooks/handlers/pull_request/closed_handler.rb +68 -0
- data/app/models/shipit/webhooks/handlers/pull_request/edited_handler.rb +74 -0
- data/app/models/shipit/webhooks/handlers/pull_request/label_capturing_handler.rb +127 -0
- data/app/models/shipit/webhooks/handlers/pull_request/labeled_handler.rb +106 -0
- data/app/models/shipit/webhooks/handlers/pull_request/opened_handler.rb +83 -0
- data/app/models/shipit/webhooks/handlers/pull_request/reopened_handler.rb +88 -0
- data/app/models/shipit/webhooks/handlers/pull_request/review_stack_adapter.rb +103 -0
- data/app/models/shipit/webhooks/handlers/pull_request/unlabeled_handler.rb +107 -0
- data/app/models/shipit/webhooks/handlers/push_handler.rb +4 -1
- data/app/models/shipit/webhooks.rb +10 -0
- data/app/serializers/shipit/deploy_serializer.rb +6 -0
- data/app/serializers/shipit/merge_request_serializer.rb +21 -0
- data/app/serializers/shipit/pull_request_serializer.rb +5 -8
- data/app/serializers/shipit/review_stack_serializer.rb +7 -0
- data/app/serializers/shipit/stack_serializer.rb +7 -6
- data/app/serializers/shipit/tail_task_serializer.rb +10 -2
- data/app/serializers/shipit/task_serializer.rb +1 -1
- data/app/validators/subset_validator.rb +1 -1
- data/app/views/layouts/merge_status.html.erb +1 -1
- data/app/views/shipit/merge_requests/_merge_request.html.erb +29 -0
- data/app/views/shipit/{pull_requests → merge_requests}/index.html.erb +2 -2
- data/app/views/shipit/merge_requests/merge_requests/_pull_request.html.erb +29 -0
- data/app/views/shipit/merge_requests/merge_requests/index.html.erb +20 -0
- data/app/views/shipit/merge_status/_merge_queue_button.html.erb +3 -3
- data/app/views/shipit/merge_status/backlogged.html.erb +1 -1
- data/app/views/shipit/merge_status/failure.html.erb +1 -1
- data/app/views/shipit/merge_status/locked.html.erb +1 -1
- data/app/views/shipit/merge_status/success.html.erb +2 -2
- data/app/views/shipit/repositories/_header.html.erb +19 -0
- data/app/views/shipit/repositories/index.html.erb +31 -0
- data/app/views/shipit/repositories/new.html.erb +23 -0
- data/app/views/shipit/repositories/settings.html.erb +53 -0
- data/app/views/shipit/repositories/show.html.erb +30 -0
- data/app/views/shipit/stacks/_banners.html.erb +15 -1
- data/app/views/shipit/stacks/_header.html.erb +5 -2
- data/app/views/shipit/stacks/_stack.html.erb +8 -0
- data/app/views/shipit/stacks/index.html.erb +2 -1
- data/app/views/shipit/stacks/new.html.erb +1 -1
- data/app/views/shipit/stacks/settings.html.erb +5 -5
- data/app/views/shipit/stacks/show.html.erb +1 -1
- data/app/views/shipit/tasks/_task_output.html.erb +1 -1
- data/config/routes.rb +15 -5
- data/config/secrets.development.example.yml +24 -0
- data/config/secrets.development.shopify.yml +20 -9
- data/db/migrate/20200706145406_add_review_stacks.rb +12 -0
- data/db/migrate/20200804144639_rename_pull_request_to_merge_request.rb +7 -0
- data/db/migrate/20200804161512_rename_commits_pull_request_id_to_merge_request_id.rb +5 -0
- data/db/migrate/20200813134712_recreate_shipit_pull_requests.rb +22 -0
- data/db/migrate/20200813194056_create_pull_request_assignments.rb +8 -0
- data/db/migrate/20201001125502_add_provision_pr_stacks_flag_to_repositories.rb +7 -0
- data/db/migrate/20201008145809_add_retry_attempt_to_tasks.rb +5 -0
- data/db/migrate/20201008152744_add_max_retries_to_tasks.rb +5 -0
- data/db/migrate/20210325194053_remove_stacks_branch_default.rb +5 -0
- data/db/migrate/20210504200438_add_github_updated_at_to_check_runs.rb +5 -0
- data/db/migrate/20210823075617_change_check_runs_github_updated_at_default.rb +5 -0
- data/lib/shipit/command.rb +7 -6
- data/lib/shipit/commands.rb +18 -5
- data/lib/shipit/engine.rb +2 -0
- data/lib/shipit/flock.rb +8 -1
- data/lib/shipit/github_app.rb +8 -6
- data/lib/shipit/octokit_iterator.rb +3 -3
- data/lib/shipit/review_stack_commands.rb +8 -0
- data/lib/shipit/simple_message_verifier.rb +2 -2
- data/lib/shipit/stack_commands.rb +36 -7
- data/lib/shipit/task_commands.rb +8 -1
- data/lib/shipit/version.rb +1 -1
- data/lib/shipit.rb +50 -16
- data/lib/snippets/publish-lerna-independent-packages +35 -34
- data/lib/snippets/publish-lerna-independent-packages-legacy +39 -0
- data/lib/tasks/cron.rake +11 -2
- data/test/controllers/api/ccmenu_controller_test.rb +1 -1
- data/test/controllers/api/deploys_controller_test.rb +17 -0
- data/test/controllers/api/{pull_requests_controller_test.rb → merge_requests_controller_test.rb} +12 -12
- data/test/controllers/api/outputs_controller_test.rb +1 -0
- data/test/controllers/api/rollback_controller_test.rb +1 -1
- data/test/controllers/api/stacks_controller_test.rb +42 -8
- data/test/controllers/{pull_requests_controller_test.rb → merge_requests_controller_test.rb} +6 -6
- data/test/controllers/repositories_controller_test.rb +71 -0
- data/test/controllers/stacks_controller_test.rb +9 -1
- data/test/controllers/tasks_controller_test.rb +14 -2
- data/test/controllers/webhooks_controller_test.rb +27 -12
- data/test/dummy/app/assets/config/manifest.js +3 -0
- data/test/dummy/config/application.rb +7 -2
- data/test/dummy/config/database.yml +9 -0
- data/test/dummy/config/environments/development.rb +1 -4
- data/test/dummy/config/environments/test.rb +0 -5
- data/test/dummy/config/secrets_double_github_app.yml +79 -0
- data/test/dummy/db/schema.rb +56 -17
- data/test/dummy/db/seeds.rb +2 -1
- data/test/fixtures/payloads/check_suite_master.json +4 -32
- data/test/fixtures/payloads/invalid_pull_request.json +117 -0
- data/test/fixtures/payloads/provision_disabled_pull_request.json +454 -0
- data/test/fixtures/payloads/pull_request_assigned.json +480 -0
- data/test/fixtures/payloads/pull_request_closed.json +454 -0
- data/test/fixtures/payloads/pull_request_labeled.json +461 -0
- data/test/fixtures/payloads/pull_request_opened.json +454 -0
- data/test/fixtures/payloads/pull_request_reopened.json +454 -0
- data/test/fixtures/payloads/pull_request_unlabeled.json +454 -0
- data/test/fixtures/payloads/pull_request_with_no_repo.json +454 -0
- data/test/fixtures/payloads/push_master.json +1 -1
- data/test/fixtures/payloads/push_not_master.json +1 -1
- data/test/fixtures/shipit/commits.yml +17 -4
- data/test/fixtures/shipit/hooks.yml +1 -0
- data/test/fixtures/shipit/merge_requests.yml +141 -0
- data/test/fixtures/shipit/pull_request_assignments.yml +3 -0
- data/test/fixtures/shipit/pull_requests.yml +10 -131
- data/test/fixtures/shipit/repositories.yml +1 -0
- data/test/fixtures/shipit/stacks.yml +145 -0
- data/test/fixtures/shipit/statuses.yml +9 -0
- data/test/fixtures/shipit/tasks.yml +4 -1
- data/test/fixtures/shipit/users.yml +7 -0
- data/test/helpers/json_helper.rb +5 -1
- data/test/helpers/payloads_helper.rb +4 -0
- data/test/jobs/chunk_rollup_job_test.rb +15 -1
- data/test/jobs/destroy_repository_job_test.rb +27 -0
- data/test/jobs/github_sync_job_test.rb +2 -1
- data/test/jobs/perform_task_job_test.rb +8 -8
- data/test/jobs/{merge_pull_requests_job_test.rb → process_merge_requests_job_test.rb} +18 -18
- data/test/lib/shipit/deploy_commands_test.rb +16 -0
- data/test/lib/shipit/task_commands_test.rb +17 -0
- data/test/models/commit_deployment_status_test.rb +3 -3
- data/test/models/commits_test.rb +24 -13
- data/test/models/deploy_spec_test.rb +64 -24
- data/test/models/deploys_test.rb +188 -14
- data/test/models/hook_test.rb +30 -1
- data/test/models/{pull_request_test.rb → merge_request_test.rb} +49 -34
- data/test/models/pull_request_assignment_test.rb +16 -0
- data/test/models/shipit/check_run_test.rb +124 -5
- data/test/models/shipit/provisioning_handler/base_test.rb +33 -0
- data/test/models/shipit/provisioning_handler/unregistered_provisioning_handler_test.rb +49 -0
- data/test/models/shipit/provisioning_handler_test.rb +64 -0
- data/test/models/shipit/pull_request_test.rb +52 -0
- data/test/models/shipit/repository_test.rb +5 -1
- data/test/models/shipit/review_stack_provision_status_test.rb +77 -0
- data/test/models/shipit/review_stack_provisioning_queue_test.rb +63 -0
- data/test/models/shipit/review_stack_test.rb +91 -0
- data/test/models/{stacks_test.rb → shipit/stacks_test.rb} +52 -8
- data/test/models/shipit/webhooks/handlers/pull_request/assigned_handler_test.rb +45 -0
- data/test/models/shipit/webhooks/handlers/pull_request/closed_handler_test.rb +192 -0
- data/test/models/shipit/webhooks/handlers/pull_request/edited_handler_test.rb +47 -0
- data/test/models/shipit/webhooks/handlers/pull_request/label_capturing_handler_test.rb +209 -0
- data/test/models/shipit/webhooks/handlers/pull_request/labeled_handler_test.rb +332 -0
- data/test/models/shipit/webhooks/handlers/pull_request/opened_handler_test.rb +238 -0
- data/test/models/shipit/webhooks/handlers/pull_request/reopened_handler_test.rb +282 -0
- data/test/models/shipit/webhooks/handlers/pull_request/review_stack_adapter_test.rb +107 -0
- data/test/models/shipit/webhooks/handlers/pull_request/unlabeled_handler_test.rb +324 -0
- data/test/models/shipit/{wehbooks → webhooks}/handlers_test.rb +0 -0
- data/test/models/tasks_test.rb +66 -3
- data/test/serializers/shipit/pull_request_serializer_test.rb +29 -0
- data/test/test_helper.rb +15 -0
- data/test/unit/anonymous_user_serializer_test.rb +1 -1
- data/test/unit/command_test.rb +8 -3
- data/test/unit/commit_serializer_test.rb +1 -1
- data/test/unit/deploy_commands_test.rb +73 -17
- data/test/unit/deploy_serializer_test.rb +1 -1
- data/test/unit/github_app_test.rb +2 -3
- data/test/unit/github_apps_test.rb +416 -0
- data/test/unit/github_url_helper_test.rb +5 -0
- data/test/unit/shipit_deployment_checks_test.rb +77 -0
- data/test/unit/shipit_task_execution_strategy_test.rb +47 -0
- data/test/unit/shipit_test.rb +14 -0
- data/test/unit/user_serializer_test.rb +1 -1
- metadata +306 -188
- data/app/controllers/shipit/pull_requests_controller.rb +0 -31
- data/app/jobs/shipit/merge_pull_requests_job.rb +0 -32
- data/app/jobs/shipit/refresh_pull_request_job.rb +0 -11
- data/app/views/shipit/pull_requests/_pull_request.html.erb +0 -29
- data/test/fixtures/shipit/output_chunks.yml +0 -47
- data/test/models/output_chunk_test.rb +0 -21
|
@@ -4,104 +4,10 @@ module Shipit
|
|
|
4
4
|
queue_as :deploys
|
|
5
5
|
|
|
6
6
|
def perform(task)
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
return
|
|
12
|
-
end
|
|
13
|
-
run
|
|
14
|
-
ensure
|
|
15
|
-
@commands.clear_working_directory
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def run
|
|
19
|
-
@task.ping
|
|
20
|
-
@task.run!
|
|
21
|
-
checkout_repository
|
|
22
|
-
perform_task
|
|
23
|
-
@task.write("\nCompleted successfully\n")
|
|
24
|
-
@task.report_complete!
|
|
25
|
-
rescue Command::TimedOut => error
|
|
26
|
-
@task.write("\n#{error.message}\n")
|
|
27
|
-
@task.report_timeout!(error)
|
|
28
|
-
rescue Command::Error => error
|
|
29
|
-
@task.write("\n#{error.message}\n")
|
|
30
|
-
@task.report_failure!(error)
|
|
31
|
-
rescue StandardError => error
|
|
32
|
-
@task.report_error!(error)
|
|
33
|
-
rescue Exception => error
|
|
34
|
-
@task.report_error!(error)
|
|
35
|
-
raise
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
def abort!(signal: 'TERM')
|
|
39
|
-
pid = @task.pid
|
|
40
|
-
if pid
|
|
41
|
-
@task.write("$ kill #{pid}\n")
|
|
42
|
-
Process.kill(signal, pid)
|
|
43
|
-
else
|
|
44
|
-
@task.write("Can't abort, no recorded pid, WTF?\n")
|
|
45
|
-
end
|
|
46
|
-
rescue SystemCallError => error
|
|
47
|
-
@task.write("kill: (#{pid}) - #{error.message}\n")
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
def check_for_abort
|
|
51
|
-
@task.should_abort? do |times_killed|
|
|
52
|
-
if times_killed > 3
|
|
53
|
-
abort!(signal: 'KILL')
|
|
54
|
-
else
|
|
55
|
-
abort!
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
def perform_task
|
|
61
|
-
capture_all!(@commands.install_dependencies)
|
|
62
|
-
capture_all!(@commands.perform)
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
def checkout_repository
|
|
66
|
-
unless @commands.fetched?(@task.until_commit).tap(&:run).success?
|
|
67
|
-
# acquire_git_cache_lock can take upto 15 seconds
|
|
68
|
-
# to process. Try to make sure that the job isn't
|
|
69
|
-
# marked dead while we attempt to acquire the lock.
|
|
70
|
-
@task.ping
|
|
71
|
-
@task.acquire_git_cache_lock do
|
|
72
|
-
@task.ping
|
|
73
|
-
unless @commands.fetched?(@task.until_commit).tap(&:run).success?
|
|
74
|
-
capture!(@commands.fetch)
|
|
75
|
-
end
|
|
76
|
-
end
|
|
77
|
-
end
|
|
78
|
-
capture_all!(@commands.clone)
|
|
79
|
-
capture!(@commands.checkout(@task.until_commit))
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
def capture_all!(commands)
|
|
83
|
-
commands.map { |c| capture!(c) }
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
def capture!(command)
|
|
87
|
-
command.start do
|
|
88
|
-
@task.ping
|
|
89
|
-
check_for_abort
|
|
90
|
-
end
|
|
91
|
-
@task.write("$ #{command}\npid: #{command.pid}\n")
|
|
92
|
-
@task.pid = command.pid
|
|
93
|
-
command.stream! do |line|
|
|
94
|
-
@task.write(line)
|
|
95
|
-
end
|
|
96
|
-
@task.write("\n")
|
|
97
|
-
command.success?
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
def capture(command)
|
|
101
|
-
capture!(command)
|
|
102
|
-
command.success?
|
|
103
|
-
rescue Command::Error
|
|
104
|
-
false
|
|
7
|
+
Shipit
|
|
8
|
+
.task_execution_strategy
|
|
9
|
+
.new(task)
|
|
10
|
+
.execute
|
|
105
11
|
end
|
|
106
12
|
end
|
|
107
13
|
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
module Shipit
|
|
3
|
+
class ProcessMergeRequestsJob < BackgroundJob
|
|
4
|
+
include BackgroundJob::Unique
|
|
5
|
+
on_duplicate :drop
|
|
6
|
+
|
|
7
|
+
queue_as :default
|
|
8
|
+
|
|
9
|
+
def perform(stack)
|
|
10
|
+
merge_requests = stack.merge_requests.to_be_merged.to_a
|
|
11
|
+
merge_requests.each do |merge_request|
|
|
12
|
+
merge_request.refresh!
|
|
13
|
+
merge_request.reject_unless_mergeable!
|
|
14
|
+
merge_request.cancel! if merge_request.closed?
|
|
15
|
+
merge_request.revalidate! if merge_request.need_revalidation?
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
return false unless stack.allows_merges?
|
|
19
|
+
|
|
20
|
+
merge_requests.select(&:pending?).each do |merge_request|
|
|
21
|
+
merge_request.refresh!
|
|
22
|
+
next unless merge_request.all_status_checks_passed?
|
|
23
|
+
begin
|
|
24
|
+
merge_request.merge!
|
|
25
|
+
rescue MergeRequest::NotReady
|
|
26
|
+
ProcessMergeRequestsJob.set(wait: 10.seconds).perform_later(stack)
|
|
27
|
+
return false
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
module Shipit
|
|
3
3
|
class AnonymousUser
|
|
4
|
-
def
|
|
5
|
-
|
|
4
|
+
def blank?
|
|
5
|
+
true
|
|
6
6
|
end
|
|
7
7
|
|
|
8
8
|
def email
|
|
@@ -35,6 +35,10 @@ module Shipit
|
|
|
35
35
|
Shipit.authentication_disabled?
|
|
36
36
|
end
|
|
37
37
|
|
|
38
|
+
def repositories_contributed_to
|
|
39
|
+
[]
|
|
40
|
+
end
|
|
41
|
+
|
|
38
42
|
def stacks_contributed_to
|
|
39
43
|
[]
|
|
40
44
|
end
|
|
@@ -59,5 +63,9 @@ module Shipit
|
|
|
59
63
|
def serializer_class
|
|
60
64
|
AnonymousUserSerializer
|
|
61
65
|
end
|
|
66
|
+
|
|
67
|
+
def marked_for_destruction?
|
|
68
|
+
true
|
|
69
|
+
end
|
|
62
70
|
end
|
|
63
71
|
end
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
module Shipit
|
|
3
3
|
class CheckRun < ApplicationRecord
|
|
4
|
-
CONCLUSIONS = %w(success failure neutral cancelled timed_out action_required stale).freeze
|
|
4
|
+
CONCLUSIONS = %w(success failure neutral cancelled timed_out action_required stale skipped).freeze
|
|
5
5
|
include DeferredTouch
|
|
6
6
|
include Status::Common
|
|
7
7
|
|
|
8
|
+
CHECK_RUN_REFRESH_DELAY = 5.seconds
|
|
9
|
+
|
|
8
10
|
belongs_to :stack, required: true
|
|
9
11
|
belongs_to :commit, required: true
|
|
10
12
|
|
|
@@ -19,11 +21,30 @@ module Shipit
|
|
|
19
21
|
create!(selector.merge(attributes))
|
|
20
22
|
rescue ActiveRecord::RecordNotUnique
|
|
21
23
|
record = find_by!(selector)
|
|
24
|
+
|
|
25
|
+
# Checkruns can jump between states and conclusions, and the github timestamps are low precision and unreliable.
|
|
26
|
+
# Since there's a conflict and the webhook seems older, enqueue a refresh.
|
|
27
|
+
# Persist the received data anyways, in case it is now the canonical data on GitHub despite the timestamp.
|
|
28
|
+
if attributes[:conclusion] != record.conclusion && record.newer_than_webhook?(attributes)
|
|
29
|
+
Rails.logger.warn(
|
|
30
|
+
"Conflicting stale checkrun received. Checkrun id: #{selector[:github_id]}, Details: #{attributes}"
|
|
31
|
+
)
|
|
32
|
+
RefreshCheckRunsJob.set(wait: CHECK_RUN_REFRESH_DELAY).perform_later(commit_id: record.commit_id)
|
|
33
|
+
end
|
|
34
|
+
|
|
22
35
|
record.update!(attributes)
|
|
23
36
|
record
|
|
24
37
|
end
|
|
25
38
|
|
|
26
39
|
def create_or_update_from_github!(stack_id, github_check_run)
|
|
40
|
+
checkrun_date = parse_newest_date(github_check_run)
|
|
41
|
+
|
|
42
|
+
unless checkrun_date
|
|
43
|
+
Rails.logger.warn("No valid timestamp found in checkrun data. Checkrun id: #{github_check_run.id}.")
|
|
44
|
+
RefreshCheckRunsJob.set(wait: CHECK_RUN_REFRESH_DELAY).perform_later(stack_id: stack_id)
|
|
45
|
+
return
|
|
46
|
+
end
|
|
47
|
+
|
|
27
48
|
create_or_update_by!(
|
|
28
49
|
selector: {
|
|
29
50
|
github_id: github_check_run.id,
|
|
@@ -35,16 +56,27 @@ module Shipit
|
|
|
35
56
|
title: github_check_run.output.title.to_s.truncate(1_000),
|
|
36
57
|
details_url: github_check_run.details_url,
|
|
37
58
|
html_url: github_check_run.html_url,
|
|
59
|
+
github_updated_at: checkrun_date,
|
|
38
60
|
},
|
|
39
61
|
)
|
|
40
62
|
end
|
|
63
|
+
|
|
64
|
+
def parse_newest_date(github_check_run)
|
|
65
|
+
started_at = github_check_run.started_at
|
|
66
|
+
completed_at = github_check_run.completed_at
|
|
67
|
+
|
|
68
|
+
started_at_date = Time.parse(started_at.to_s) if started_at
|
|
69
|
+
completed_at_date = Time.parse(completed_at.to_s) if completed_at
|
|
70
|
+
|
|
71
|
+
[started_at_date, completed_at_date].compact.max
|
|
72
|
+
end
|
|
41
73
|
end
|
|
42
74
|
|
|
43
75
|
def state
|
|
44
76
|
case conclusion
|
|
45
77
|
when nil, 'action_required'
|
|
46
78
|
'pending'
|
|
47
|
-
when 'success', 'neutral'
|
|
79
|
+
when 'success', 'neutral', 'skipped'
|
|
48
80
|
'success'
|
|
49
81
|
when 'failure', 'cancelled', 'stale'
|
|
50
82
|
'failure'
|
|
@@ -71,6 +103,10 @@ module Shipit
|
|
|
71
103
|
'shipit/statuses/status'
|
|
72
104
|
end
|
|
73
105
|
|
|
106
|
+
def newer_than_webhook?(webhook_attributes)
|
|
107
|
+
github_updated_at && github_updated_at >= webhook_attributes[:github_updated_at]
|
|
108
|
+
end
|
|
109
|
+
|
|
74
110
|
private
|
|
75
111
|
|
|
76
112
|
def enable_ci_on_stack
|
data/app/models/shipit/commit.rb
CHANGED
|
@@ -8,42 +8,53 @@ module Shipit
|
|
|
8
8
|
AmbiguousRevision = Class.new(StandardError)
|
|
9
9
|
|
|
10
10
|
belongs_to :stack
|
|
11
|
-
has_many :deploys
|
|
12
11
|
has_many :statuses, -> { order(created_at: :desc) }, dependent: :destroy, inverse_of: :commit
|
|
13
12
|
has_many :check_runs, -> { order(created_at: :desc) }, dependent: :destroy, inverse_of: :commit
|
|
14
13
|
has_many :commit_deployments, dependent: :destroy
|
|
15
14
|
has_many :release_statuses, dependent: :destroy
|
|
16
|
-
belongs_to :
|
|
15
|
+
belongs_to :merge_request, inverse_of: :merge_commit, optional: true
|
|
17
16
|
|
|
18
17
|
deferred_touch stack: :updated_at
|
|
19
18
|
|
|
20
|
-
before_create :
|
|
19
|
+
before_create :identify_merge_request
|
|
21
20
|
after_commit { broadcast_update }
|
|
22
21
|
after_create { stack.update_undeployed_commits_count }
|
|
23
22
|
|
|
24
23
|
after_commit :schedule_refresh_statuses!, :schedule_refresh_check_runs!, :schedule_fetch_stats!,
|
|
25
|
-
|
|
24
|
+
:schedule_continuous_delivery, on: :create
|
|
26
25
|
|
|
27
|
-
belongs_to :author, class_name: 'User', inverse_of: :authored_commits
|
|
28
|
-
belongs_to :committer, class_name: 'User', inverse_of: :commits
|
|
29
|
-
belongs_to :lock_author, class_name:
|
|
26
|
+
belongs_to :author, class_name: 'User', optional: true, inverse_of: :authored_commits
|
|
27
|
+
belongs_to :committer, class_name: 'User', optional: true, inverse_of: :commits
|
|
28
|
+
belongs_to :lock_author, class_name: 'User', optional: true, inverse_of: false
|
|
30
29
|
|
|
31
30
|
def author
|
|
32
31
|
super || AnonymousUser.new
|
|
33
32
|
end
|
|
34
33
|
|
|
34
|
+
def author=(user)
|
|
35
|
+
super(user.presence)
|
|
36
|
+
end
|
|
37
|
+
|
|
35
38
|
def committer
|
|
36
39
|
super || AnonymousUser.new
|
|
37
40
|
end
|
|
38
41
|
|
|
42
|
+
def committer=(user)
|
|
43
|
+
super(user.presence)
|
|
44
|
+
end
|
|
45
|
+
|
|
39
46
|
def lock_author
|
|
40
47
|
super || AnonymousUser.new
|
|
41
48
|
end
|
|
42
49
|
|
|
50
|
+
def lock_author=(user)
|
|
51
|
+
super(user.presence)
|
|
52
|
+
end
|
|
53
|
+
|
|
43
54
|
scope :reachable, -> { where(detached: false) }
|
|
44
55
|
|
|
45
56
|
delegate :broadcast_update, :github_repo_name, :hidden_statuses, :required_statuses, :blocking_statuses,
|
|
46
|
-
|
|
57
|
+
:soft_failing_statuses, to: :stack
|
|
47
58
|
|
|
48
59
|
def self.newer_than(commit)
|
|
49
60
|
return all unless commit
|
|
@@ -113,7 +124,7 @@ module Shipit
|
|
|
113
124
|
|
|
114
125
|
def message=(message)
|
|
115
126
|
limit = self.class.columns_hash['message'].limit
|
|
116
|
-
if limit && message && message.
|
|
127
|
+
if limit && message && message.bytesize > limit
|
|
117
128
|
message = message.truncate_bytes(limit)
|
|
118
129
|
end
|
|
119
130
|
super(message)
|
|
@@ -144,7 +155,7 @@ module Shipit
|
|
|
144
155
|
|
|
145
156
|
def refresh_statuses!
|
|
146
157
|
github_statuses = stack.handle_github_redirections do
|
|
147
|
-
|
|
158
|
+
stack.github_api.statuses(github_repo_name, sha, per_page: 100)
|
|
148
159
|
end
|
|
149
160
|
github_statuses.each do |status|
|
|
150
161
|
create_status_from_github!(status)
|
|
@@ -159,7 +170,7 @@ module Shipit
|
|
|
159
170
|
|
|
160
171
|
def refresh_check_runs!
|
|
161
172
|
response = stack.handle_github_redirections do
|
|
162
|
-
|
|
173
|
+
stack.github_api.check_runs(github_repo_name, sha)
|
|
163
174
|
end
|
|
164
175
|
response.check_runs.each do |check_run|
|
|
165
176
|
create_or_update_check_run_from_github!(check_run)
|
|
@@ -261,7 +272,7 @@ module Shipit
|
|
|
261
272
|
end
|
|
262
273
|
|
|
263
274
|
def github_commit
|
|
264
|
-
@github_commit ||=
|
|
275
|
+
@github_commit ||= stack.github_api.commit(github_repo_name, sha)
|
|
265
276
|
end
|
|
266
277
|
|
|
267
278
|
def schedule_fetch_stats!
|
|
@@ -287,13 +298,13 @@ module Shipit
|
|
|
287
298
|
stack.deploys.unsuccessful.where(until_commit_id: id).any?
|
|
288
299
|
end
|
|
289
300
|
|
|
290
|
-
def
|
|
301
|
+
def identify_merge_request
|
|
291
302
|
return unless message_parser.pull_request?
|
|
292
|
-
if
|
|
293
|
-
self.
|
|
294
|
-
self.pull_request_number =
|
|
295
|
-
self.pull_request_title =
|
|
296
|
-
self.author =
|
|
303
|
+
if merge_request = stack.merge_requests.find_by(number: message_parser.pull_request_number)
|
|
304
|
+
self.merge_request = merge_request
|
|
305
|
+
self.pull_request_number = merge_request.number
|
|
306
|
+
self.pull_request_title = merge_request.title
|
|
307
|
+
self.author = merge_request.merge_requested_by if merge_request.merge_requested_by
|
|
297
308
|
end
|
|
298
309
|
|
|
299
310
|
self.pull_request_number = message_parser.pull_request_number unless self[:pull_request_number]
|
|
@@ -301,8 +312,8 @@ module Shipit
|
|
|
301
312
|
end
|
|
302
313
|
|
|
303
314
|
def deploy_requested_at
|
|
304
|
-
if
|
|
305
|
-
|
|
315
|
+
if merge_request&.merged?
|
|
316
|
+
merge_request.merge_requested_at
|
|
306
317
|
else
|
|
307
318
|
created_at
|
|
308
319
|
end
|
|
@@ -6,17 +6,18 @@ module Shipit
|
|
|
6
6
|
|
|
7
7
|
def initialize(commit)
|
|
8
8
|
@commit = commit
|
|
9
|
+
super(commit)
|
|
9
10
|
end
|
|
10
11
|
|
|
11
12
|
def synchronize(&block)
|
|
12
|
-
@lock ||= Redis::Lock.new('lock', redis, expiration: 1, timeout: 2)
|
|
13
|
+
@lock ||= Redis::Lock.new(key('lock'), Shipit.redis, expiration: 1, timeout: 2)
|
|
13
14
|
@lock.lock(&block)
|
|
14
15
|
end
|
|
15
16
|
|
|
16
17
|
def schedule
|
|
17
|
-
return false if redis.get('status').present?
|
|
18
|
+
return false if Shipit.redis.get(key('status')).present?
|
|
18
19
|
synchronize do
|
|
19
|
-
return false if redis.get('status').present?
|
|
20
|
+
return false if Shipit.redis.get(key('status')).present?
|
|
20
21
|
|
|
21
22
|
initialize_redis_state
|
|
22
23
|
end
|
|
@@ -25,34 +26,34 @@ module Shipit
|
|
|
25
26
|
end
|
|
26
27
|
|
|
27
28
|
def initialize_redis_state
|
|
28
|
-
redis.
|
|
29
|
-
redis.set('output', '', ex: OUTPUT_TTL)
|
|
30
|
-
redis.set('status', 'scheduled', ex: OUTPUT_TTL)
|
|
31
|
-
end
|
|
29
|
+
Shipit.redis.set(key('status'), 'scheduled', ex: OUTPUT_TTL)
|
|
32
30
|
@status = 'scheduled'
|
|
33
31
|
end
|
|
34
32
|
|
|
35
33
|
def status
|
|
36
|
-
@status ||= redis.get('status')
|
|
34
|
+
@status ||= Shipit.redis.get(key('status'))
|
|
37
35
|
end
|
|
38
36
|
|
|
39
37
|
def status=(status)
|
|
40
|
-
redis.set('status', status)
|
|
38
|
+
Shipit.redis.set(key('status'), status)
|
|
41
39
|
@status = status
|
|
42
40
|
end
|
|
43
41
|
|
|
44
42
|
def output(since: 0)
|
|
45
|
-
redis.getrange('output', since, -1)
|
|
43
|
+
Shipit.redis.getrange(key('output'), since, -1)
|
|
46
44
|
end
|
|
47
45
|
|
|
48
46
|
def write(output)
|
|
49
|
-
redis.
|
|
47
|
+
Shipit.redis.pipelined do
|
|
48
|
+
Shipit.redis.append(key('output'), output)
|
|
49
|
+
Shipit.redis.expire(key('output'), OUTPUT_TTL)
|
|
50
|
+
end
|
|
50
51
|
end
|
|
51
52
|
|
|
52
53
|
private
|
|
53
54
|
|
|
54
|
-
def
|
|
55
|
-
|
|
55
|
+
def key(key)
|
|
56
|
+
"commit:#{commit.id}:checks:#{key}"
|
|
56
57
|
end
|
|
57
58
|
end
|
|
58
59
|
end
|