shipit-engine 0.28.0 → 0.32.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 +41 -2
- data/Rakefile +4 -2
- data/app/assets/images/archive-solid.svg +1 -0
- data/app/assets/stylesheets/_pages/_stacks.scss +76 -3
- data/app/assets/stylesheets/_structure/_main.scss +2 -1
- data/app/assets/stylesheets/merge_status.scss +0 -3
- data/app/controllers/concerns/shipit/active_model_serializers_patch.rb +13 -0
- data/app/controllers/concerns/shipit/api/cacheable.rb +1 -0
- data/app/controllers/concerns/shipit/api/paginable.rb +3 -2
- data/app/controllers/concerns/shipit/api/rendering.rb +5 -4
- data/app/controllers/concerns/shipit/authentication.rb +3 -2
- data/app/controllers/concerns/shipit/pagination.rb +2 -1
- data/app/controllers/shipit/api/base_controller.rb +11 -6
- data/app/controllers/shipit/api/ccmenu_controller.rb +2 -1
- data/app/controllers/shipit/api/commits_controller.rb +2 -1
- data/app/controllers/shipit/api/deploys_controller.rb +4 -3
- data/app/controllers/shipit/api/hooks_controller.rb +6 -5
- data/app/controllers/shipit/api/locks_controller.rb +5 -4
- data/app/controllers/shipit/api/outputs_controller.rb +2 -1
- data/app/controllers/shipit/api/pull_requests_controller.rb +7 -6
- data/app/controllers/shipit/api/release_statuses_controller.rb +3 -2
- data/app/controllers/shipit/api/rollbacks_controller.rb +33 -0
- data/app/controllers/shipit/api/stacks_controller.rb +37 -5
- data/app/controllers/shipit/api/tasks_controller.rb +6 -5
- data/app/controllers/shipit/api_clients_controller.rb +50 -0
- data/app/controllers/shipit/ccmenu_url_controller.rb +4 -3
- data/app/controllers/shipit/commit_checks_controller.rb +2 -1
- data/app/controllers/shipit/commits_controller.rb +2 -1
- data/app/controllers/shipit/deploys_controller.rb +3 -2
- data/app/controllers/shipit/github_authentication_controller.rb +4 -3
- data/app/controllers/shipit/merge_status_controller.rb +19 -14
- data/app/controllers/shipit/pull_requests_controller.rb +3 -2
- data/app/controllers/shipit/release_statuses_controller.rb +3 -2
- data/app/controllers/shipit/rollbacks_controller.rb +3 -2
- data/app/controllers/shipit/shipit_controller.rb +2 -1
- data/app/controllers/shipit/stacks_controller.rb +78 -14
- data/app/controllers/shipit/status_controller.rb +2 -1
- data/app/controllers/shipit/tasks_controller.rb +6 -5
- data/app/controllers/shipit/webhooks_controller.rb +5 -132
- data/app/helpers/shipit/chunks_helper.rb +1 -0
- data/app/helpers/shipit/deploys_helper.rb +4 -3
- data/app/helpers/shipit/github_url_helper.rb +1 -0
- data/app/helpers/shipit/merge_status_helper.rb +1 -0
- data/app/helpers/shipit/shipit_helper.rb +1 -0
- data/app/helpers/shipit/stacks_helper.rb +5 -0
- data/app/helpers/shipit/tasks_helper.rb +1 -0
- data/app/jobs/shipit/background_job.rb +4 -0
- data/app/jobs/shipit/background_job/unique.rb +4 -1
- data/app/jobs/shipit/cache_deploy_spec_job.rb +1 -0
- data/app/jobs/shipit/chunk_rollup_job.rb +4 -0
- data/app/jobs/shipit/clear_git_cache_job.rb +1 -0
- data/app/jobs/shipit/continuous_delivery_job.rb +3 -1
- data/app/jobs/shipit/create_on_github_job.rb +6 -1
- data/app/jobs/shipit/create_release_statuses_job.rb +1 -0
- data/app/jobs/shipit/deferred_touch_job.rb +4 -0
- data/app/jobs/shipit/deliver_hook_job.rb +1 -0
- data/app/jobs/shipit/destroy_job.rb +1 -0
- data/app/jobs/shipit/destroy_stack_job.rb +3 -2
- data/app/jobs/shipit/emit_event_job.rb +2 -1
- data/app/jobs/shipit/fetch_commit_stats_job.rb +1 -0
- data/app/jobs/shipit/fetch_deployed_revision_job.rb +2 -1
- data/app/jobs/shipit/github_sync_job.rb +3 -2
- data/app/jobs/shipit/{mark_deploy_healty_job.rb → mark_deploy_healthy_job.rb} +1 -0
- data/app/jobs/shipit/merge_pull_requests_job.rb +1 -0
- data/app/jobs/shipit/perform_commit_checks_job.rb +1 -0
- data/app/jobs/shipit/perform_task_job.rb +14 -5
- data/app/jobs/shipit/purge_old_deliveries_job.rb +1 -0
- data/app/jobs/shipit/reap_dead_tasks_job.rb +21 -0
- data/app/jobs/shipit/refresh_check_runs_job.rb +1 -0
- data/app/jobs/shipit/refresh_github_user_job.rb +1 -0
- data/app/jobs/shipit/refresh_pull_request_job.rb +1 -0
- data/app/jobs/shipit/refresh_statuses_job.rb +1 -0
- data/app/jobs/shipit/setup_github_hook_job.rb +1 -0
- data/app/jobs/shipit/update_estimated_deploy_duration_job.rb +1 -0
- data/app/jobs/shipit/update_github_last_deployed_ref_job.rb +6 -3
- data/app/models/concerns/shipit/deferred_touch.rb +4 -3
- data/app/models/shipit/anonymous_user.rb +5 -0
- data/app/models/shipit/api_client.rb +3 -2
- data/app/models/shipit/application_record.rb +2 -1
- data/app/models/shipit/check_run.rb +4 -3
- data/app/models/shipit/command_line_user.rb +1 -0
- data/app/models/shipit/commit.rb +31 -12
- data/app/models/shipit/commit_checks.rb +1 -0
- data/app/models/shipit/commit_deployment.rb +17 -12
- data/app/models/shipit/commit_deployment_status.rb +8 -3
- data/app/models/shipit/commit_message.rb +1 -0
- data/app/models/shipit/delivery.rb +4 -3
- data/app/models/shipit/deploy.rb +40 -10
- data/app/models/shipit/deploy_spec.rb +22 -3
- data/app/models/shipit/deploy_spec/bundler_discovery.rb +2 -1
- data/app/models/shipit/deploy_spec/capistrano_discovery.rb +1 -0
- data/app/models/shipit/deploy_spec/file_system.rb +10 -3
- data/app/models/shipit/deploy_spec/kubernetes_discovery.rb +1 -0
- data/app/models/shipit/deploy_spec/lerna_discovery.rb +1 -0
- data/app/models/shipit/deploy_spec/npm_discovery.rb +5 -4
- data/app/models/shipit/deploy_spec/pypi_discovery.rb +1 -0
- data/app/models/shipit/deploy_spec/rubygems_discovery.rb +1 -0
- data/app/models/shipit/deploy_stats.rb +58 -0
- data/app/models/shipit/duration.rb +3 -2
- data/app/models/shipit/ephemeral_commit_checks.rb +1 -0
- data/app/models/shipit/github_hook.rb +2 -1
- data/app/models/shipit/github_status.rb +3 -2
- data/app/models/shipit/hook.rb +6 -5
- data/app/models/shipit/membership.rb +3 -2
- data/app/models/shipit/output_chunk.rb +7 -2
- data/app/models/shipit/pull_request.rb +13 -7
- data/app/models/shipit/record.rb +18 -0
- data/app/models/shipit/release_status.rb +3 -2
- data/app/models/shipit/repository.rb +43 -0
- data/app/models/shipit/rollback.rb +1 -0
- data/app/models/shipit/stack.rb +109 -50
- data/app/models/shipit/status.rb +3 -2
- data/app/models/shipit/status/common.rb +7 -6
- data/app/models/shipit/status/group.rb +1 -0
- data/app/models/shipit/status/missing.rb +2 -1
- data/app/models/shipit/status/unknown.rb +2 -1
- data/app/models/shipit/task.rb +64 -9
- data/app/models/shipit/task_definition.rb +1 -0
- data/app/models/shipit/team.rb +2 -1
- data/app/models/shipit/undeployed_commit.rb +1 -0
- data/app/models/shipit/unlimited_api_client.rb +1 -0
- data/app/models/shipit/user.rb +29 -5
- data/app/models/shipit/variable_definition.rb +1 -0
- data/app/models/shipit/webhooks.rb +33 -0
- data/app/models/shipit/webhooks/handlers/check_suite_handler.rb +20 -0
- data/app/models/shipit/webhooks/handlers/handler.rb +41 -0
- data/app/models/shipit/webhooks/handlers/membership_handler.rb +46 -0
- data/app/models/shipit/webhooks/handlers/push_handler.rb +21 -0
- data/app/models/shipit/webhooks/handlers/status_handler.rb +27 -0
- data/app/serializers/concerns/shipit/conditional_attributes.rb +1 -0
- data/app/serializers/shipit/anonymous_user_serializer.rb +1 -0
- data/app/serializers/shipit/command_line_user_serializer.rb +1 -0
- data/app/serializers/shipit/commit_serializer.rb +1 -0
- data/app/serializers/shipit/deploy_serializer.rb +2 -1
- data/app/serializers/shipit/hook_serializer.rb +1 -0
- data/app/serializers/shipit/pull_request_serializer.rb +1 -0
- data/app/serializers/shipit/rollback_serializer.rb +1 -0
- data/app/serializers/shipit/short_commit_serializer.rb +1 -0
- data/app/serializers/shipit/stack_serializer.rb +7 -1
- data/app/serializers/shipit/tail_task_serializer.rb +1 -0
- data/app/serializers/shipit/task_serializer.rb +2 -17
- data/app/serializers/shipit/user_serializer.rb +6 -1
- data/app/validators/ascii_only_validator.rb +4 -3
- data/app/validators/subset_validator.rb +1 -0
- data/app/views/layouts/_head.html.erb +0 -0
- data/app/views/layouts/shipit.html.erb +6 -4
- data/app/views/shipit/_variables.html.erb +1 -1
- data/app/views/shipit/api_clients/index.html.erb +36 -0
- data/app/views/shipit/api_clients/new.html.erb +33 -0
- data/app/views/shipit/api_clients/show.html.erb +35 -0
- data/app/views/shipit/ccmenu/project.xml.builder +2 -1
- data/app/views/shipit/deploys/new.html.erb +17 -12
- data/app/views/shipit/deploys/show.html.erb +2 -2
- data/app/views/shipit/merge_status/logged_out.erb +1 -1
- data/app/views/shipit/stacks/_header.html.erb +27 -12
- data/app/views/shipit/stacks/_links.html.erb +1 -0
- data/app/views/shipit/stacks/all_tasks.html.erb +28 -0
- data/app/views/shipit/stacks/index.html.erb +7 -2
- data/app/views/shipit/stacks/settings.html.erb +19 -0
- data/app/views/shipit/stacks/statistics.html.erb +82 -0
- data/app/views/shipit/tasks/show.html.erb +1 -1
- data/config/initializers/inflections.rb +2 -1
- data/config/locales/en.yml +18 -5
- data/config/routes.rb +14 -2
- data/db/migrate/20191209231045_create_shipit_repositories.rb +12 -0
- data/db/migrate/20191209231307_add_repository_reference_to_stacks.rb +15 -0
- data/db/migrate/20191216162728_backfill_repository_data.rb +22 -0
- data/db/migrate/20191216163010_remove_repository_information_from_stacks.rb +20 -0
- data/db/migrate/20191219205202_add_archived_since_to_stacks.rb +6 -0
- data/db/migrate/20200102175621_optional_task_commits.rb +6 -0
- data/db/migrate/20200109132519_add_sha_to_commit_deployments.rb +5 -0
- data/db/migrate/20200226211925_add_index_to_tasks_status.rb +5 -0
- data/db/migrate/20200427135152_add_pull_request_head_sha_to_commit.rb +5 -0
- data/db/migrate/20200615181558_add_rollback_once_aborted_to.rb +5 -0
- data/lib/shipit.rb +18 -20
- data/lib/shipit/cast_value.rb +1 -0
- data/lib/shipit/command.rb +14 -18
- data/lib/shipit/commands.rb +5 -4
- data/lib/shipit/csv_serializer.rb +1 -0
- data/lib/shipit/deploy_commands.rb +1 -0
- data/lib/shipit/engine.rb +11 -2
- data/lib/shipit/environment_variables.rb +11 -1
- data/lib/shipit/first_parent_commits_iterator.rb +1 -0
- data/lib/shipit/flock.rb +1 -0
- data/lib/shipit/github_app.rb +60 -6
- data/lib/shipit/github_http_cache_middleware.rb +57 -0
- data/lib/shipit/null_serializer.rb +1 -0
- data/lib/shipit/octokit_check_runs.rb +3 -2
- data/lib/shipit/octokit_iterator.rb +3 -2
- data/lib/shipit/paginator.rb +3 -2
- data/lib/shipit/rollback_commands.rb +1 -0
- data/lib/shipit/same_site_cookie_middleware.rb +29 -0
- data/lib/shipit/simple_message_verifier.rb +1 -0
- data/lib/shipit/stack_commands.rb +6 -3
- data/lib/shipit/stat.rb +1 -0
- data/lib/shipit/task_commands.rb +22 -14
- data/lib/shipit/version.rb +2 -1
- data/lib/snippets/release-gem +5 -1
- data/lib/tasks/cron.rake +2 -0
- data/lib/tasks/dev.rake +3 -2
- data/lib/tasks/shipit.rake +16 -17
- data/lib/tasks/teams.rake +1 -0
- data/test/controllers/api/base_controller_test.rb +3 -2
- data/test/controllers/api/ccmenu_controller_test.rb +9 -8
- data/test/controllers/api/commits_controller_test.rb +3 -2
- data/test/controllers/api/deploys_controller_test.rb +15 -14
- data/test/controllers/api/hooks_controller_test.rb +8 -7
- data/test/controllers/api/locks_controller_test.rb +7 -6
- data/test/controllers/api/outputs_controller_test.rb +3 -2
- data/test/controllers/api/pull_requests_controller_test.rb +8 -7
- data/test/controllers/api/release_statuses_controller_test.rb +2 -1
- data/test/controllers/api/rollback_controller_test.rb +113 -0
- data/test/controllers/api/stacks_controller_test.rb +44 -15
- data/test/controllers/api/tasks_controller_test.rb +13 -12
- data/test/controllers/api_clients_controller_test.rb +104 -0
- data/test/controllers/ccmenu_controller_test.rb +4 -3
- data/test/controllers/commit_checks_controller_test.rb +4 -3
- data/test/controllers/commits_controller_test.rb +3 -2
- data/test/controllers/deploys_controller_test.rb +33 -22
- data/test/controllers/github_authentication_controller_test.rb +1 -0
- data/test/controllers/merge_status_controller_test.rb +27 -9
- data/test/controllers/pull_requests_controller_test.rb +4 -3
- data/test/controllers/release_statuses_controller_test.rb +3 -2
- data/test/controllers/rollbacks_controller_test.rb +9 -8
- data/test/controllers/stacks_controller_test.rb +64 -15
- data/test/controllers/status_controller_test.rb +1 -0
- data/test/controllers/tasks_controller_test.rb +20 -19
- data/test/controllers/webhooks_controller_test.rb +36 -9
- data/test/dummy/config/application.rb +1 -1
- data/test/dummy/config/environments/development.rb +24 -4
- data/test/dummy/config/environments/test.rb +2 -0
- data/test/dummy/db/schema.rb +25 -11
- data/test/dummy/db/seeds.rb +34 -17
- data/test/fixtures/shipit/commit_deployment_statuses.yml +4 -4
- data/test/fixtures/shipit/commit_deployments.yml +8 -8
- data/test/fixtures/shipit/commits.yml +38 -0
- data/test/fixtures/shipit/repositories.yml +27 -0
- data/test/fixtures/shipit/stacks.yml +190 -30
- data/test/fixtures/shipit/tasks.yml +66 -3
- data/test/fixtures/timeout +2 -1
- data/test/helpers/api_helper.rb +1 -0
- data/test/helpers/fixture_aliases_helper.rb +1 -0
- data/test/helpers/hooks_helper.rb +2 -1
- data/test/helpers/json_helper.rb +15 -11
- data/test/helpers/links_helper.rb +4 -3
- data/test/helpers/payloads_helper.rb +1 -0
- data/test/helpers/queries_helper.rb +3 -2
- data/test/jobs/cache_deploy_spec_job_test.rb +2 -1
- data/test/jobs/chunk_rollup_job_test.rb +1 -0
- data/test/jobs/deliver_hook_job_test.rb +2 -1
- data/test/jobs/destroy_stack_job_test.rb +10 -0
- data/test/jobs/emit_event_job_test.rb +2 -1
- data/test/jobs/fetch_commit_stats_job_test.rb +1 -0
- data/test/jobs/fetch_deployed_revision_job_test.rb +1 -0
- data/test/jobs/github_sync_job_test.rb +1 -0
- data/test/jobs/mark_deploy_healthy_job_test.rb +1 -0
- data/test/jobs/merge_pull_requests_job_test.rb +5 -4
- data/test/jobs/perform_task_job_test.rb +4 -3
- data/test/jobs/purge_old_deliveries_job_test.rb +1 -0
- data/test/jobs/reap_dead_tasks_job_test.rb +68 -0
- data/test/jobs/refresh_github_user_job_test.rb +1 -0
- data/test/jobs/refresh_status_job_test.rb +1 -0
- data/test/jobs/unique_job_test.rb +1 -0
- data/test/jobs/update_github_last_deployed_ref_job_test.rb +13 -11
- data/test/middleware/same_site_cookie_middleware_test.rb +52 -0
- data/test/models/api_client_test.rb +1 -0
- data/test/models/commit_checks_test.rb +1 -0
- data/test/models/commit_deployment_status_test.rb +34 -4
- data/test/models/commit_deployment_test.rb +9 -11
- data/test/models/commits_test.rb +99 -7
- data/test/models/delivery_test.rb +3 -2
- data/test/models/deploy_spec_test.rb +47 -42
- data/test/models/deploy_stats_test.rb +113 -0
- data/test/models/deploys_test.rb +60 -13
- data/test/models/duration_test.rb +1 -0
- data/test/models/github_hook_test.rb +1 -0
- data/test/models/hook_test.rb +20 -16
- data/test/models/membership_test.rb +1 -0
- data/test/models/output_chunk_test.rb +1 -0
- data/test/models/pull_request_test.rb +18 -11
- data/test/models/release_statuses_test.rb +1 -0
- data/test/models/rollbacks_test.rb +1 -0
- data/test/models/shipit/check_run_test.rb +1 -0
- data/test/models/shipit/repository_test.rb +77 -0
- data/test/models/shipit/wehbooks/handlers_test.rb +27 -0
- data/test/models/stacks_test.rb +110 -56
- data/test/models/status/group_test.rb +1 -0
- data/test/models/status/missing_test.rb +1 -0
- data/test/models/status_test.rb +1 -0
- data/test/models/task_definitions_test.rb +9 -8
- data/test/models/tasks_test.rb +18 -1
- data/test/models/team_test.rb +4 -2
- data/test/models/undeployed_commits_test.rb +14 -0
- data/test/models/users_test.rb +109 -1
- data/test/test_command_integration.rb +3 -2
- data/test/test_helper.rb +38 -34
- data/test/unit/anonymous_user_serializer_test.rb +14 -0
- data/test/unit/command_test.rb +12 -7
- data/test/unit/commands_test.rb +1 -0
- data/test/unit/commit_serializer_test.rb +16 -0
- data/test/unit/csv_serializer_test.rb +3 -2
- data/test/unit/deploy_commands_test.rb +14 -4
- data/test/unit/deploy_serializer_test.rb +17 -0
- data/test/unit/environment_variables_test.rb +5 -4
- data/test/unit/github_app_test.rb +165 -0
- data/test/unit/github_url_helper_test.rb +1 -0
- data/test/unit/rollback_commands_test.rb +2 -1
- data/test/unit/shipit_helper_test.rb +17 -0
- data/test/unit/shipit_test.rb +1 -0
- data/test/unit/user_serializer_test.rb +14 -0
- data/test/unit/variable_definition_test.rb +1 -0
- metadata +215 -157
- data/lib/shipit/strip_cache_control.rb +0 -40
@@ -1,13 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'json'
|
2
3
|
|
3
4
|
module Shipit
|
4
5
|
class DeploySpec
|
5
6
|
module NpmDiscovery
|
6
7
|
# https://docs.npmjs.com/cli/publish
|
7
|
-
PUBLIC = 'public'
|
8
|
-
PRIVATE = 'restricted'
|
8
|
+
PUBLIC = 'public'
|
9
|
+
PRIVATE = 'restricted'
|
9
10
|
VALID_ACCESS = [PUBLIC, PRIVATE].freeze
|
10
|
-
NPM_REGISTRY = "https://registry.npmjs.org/"
|
11
|
+
NPM_REGISTRY = "https://registry.npmjs.org/"
|
11
12
|
|
12
13
|
def discover_dependencies_steps
|
13
14
|
discover_package_json || super
|
@@ -57,7 +58,7 @@ module Shipit
|
|
57
58
|
# are treated as 'next' npm dist-tags.
|
58
59
|
# An 1.0.0-beta.1 would be installable using both:
|
59
60
|
# `yarn add package@1.0.0-beta.1` and `yarn add package@next`
|
60
|
-
return 'next' if ['-beta', '-alpha', '-rc', '-next'].any? { |tag| version.include?
|
61
|
+
return 'next' if ['-beta', '-alpha', '-rc', '-next'].any? { |tag| version.include?(tag) }
|
61
62
|
'latest'
|
62
63
|
end
|
63
64
|
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Shipit
|
3
|
+
class DeployStats
|
4
|
+
delegate :empty?, to: :@deploys
|
5
|
+
|
6
|
+
def initialize(deploys)
|
7
|
+
@deploys = deploys
|
8
|
+
@durations = @deploys.map { |d| d.duration&.value }.compact
|
9
|
+
end
|
10
|
+
|
11
|
+
def count
|
12
|
+
@deploys.length
|
13
|
+
end
|
14
|
+
|
15
|
+
def average_duration
|
16
|
+
return if empty?
|
17
|
+
@durations.sum / @durations.length.to_f
|
18
|
+
end
|
19
|
+
|
20
|
+
def max_duration
|
21
|
+
@durations.max
|
22
|
+
end
|
23
|
+
|
24
|
+
def min_duration
|
25
|
+
@durations.min
|
26
|
+
end
|
27
|
+
|
28
|
+
def median_duration
|
29
|
+
return if @durations.empty?
|
30
|
+
(sorted_durations[(@durations.length - 1) / 2] + sorted_durations[@durations.length / 2]) / 2.0
|
31
|
+
end
|
32
|
+
|
33
|
+
def success_rate
|
34
|
+
return if empty?
|
35
|
+
(@deploys.count(&:success?) / @deploys.length.to_f) * 100
|
36
|
+
end
|
37
|
+
|
38
|
+
def compare(compare_stats)
|
39
|
+
{
|
40
|
+
count: percent_change(compare_stats.count, count),
|
41
|
+
average_duration: percent_change(compare_stats.average_duration, average_duration),
|
42
|
+
median_duration: percent_change(compare_stats.median_duration, median_duration),
|
43
|
+
}
|
44
|
+
end
|
45
|
+
|
46
|
+
protected
|
47
|
+
|
48
|
+
def sorted_durations
|
49
|
+
@sorted ||= @durations.sort
|
50
|
+
end
|
51
|
+
|
52
|
+
def percent_change(from, to)
|
53
|
+
return if to.nil? || from.nil?
|
54
|
+
return to * 100 if from.zero?
|
55
|
+
((to - from) / from.to_f) * 100
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -1,15 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module Shipit
|
2
3
|
class Duration < ActiveSupport::Duration
|
3
4
|
ParseError = Class.new(ArgumentError)
|
4
5
|
|
5
|
-
FORMAT =
|
6
|
+
FORMAT = %r{
|
6
7
|
\A
|
7
8
|
(?<days>\d+d)?
|
8
9
|
(?<hours>\d+h)?
|
9
10
|
(?<minutes>\d+m)?
|
10
11
|
(?<seconds>\d+s?)?
|
11
12
|
\z
|
12
|
-
|
13
|
+
}x
|
13
14
|
UNITS = {
|
14
15
|
's' => :seconds,
|
15
16
|
'm' => :minutes,
|
@@ -1,6 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module Shipit
|
2
3
|
module GithubStatus
|
3
|
-
CACHE_KEY = 'github::status'
|
4
|
+
CACHE_KEY = 'github::status'
|
4
5
|
|
5
6
|
class << self
|
6
7
|
def status
|
@@ -8,7 +9,7 @@ module Shipit
|
|
8
9
|
end
|
9
10
|
|
10
11
|
def refresh_status
|
11
|
-
Rails.cache.write(CACHE_KEY, Shipit.github.
|
12
|
+
Rails.cache.write(CACHE_KEY, Shipit.github.api_status)
|
12
13
|
rescue Faraday::Error, Octokit::ServerError
|
13
14
|
end
|
14
15
|
end
|
data/app/models/shipit/hook.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module Shipit
|
2
|
-
class Hook <
|
3
|
+
class Hook < Record
|
3
4
|
class DeliverySpec
|
4
5
|
def initialize(event:, url:, content_type:, payload:)
|
5
6
|
@event = event
|
@@ -19,7 +20,7 @@ module Shipit
|
|
19
20
|
def http
|
20
21
|
Faraday::Connection.new do |connection|
|
21
22
|
connection.headers = headers
|
22
|
-
connection.adapter
|
23
|
+
connection.adapter(Faraday.default_adapter)
|
23
24
|
end
|
24
25
|
end
|
25
26
|
|
@@ -57,9 +58,9 @@ module Shipit
|
|
57
58
|
belongs_to :stack, required: false
|
58
59
|
has_many :deliveries
|
59
60
|
|
60
|
-
validates :delivery_url, presence: true, url: {no_local: true, allow_blank: true}
|
61
|
-
validates :content_type, presence: true, inclusion: {in: CONTENT_TYPES.keys}
|
62
|
-
validates :events, presence: true, subset: {of: EVENTS}
|
61
|
+
validates :delivery_url, presence: true, url: { no_local: true, allow_blank: true }
|
62
|
+
validates :content_type, presence: true, inclusion: { in: CONTENT_TYPES.keys }
|
63
|
+
validates :events, presence: true, subset: { of: EVENTS }
|
63
64
|
|
64
65
|
serialize :events, Shipit::CSVSerializer
|
65
66
|
|
@@ -1,8 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module Shipit
|
2
|
-
class Membership <
|
3
|
+
class Membership < Record
|
3
4
|
belongs_to :team, required: true
|
4
5
|
belongs_to :user, required: true
|
5
6
|
|
6
|
-
validates :user_id, uniqueness: {scope: :team_id}
|
7
|
+
validates :user_id, uniqueness: { scope: :team_id }
|
7
8
|
end
|
8
9
|
end
|
@@ -1,11 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module Shipit
|
2
|
-
class OutputChunk <
|
3
|
+
class OutputChunk < Record
|
3
4
|
belongs_to :task
|
4
5
|
|
5
6
|
scope :tail, ->(start) { order(id: :asc).where('id > ?', start || 0) }
|
6
7
|
|
7
8
|
def text=(string)
|
8
|
-
|
9
|
+
if string.frozen?
|
10
|
+
super(string)
|
11
|
+
else
|
12
|
+
super(string.force_encoding(Encoding::UTF_8).scrub)
|
13
|
+
end
|
9
14
|
end
|
10
15
|
end
|
11
16
|
end
|
@@ -1,12 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module Shipit
|
2
3
|
class PullRequest < ApplicationRecord
|
3
4
|
include DeferredTouch
|
4
5
|
|
5
|
-
MERGE_REQUEST_FIELD = 'Merge-Requested-By'
|
6
|
+
MERGE_REQUEST_FIELD = 'Merge-Requested-By'
|
6
7
|
|
7
8
|
WAITING_STATUSES = %w(fetching pending).freeze
|
8
9
|
QUEUED_STATUSES = %w(pending revalidating).freeze
|
9
|
-
REJECTION_REASONS = %w(ci_failing merge_conflict requires_rebase).freeze
|
10
|
+
REJECTION_REASONS = %w(ci_missing ci_failing merge_conflict requires_rebase).freeze
|
10
11
|
InvalidTransition = Class.new(StandardError)
|
11
12
|
NotReady = Class.new(StandardError)
|
12
13
|
|
@@ -45,7 +46,7 @@ module Shipit
|
|
45
46
|
|
46
47
|
deferred_touch stack: :updated_at
|
47
48
|
|
48
|
-
validates :number, presence: true, uniqueness: {scope: :stack_id}
|
49
|
+
validates :number, presence: true, uniqueness: { scope: :stack_id }
|
49
50
|
|
50
51
|
scope :waiting, -> { where(merge_status: WAITING_STATUSES) }
|
51
52
|
scope :pending, -> { where(merge_status: 'pending') }
|
@@ -149,6 +150,7 @@ module Shipit
|
|
149
150
|
|
150
151
|
def reject_unless_mergeable!
|
151
152
|
return reject!('merge_conflict') if merge_conflict?
|
153
|
+
return reject!('ci_missing') if any_status_checks_missing?
|
152
154
|
return reject!('ci_failing') if any_status_checks_failed?
|
153
155
|
return reject!('requires_rebase') if stale?
|
154
156
|
false
|
@@ -175,10 +177,10 @@ module Shipit
|
|
175
177
|
# branch was already deleted somehow
|
176
178
|
end
|
177
179
|
complete!
|
178
|
-
|
180
|
+
true
|
179
181
|
rescue Octokit::MethodNotAllowed # merge conflict
|
180
182
|
reject!('merge_conflict')
|
181
|
-
|
183
|
+
false
|
182
184
|
rescue Octokit::Conflict # shas didn't match, PR was updated.
|
183
185
|
raise NotReady
|
184
186
|
end
|
@@ -190,7 +192,11 @@ module Shipit
|
|
190
192
|
|
191
193
|
def any_status_checks_failed?
|
192
194
|
status = StatusChecker.new(head, head.statuses_and_check_runs, stack.cached_deploy_spec)
|
193
|
-
status.failure? || status.error?
|
195
|
+
status.failure? || status.error?
|
196
|
+
end
|
197
|
+
|
198
|
+
def any_status_checks_missing?
|
199
|
+
StatusChecker.new(head, head.statuses_and_check_runs, stack.cached_deploy_spec).missing?
|
194
200
|
end
|
195
201
|
|
196
202
|
def waiting?
|
@@ -284,7 +290,7 @@ module Shipit
|
|
284
290
|
|
285
291
|
def find_or_create_commit_from_github_by_sha!(sha, attributes)
|
286
292
|
if commit = stack.commits.by_sha(sha)
|
287
|
-
|
293
|
+
commit
|
288
294
|
else
|
289
295
|
github_commit = Shipit.github.api.commit(stack.github_repo_name, sha)
|
290
296
|
stack.commits.create_from_github!(github_commit, attributes)
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Shipit
|
3
|
+
class Record < ActiveRecord::Base
|
4
|
+
self.abstract_class = true
|
5
|
+
|
6
|
+
class << self
|
7
|
+
def serializer_class
|
8
|
+
if defined? @serializer_class
|
9
|
+
@serializer_class
|
10
|
+
else
|
11
|
+
@serializer_class = "#{name}Serializer".safe_constantize
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
delegate :serializer_class, to: :class
|
17
|
+
end
|
18
|
+
end
|
@@ -1,5 +1,6 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module Shipit
|
2
|
-
class ReleaseStatus <
|
3
|
+
class ReleaseStatus < Record
|
3
4
|
MAX_DESCRIPTION_LENGTH = 140
|
4
5
|
include DeferredTouch
|
5
6
|
|
@@ -13,7 +14,7 @@ module Shipit
|
|
13
14
|
scope :to_be_created, -> { where(github_id: nil).order(id: :asc) }
|
14
15
|
|
15
16
|
STATES = %w(pending success failure error).freeze
|
16
|
-
validates :state, presence: true, inclusion: {in: STATES}
|
17
|
+
validates :state, presence: true, inclusion: { in: STATES }
|
17
18
|
|
18
19
|
def create_status_on_github!
|
19
20
|
return true if github_id?
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Shipit
|
3
|
+
class Repository < ApplicationRecord
|
4
|
+
OWNER_MAX_SIZE = 39
|
5
|
+
private_constant :OWNER_MAX_SIZE
|
6
|
+
|
7
|
+
NAME_MAX_SIZE = 100
|
8
|
+
private_constant :NAME_MAX_SIZE
|
9
|
+
|
10
|
+
validates :name, uniqueness: { scope: %i(owner), case_sensitive: false,
|
11
|
+
message: 'cannot be used more than once' }
|
12
|
+
validates :owner, :name, presence: true, ascii_only: true
|
13
|
+
validates :owner, format: { with: /\A[a-z0-9_\-\.]+\z/ }, length: { maximum: OWNER_MAX_SIZE }
|
14
|
+
validates :name, format: { with: /\A[a-z0-9_\-\.]+\z/ }, length: { maximum: NAME_MAX_SIZE }
|
15
|
+
|
16
|
+
has_many :stacks, dependent: :destroy
|
17
|
+
|
18
|
+
def self.from_github_repo_name(github_repo_name)
|
19
|
+
repo_owner, repo_name = github_repo_name.downcase.split('/')
|
20
|
+
find_by(owner: repo_owner, name: repo_name)
|
21
|
+
end
|
22
|
+
|
23
|
+
def name=(n)
|
24
|
+
super(n&.downcase)
|
25
|
+
end
|
26
|
+
|
27
|
+
def owner=(o)
|
28
|
+
super(o&.downcase)
|
29
|
+
end
|
30
|
+
|
31
|
+
def http_url
|
32
|
+
Shipit.github.url(full_name)
|
33
|
+
end
|
34
|
+
|
35
|
+
def full_name
|
36
|
+
"#{owner}/#{name}"
|
37
|
+
end
|
38
|
+
|
39
|
+
def git_url
|
40
|
+
"https://#{Shipit.github.domain}/#{owner}/#{name}.git"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
data/app/models/shipit/stack.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'fileutils'
|
2
3
|
|
3
4
|
module Shipit
|
4
|
-
class Stack <
|
5
|
+
class Stack < Record
|
5
6
|
module NoDeployedCommit
|
6
7
|
extend self
|
7
8
|
|
@@ -22,8 +23,6 @@ module Shipit
|
|
22
23
|
end
|
23
24
|
end
|
24
25
|
|
25
|
-
REPO_OWNER_MAX_SIZE = 39
|
26
|
-
REPO_NAME_MAX_SIZE = 100
|
27
26
|
ENVIRONMENT_MAX_SIZE = 50
|
28
27
|
REQUIRED_HOOKS = %i(push status).freeze
|
29
28
|
|
@@ -40,6 +39,27 @@ module Shipit
|
|
40
39
|
has_many :hooks, dependent: :destroy
|
41
40
|
has_many :api_clients, dependent: :destroy
|
42
41
|
belongs_to :lock_author, class_name: :User, optional: true
|
42
|
+
belongs_to :repository
|
43
|
+
validates_associated :repository
|
44
|
+
|
45
|
+
scope :not_archived, -> { where(archived_since: nil) }
|
46
|
+
|
47
|
+
default_scope { preload(:repository) }
|
48
|
+
|
49
|
+
def env
|
50
|
+
{
|
51
|
+
'ENVIRONMENT' => environment,
|
52
|
+
'LAST_DEPLOYED_SHA' => last_deployed_commit.sha,
|
53
|
+
'GITHUB_REPO_OWNER' => repository.owner,
|
54
|
+
'GITHUB_REPO_NAME' => repository.name,
|
55
|
+
'DEPLOY_URL' => deploy_url,
|
56
|
+
'BRANCH' => branch,
|
57
|
+
}
|
58
|
+
end
|
59
|
+
|
60
|
+
def repository
|
61
|
+
super || build_repository
|
62
|
+
end
|
43
63
|
|
44
64
|
def lock_author(*)
|
45
65
|
super || AnonymousUser.new
|
@@ -49,11 +69,6 @@ module Shipit
|
|
49
69
|
super(user&.logged_in? ? user : nil)
|
50
70
|
end
|
51
71
|
|
52
|
-
def self.repo(full_name)
|
53
|
-
repo_owner, repo_name = full_name.downcase.split('/')
|
54
|
-
where(repo_owner: repo_owner, repo_name: repo_name)
|
55
|
-
end
|
56
|
-
|
57
72
|
before_validation :update_defaults
|
58
73
|
before_destroy :clear_local_files
|
59
74
|
before_save :set_locked_since
|
@@ -66,18 +81,17 @@ module Shipit
|
|
66
81
|
after_commit :sync_github, on: :create
|
67
82
|
after_commit :schedule_merges_if_necessary, on: :update
|
68
83
|
|
69
|
-
validates :
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
validates :
|
74
|
-
validates :
|
75
|
-
validates :deploy_url, format: {with: URI.regexp(%w(http https ssh))}, allow_blank: true
|
84
|
+
validates :repository, uniqueness: {
|
85
|
+
scope: %i(environment), case_sensitive: false,
|
86
|
+
message: 'cannot be used more than once with this environment. Check archived stacks.'
|
87
|
+
}
|
88
|
+
validates :environment, format: { with: /\A[a-z0-9\-_\:]+\z/ }, length: { maximum: ENVIRONMENT_MAX_SIZE }
|
89
|
+
validates :deploy_url, format: { with: URI.regexp(%w(http https ssh)) }, allow_blank: true
|
76
90
|
|
77
|
-
validates :lock_reason, length: {maximum: 4096}
|
91
|
+
validates :lock_reason, length: { maximum: 4096 }
|
78
92
|
|
79
93
|
serialize :cached_deploy_spec, DeploySpec
|
80
|
-
delegate :find_task_definition, :supports_rollback?, :
|
94
|
+
delegate :find_task_definition, :supports_rollback?, :release_status?, :release_status_delay,
|
81
95
|
:release_status_context, :supports_fetch_deployed_revision?, to: :cached_deploy_spec, allow_nil: true
|
82
96
|
|
83
97
|
def self.refresh_deployed_revisions
|
@@ -129,9 +143,24 @@ module Shipit
|
|
129
143
|
end
|
130
144
|
|
131
145
|
def trigger_deploy(*args, **kwargs)
|
146
|
+
if changed?
|
147
|
+
# If this is the first deploy since the spec changed it's possible the record will be dirty here, meaning we
|
148
|
+
# cant lock. In this one case persist the changes, otherwise log a warning and let the lock raise, so we
|
149
|
+
# can debug what's going on here. We don't expect anything other than the deploy spec to dirty the model
|
150
|
+
# instance, because of how that field is serialised.
|
151
|
+
if changes.keys == ['cached_deploy_spec']
|
152
|
+
save!
|
153
|
+
else
|
154
|
+
Rails.logger.warning("#{changes.keys} field(s) were unexpectedly modified on stack #{id} while deploying")
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
132
158
|
run_now = kwargs.delete(:run_now)
|
133
|
-
deploy =
|
134
|
-
|
159
|
+
deploy = with_lock do
|
160
|
+
deploy = build_deploy(*args, **kwargs)
|
161
|
+
deploy.save!
|
162
|
+
deploy
|
163
|
+
end
|
135
164
|
run_now ? deploy.run_now! : deploy.enqueue
|
136
165
|
continuous_delivery_resumed!
|
137
166
|
deploy
|
@@ -150,14 +179,16 @@ module Shipit
|
|
150
179
|
end
|
151
180
|
|
152
181
|
def trigger_continuous_delivery
|
182
|
+
return if cached_deploy_spec.blank?
|
183
|
+
|
153
184
|
commit = next_commit_to_deploy
|
154
185
|
|
155
|
-
if
|
186
|
+
if should_resume_continuous_delivery?(commit)
|
156
187
|
continuous_delivery_resumed!
|
157
188
|
return
|
158
189
|
end
|
159
190
|
|
160
|
-
if
|
191
|
+
if should_delay_continuous_delivery?(commit)
|
161
192
|
continuous_delivery_delayed!
|
162
193
|
return
|
163
194
|
end
|
@@ -189,7 +220,7 @@ module Shipit
|
|
189
220
|
def async_refresh_deployed_revision
|
190
221
|
async_refresh_deployed_revision!
|
191
222
|
rescue => error
|
192
|
-
logger.warn
|
223
|
+
logger.warn("Failed to dispatch FetchDeployedRevisionJob: [#{error.class.name}] #{error.message}")
|
193
224
|
end
|
194
225
|
|
195
226
|
def async_refresh_deployed_revision!
|
@@ -257,8 +288,8 @@ module Shipit
|
|
257
288
|
next if commits_to_lock.empty?
|
258
289
|
|
259
290
|
affected_rows += commits
|
260
|
-
|
261
|
-
|
291
|
+
.where(id: commits_to_lock.map(&:id).uniq)
|
292
|
+
.lock_all(revert.author)
|
262
293
|
end
|
263
294
|
|
264
295
|
touch if affected_rows > 1
|
@@ -320,21 +351,12 @@ module Shipit
|
|
320
351
|
cached_deploy_spec&.pull_request_merge_method || Shipit.default_merge_method
|
321
352
|
end
|
322
353
|
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
end
|
330
|
-
|
331
|
-
def repo_http_url
|
332
|
-
Shipit.github.url("#{repo_owner}/#{repo_name}")
|
333
|
-
end
|
334
|
-
|
335
|
-
def repo_git_url
|
336
|
-
"https://#{Shipit.github.domain}/#{repo_owner}/#{repo_name}.git"
|
337
|
-
end
|
354
|
+
delegate :name=, to: :repository, prefix: :repo
|
355
|
+
delegate :name, to: :repository, prefix: :repo
|
356
|
+
delegate :owner=, to: :repository, prefix: :repo
|
357
|
+
delegate :owner, to: :repository, prefix: :repo
|
358
|
+
delegate :http_url, to: :repository, prefix: :repo
|
359
|
+
delegate :git_url, to: :repository, prefix: :repo
|
338
360
|
|
339
361
|
def base_path
|
340
362
|
Rails.root.join('data', 'stacks', repo_owner, repo_name, environment)
|
@@ -354,8 +376,8 @@ module Shipit
|
|
354
376
|
|
355
377
|
def clear_git_cache!
|
356
378
|
tmp_path = "#{git_path}-#{SecureRandom.hex}"
|
379
|
+
return unless File.exist?(git_path)
|
357
380
|
acquire_git_cache_lock do
|
358
|
-
return unless File.exist?(git_path)
|
359
381
|
File.rename(git_path, tmp_path)
|
360
382
|
end
|
361
383
|
FileUtils.rm_rf(tmp_path)
|
@@ -389,7 +411,7 @@ module Shipit
|
|
389
411
|
if resource.try(:message) == 'Moved Permanently'
|
390
412
|
resource = Shipit.github.api.get(resource.url)
|
391
413
|
end
|
392
|
-
update!(
|
414
|
+
repository.update!(owner: resource.owner.login, name: resource.name)
|
393
415
|
end
|
394
416
|
|
395
417
|
def active_task?
|
@@ -406,7 +428,7 @@ module Shipit
|
|
406
428
|
end
|
407
429
|
|
408
430
|
def lock(reason, user)
|
409
|
-
params = {lock_reason: reason, lock_author: user}
|
431
|
+
params = { lock_reason: reason, lock_author: user }
|
410
432
|
update!(params)
|
411
433
|
end
|
412
434
|
|
@@ -414,6 +436,18 @@ module Shipit
|
|
414
436
|
update!(lock_reason: nil, lock_author: nil, locked_since: nil)
|
415
437
|
end
|
416
438
|
|
439
|
+
def archived?
|
440
|
+
archived_since.present?
|
441
|
+
end
|
442
|
+
|
443
|
+
def archive!(user)
|
444
|
+
update!(archived_since: Time.now, lock_reason: "Archived", lock_author: user)
|
445
|
+
end
|
446
|
+
|
447
|
+
def unarchive!
|
448
|
+
update!(archived_since: nil, lock_reason: nil, lock_author: nil, locked_since: nil)
|
449
|
+
end
|
450
|
+
|
417
451
|
def to_param
|
418
452
|
[repo_owner, repo_name, environment].join('/')
|
419
453
|
end
|
@@ -429,11 +463,14 @@ module Shipit
|
|
429
463
|
|
430
464
|
def self.from_param!(param)
|
431
465
|
repo_owner, repo_name, environment = param.split('/')
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
466
|
+
includes(:repository)
|
467
|
+
.where(
|
468
|
+
repositories: {
|
469
|
+
owner: repo_owner.downcase,
|
470
|
+
name: repo_name.downcase,
|
471
|
+
},
|
472
|
+
environment: environment,
|
473
|
+
).first!
|
437
474
|
end
|
438
475
|
|
439
476
|
delegate :plugins, :task_definitions, :hidden_statuses, :required_statuses, :soft_failing_statuses,
|
@@ -463,13 +500,15 @@ module Shipit
|
|
463
500
|
end
|
464
501
|
|
465
502
|
def update_latest_deployed_ref
|
466
|
-
|
503
|
+
if Shipit.update_latest_deployed_ref
|
504
|
+
UpdateGithubLastDeployedRefJob.perform_later(self)
|
505
|
+
end
|
467
506
|
end
|
468
507
|
|
469
508
|
def broadcast_update
|
470
509
|
Pubsubstub.publish(
|
471
510
|
"stack.#{id}",
|
472
|
-
{id: id, updated_at: updated_at}.to_json,
|
511
|
+
{ id: id, updated_at: updated_at }.to_json,
|
473
512
|
name: 'update',
|
474
513
|
)
|
475
514
|
end
|
@@ -521,6 +560,13 @@ module Shipit
|
|
521
560
|
GithubSyncJob.perform_later(stack_id: id)
|
522
561
|
end
|
523
562
|
|
563
|
+
def links
|
564
|
+
links_spec = cached_deploy_spec&.links || {}
|
565
|
+
context = EnvironmentVariables.with(env)
|
566
|
+
|
567
|
+
links_spec.transform_values { |url| context.interpolate(url) }
|
568
|
+
end
|
569
|
+
|
524
570
|
private
|
525
571
|
|
526
572
|
def clear_cache
|
@@ -556,7 +602,7 @@ module Shipit
|
|
556
602
|
return unless previous_changes.include?('lock_reason')
|
557
603
|
|
558
604
|
lock_details = if previous_changes['lock_reason'].last.blank?
|
559
|
-
{from: previous_changes['locked_since'].first, until: Time.zone.now}
|
605
|
+
{ from: previous_changes['locked_since'].first, until: Time.zone.now }
|
560
606
|
end
|
561
607
|
|
562
608
|
Hook.emit(:lock, self, locked: locked?, lock_details: lock_details, stack: self)
|
@@ -582,5 +628,18 @@ module Shipit
|
|
582
628
|
def ci_enabled_cache_key
|
583
629
|
"stacks:#{id}:ci_enabled"
|
584
630
|
end
|
631
|
+
|
632
|
+
def should_resume_continuous_delivery?(commit)
|
633
|
+
!deployable? ||
|
634
|
+
deployed_too_recently? ||
|
635
|
+
commit.nil? ||
|
636
|
+
commit.deployed?
|
637
|
+
end
|
638
|
+
|
639
|
+
def should_delay_continuous_delivery?(commit)
|
640
|
+
commit.deploy_failed? ||
|
641
|
+
(checks? && !EphemeralCommitChecks.new(commit).run.success?) ||
|
642
|
+
commit.recently_pushed?
|
643
|
+
end
|
585
644
|
end
|
586
645
|
end
|