shipit-engine 0.39.0 → 0.40.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 +40 -1
- data/Rakefile +2 -1
- data/app/assets/javascripts/shipit/continuous_delivery_schedule.js.coffee +15 -0
- data/app/controllers/concerns/shipit/active_model_serializers_patch.rb +1 -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 +1 -0
- data/app/controllers/concerns/shipit/authentication.rb +1 -0
- data/app/controllers/concerns/shipit/pagination.rb +3 -2
- data/app/controllers/shipit/api/base_controller.rb +10 -8
- data/app/controllers/shipit/api/ccmenu_controller.rb +2 -1
- data/app/controllers/shipit/api/commits_controller.rb +2 -3
- data/app/controllers/shipit/api/deploys_controller.rb +2 -1
- data/app/controllers/shipit/api/hooks_controller.rb +4 -3
- data/app/controllers/shipit/api/locks_controller.rb +1 -0
- data/app/controllers/shipit/api/merge_requests_controller.rb +6 -5
- data/app/controllers/shipit/api/outputs_controller.rb +1 -0
- data/app/controllers/shipit/api/release_statuses_controller.rb +2 -1
- data/app/controllers/shipit/api/rollbacks_controller.rb +1 -0
- data/app/controllers/shipit/api/stacks_controller.rb +15 -14
- data/app/controllers/shipit/api/tasks_controller.rb +6 -5
- data/app/controllers/shipit/api_clients_controller.rb +6 -7
- data/app/controllers/shipit/ccmenu_url_controller.rb +3 -2
- data/app/controllers/shipit/commit_checks_controller.rb +2 -1
- data/app/controllers/shipit/commits_controller.rb +1 -0
- data/app/controllers/shipit/continuous_delivery_schedules_controller.rb +42 -0
- data/app/controllers/shipit/deploys_controller.rb +6 -5
- data/app/controllers/shipit/github_authentication_controller.rb +6 -0
- data/app/controllers/shipit/merge_requests_controller.rb +1 -0
- data/app/controllers/shipit/merge_status_controller.rb +30 -26
- data/app/controllers/shipit/release_statuses_controller.rb +1 -0
- data/app/controllers/shipit/repositories_controller.rb +4 -7
- data/app/controllers/shipit/rollbacks_controller.rb +2 -1
- data/app/controllers/shipit/shipit_controller.rb +1 -0
- data/app/controllers/shipit/stacks_controller.rb +27 -31
- data/app/controllers/shipit/status_controller.rb +1 -0
- data/app/controllers/shipit/tasks_controller.rb +3 -1
- data/app/controllers/shipit/webhooks_controller.rb +2 -1
- data/app/helpers/shipit/api_clients_helper.rb +1 -0
- data/app/helpers/shipit/chunks_helper.rb +3 -1
- data/app/helpers/shipit/deploys_helper.rb +7 -3
- data/app/helpers/shipit/github_url_helper.rb +5 -4
- data/app/helpers/shipit/merge_status_helper.rb +1 -0
- data/app/helpers/shipit/shipit_helper.rb +11 -10
- data/app/helpers/shipit/stacks_helper.rb +10 -11
- data/app/helpers/shipit/tasks_helper.rb +2 -1
- data/app/jobs/shipit/background_job/unique.rb +3 -2
- data/app/jobs/shipit/background_job.rb +9 -1
- data/app/jobs/shipit/cache_deploy_spec_job.rb +2 -1
- data/app/jobs/shipit/chunk_rollup_job.rb +1 -0
- data/app/jobs/shipit/clear_git_cache_job.rb +1 -0
- data/app/jobs/shipit/continuous_delivery_job.rb +5 -0
- data/app/jobs/shipit/create_on_github_job.rb +1 -0
- data/app/jobs/shipit/create_release_statuses_job.rb +2 -0
- data/app/jobs/shipit/deferred_touch_job.rb +1 -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_repository_job.rb +1 -0
- data/app/jobs/shipit/destroy_stack_job.rb +36 -15
- data/app/jobs/shipit/emit_event_job.rb +1 -0
- data/app/jobs/shipit/fetch_commit_stats_job.rb +1 -0
- data/app/jobs/shipit/fetch_deployed_revision_job.rb +1 -0
- data/app/jobs/shipit/github_sync_job.rb +4 -2
- data/app/jobs/shipit/mark_deploy_healthy_job.rb +1 -0
- data/app/jobs/shipit/perform_commit_checks_job.rb +1 -0
- data/app/jobs/shipit/perform_task_job.rb +1 -0
- data/app/jobs/shipit/process_merge_requests_job.rb +2 -0
- data/app/jobs/shipit/purge_old_deliveries_job.rb +1 -0
- data/app/jobs/shipit/reap_dead_tasks_job.rb +1 -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_merge_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 -7
- data/app/models/concerns/shipit/deferred_touch.rb +5 -2
- data/app/models/shipit/anonymous_user.rb +4 -5
- data/app/models/shipit/api_client.rb +4 -2
- data/app/models/shipit/application_record.rb +1 -0
- data/app/models/shipit/check_run.rb +7 -6
- data/app/models/shipit/command_line_user.rb +4 -5
- data/app/models/shipit/commit.rb +46 -32
- data/app/models/shipit/commit_checks.rb +4 -2
- data/app/models/shipit/commit_deployment.rb +7 -5
- data/app/models/shipit/commit_deployment_status.rb +5 -2
- data/app/models/shipit/commit_message.rb +2 -0
- data/app/models/shipit/continuous_delivery_schedule.rb +84 -0
- data/app/models/shipit/delivery.rb +4 -3
- data/app/models/shipit/deploy.rb +46 -26
- data/app/models/shipit/deploy_spec/bundler_discovery.rb +3 -1
- data/app/models/shipit/deploy_spec/capistrano_discovery.rb +1 -0
- data/app/models/shipit/deploy_spec/file_system.rb +35 -16
- data/app/models/shipit/deploy_spec/kubernetes_discovery.rb +4 -3
- data/app/models/shipit/deploy_spec/lerna_discovery.rb +32 -31
- data/app/models/shipit/deploy_spec/npm_discovery.rb +18 -13
- data/app/models/shipit/deploy_spec/pypi_discovery.rb +5 -4
- data/app/models/shipit/deploy_spec/rubygems_discovery.rb +1 -0
- data/app/models/shipit/deploy_spec.rb +25 -30
- data/app/models/shipit/deploy_stats.rb +6 -1
- data/app/models/shipit/duration.rb +5 -3
- data/app/models/shipit/ephemeral_commit_checks.rb +8 -7
- data/app/models/shipit/github_hook.rb +1 -0
- data/app/models/shipit/github_status.rb +1 -0
- data/app/models/shipit/hook.rb +8 -6
- data/app/models/shipit/membership.rb +1 -0
- data/app/models/shipit/merge_request.rb +26 -16
- data/app/models/shipit/output_chunk.rb +1 -0
- data/app/models/shipit/provisioning_handler.rb +1 -0
- data/app/models/shipit/pull_request.rb +1 -1
- data/app/models/shipit/record.rb +1 -0
- data/app/models/shipit/release_status.rb +4 -3
- data/app/models/shipit/repository.rb +12 -11
- data/app/models/shipit/review_stack.rb +3 -1
- data/app/models/shipit/review_stack_provisioning_queue.rb +2 -2
- data/app/models/shipit/rollback.rb +2 -0
- data/app/models/shipit/stack.rb +59 -56
- data/app/models/shipit/status/common.rb +1 -0
- data/app/models/shipit/status/group.rb +5 -3
- data/app/models/shipit/status/missing.rb +2 -1
- data/app/models/shipit/status/unknown.rb +1 -0
- data/app/models/shipit/status.rb +5 -4
- data/app/models/shipit/task.rb +33 -28
- data/app/models/shipit/task_definition.rb +10 -7
- data/app/models/shipit/task_execution_strategy/default.rb +13 -13
- data/app/models/shipit/team.rb +13 -12
- data/app/models/shipit/undeployed_commit.rb +8 -3
- data/app/models/shipit/unlimited_api_client.rb +2 -2
- data/app/models/shipit/user.rb +21 -16
- data/app/models/shipit/variable_definition.rb +2 -1
- data/app/models/shipit/webhooks/handlers/check_suite_handler.rb +1 -0
- data/app/models/shipit/webhooks/handlers/handler.rb +1 -0
- data/app/models/shipit/webhooks/handlers/membership_handler.rb +1 -0
- data/app/models/shipit/webhooks/handlers/pull_request/assigned_handler.rb +10 -10
- data/app/models/shipit/webhooks/handlers/pull_request/closed_handler.rb +1 -1
- data/app/models/shipit/webhooks/handlers/pull_request/edited_handler.rb +10 -10
- data/app/models/shipit/webhooks/handlers/pull_request/label_capturing_handler.rb +2 -2
- data/app/models/shipit/webhooks/handlers/pull_request/labeled_handler.rb +2 -2
- data/app/models/shipit/webhooks/handlers/pull_request/reopened_handler.rb +1 -1
- data/app/models/shipit/webhooks/handlers/pull_request/review_stack_adapter.rb +3 -3
- data/app/models/shipit/webhooks/handlers/pull_request/unlabeled_handler.rb +1 -1
- data/app/models/shipit/webhooks/handlers/push_handler.rb +2 -1
- data/app/models/shipit/webhooks/handlers/status_handler.rb +1 -0
- data/app/models/shipit/webhooks.rb +3 -2
- 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 +2 -1
- data/app/serializers/shipit/deploy_serializer.rb +1 -0
- data/app/serializers/shipit/hook_serializer.rb +1 -0
- data/app/serializers/shipit/merge_request_serializer.rb +2 -1
- 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 +4 -3
- data/app/serializers/shipit/tail_task_serializer.rb +4 -1
- data/app/serializers/shipit/task_serializer.rb +1 -0
- data/app/serializers/shipit/user_serializer.rb +1 -0
- data/app/validators/ascii_only_validator.rb +4 -3
- data/app/validators/subset_validator.rb +1 -0
- data/app/views/shipit/ccmenu/project.xml.builder +2 -1
- data/app/views/shipit/continuous_delivery_schedules/show.html.erb +59 -0
- data/app/views/shipit/stacks/_settings_form.erb +1 -0
- data/config/initializers/inflections.rb +1 -0
- data/config/locales/en.yml +1 -0
- data/config/routes.rb +21 -18
- data/db/migrate/20240821003007_add_continuous_delivery_schedules.rb +13 -0
- data/db/migrate/20250207203053_embiggen_github_ids.rb +8 -0
- data/lib/shipit/cast_value.rb +1 -0
- data/lib/shipit/command.rb +29 -9
- data/lib/shipit/commands.rb +4 -2
- data/lib/shipit/csv_serializer.rb +3 -0
- data/lib/shipit/deploy_commands.rb +2 -1
- data/lib/shipit/engine.rb +5 -4
- data/lib/shipit/environment_variables.rb +2 -0
- data/lib/shipit/first_parent_commits_iterator.rb +2 -3
- data/lib/shipit/flock.rb +11 -9
- data/lib/shipit/github_app.rb +14 -15
- data/lib/shipit/github_http_cache_middleware.rb +1 -0
- data/lib/shipit/null_serializer.rb +1 -0
- data/lib/shipit/octokit_check_runs.rb +1 -0
- data/lib/shipit/octokit_iterator.rb +2 -0
- data/lib/shipit/paginator.rb +1 -0
- data/lib/shipit/rollback_commands.rb +2 -1
- data/lib/shipit/same_site_cookie_middleware.rb +1 -0
- data/lib/shipit/simple_message_verifier.rb +1 -0
- data/lib/shipit/stack_commands.rb +34 -26
- data/lib/shipit/stat.rb +1 -0
- data/lib/shipit/task_commands.rb +7 -6
- data/lib/shipit/version.rb +2 -1
- data/lib/shipit.rb +29 -16
- data/lib/tasks/cron.rake +2 -1
- data/lib/tasks/dev.rake +3 -2
- data/lib/tasks/shipit.rake +3 -2
- data/lib/tasks/teams.rake +3 -2
- data/test/controllers/api/base_controller_test.rb +1 -0
- data/test/controllers/api/ccmenu_controller_test.rb +4 -3
- data/test/controllers/api/commits_controller_test.rb +1 -0
- data/test/controllers/api/deploys_controller_test.rb +2 -1
- data/test/controllers/api/hooks_controller_test.rb +6 -5
- data/test/controllers/api/locks_controller_test.rb +1 -0
- data/test/controllers/api/merge_requests_controller_test.rb +1 -0
- data/test/controllers/api/outputs_controller_test.rb +1 -0
- data/test/controllers/api/release_statuses_controller_test.rb +4 -3
- data/test/controllers/api/rollback_controller_test.rb +3 -2
- data/test/controllers/api/stacks_controller_test.rb +13 -12
- data/test/controllers/api/tasks_controller_test.rb +7 -6
- data/test/controllers/api_clients_controller_test.rb +10 -10
- data/test/controllers/ccmenu_controller_test.rb +1 -0
- data/test/controllers/commit_checks_controller_test.rb +1 -0
- data/test/controllers/commits_controller_test.rb +9 -8
- data/test/controllers/continuous_delivery_schedules_controller_test.rb +66 -0
- data/test/controllers/deploys_controller_test.rb +4 -2
- data/test/controllers/github_authentication_controller_test.rb +6 -4
- data/test/controllers/merge_requests_controller_test.rb +1 -0
- data/test/controllers/merge_status_controller_test.rb +5 -4
- data/test/controllers/release_statuses_controller_test.rb +1 -0
- data/test/controllers/repositories_controller_test.rb +6 -5
- data/test/controllers/rollbacks_controller_test.rb +3 -2
- data/test/controllers/stacks_controller_test.rb +7 -5
- data/test/controllers/status_controller_test.rb +1 -0
- data/test/controllers/tasks_controller_test.rb +5 -4
- data/test/controllers/webhooks_controller_test.rb +10 -9
- data/test/dummy/config/application.rb +1 -1
- data/test/dummy/db/schema.rb +33 -6
- data/test/fixtures/shipit/commits.yml +7 -7
- data/test/fixtures/shipit/stacks.yml +4 -10
- data/test/fixtures/shipit/tasks.yml +3 -3
- data/test/helpers/api_helper.rb +2 -3
- data/test/helpers/fixture_aliases_helper.rb +1 -0
- data/test/helpers/hooks_helper.rb +1 -0
- data/test/helpers/json_helper.rb +4 -3
- data/test/helpers/links_helper.rb +2 -1
- data/test/helpers/payloads_helper.rb +1 -0
- data/test/helpers/queries_helper.rb +4 -3
- data/test/jobs/cache_deploy_spec_job_test.rb +3 -2
- data/test/jobs/chunk_rollup_job_test.rb +3 -2
- data/test/jobs/deliver_hook_job_test.rb +1 -0
- data/test/jobs/destroy_repository_job_test.rb +1 -0
- data/test/jobs/destroy_stack_job_test.rb +12 -0
- data/test/jobs/emit_event_job_test.rb +1 -0
- 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 +22 -21
- data/test/jobs/mark_deploy_healthy_job_test.rb +1 -0
- data/test/jobs/perform_task_job_test.rb +3 -3
- data/test/jobs/process_merge_requests_job_test.rb +7 -6
- data/test/jobs/purge_old_deliveries_job_test.rb +1 -0
- data/test/jobs/reap_dead_tasks_job_test.rb +1 -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/shipit/background_job_test.rb +35 -0
- data/test/jobs/shipit/continuous_delivery_job_test.rb +31 -0
- data/test/jobs/unique_job_test.rb +3 -1
- data/test/jobs/update_github_last_deployed_ref_job_test.rb +1 -0
- data/test/middleware/same_site_cookie_middleware_test.rb +2 -2
- data/test/models/api_client_test.rb +1 -0
- data/test/models/commit_checks_test.rb +2 -1
- data/test/models/commit_deployment_status_test.rb +2 -1
- data/test/models/commit_deployment_test.rb +4 -3
- data/test/models/commits_test.rb +72 -70
- data/test/models/delivery_test.rb +3 -2
- data/test/models/deploy_spec_test.rb +113 -109
- data/test/models/deploy_stats_test.rb +1 -0
- data/test/models/deploys_test.rb +65 -56
- data/test/models/duration_test.rb +1 -1
- data/test/models/github_hook_test.rb +1 -0
- data/test/models/hook_test.rb +7 -4
- data/test/models/membership_test.rb +1 -0
- data/test/models/merge_request_test.rb +23 -20
- data/test/models/release_statuses_test.rb +2 -1
- data/test/models/rollbacks_test.rb +4 -3
- data/test/models/shipit/check_run_test.rb +16 -15
- data/test/models/shipit/continuous_delivery_schedule_test.rb +109 -0
- data/test/models/shipit/deploy_spec/file_system_test.rb +54 -10
- data/test/models/shipit/pull_request_test.rb +9 -9
- data/test/models/shipit/repository_test.rb +3 -2
- data/test/models/shipit/review_stack_provisioning_queue_test.rb +2 -2
- data/test/models/shipit/stack_test.rb +30 -29
- data/test/models/shipit/webhooks/handlers/pull_request/closed_handler_test.rb +36 -34
- data/test/models/shipit/webhooks/handlers/pull_request/label_capturing_handler_test.rb +28 -28
- data/test/models/shipit/webhooks/handlers/pull_request/labeled_handler_test.rb +42 -42
- data/test/models/shipit/webhooks/handlers/pull_request/opened_handler_test.rb +33 -33
- data/test/models/shipit/webhooks/handlers/pull_request/reopened_handler_test.rb +37 -37
- data/test/models/shipit/webhooks/handlers/pull_request/review_stack_adapter_test.rb +1 -1
- data/test/models/shipit/webhooks/handlers/pull_request/unlabeled_handler_test.rb +44 -42
- data/test/models/shipit/webhooks/handlers_test.rb +1 -0
- data/test/models/status/group_test.rb +3 -2
- data/test/models/status/missing_test.rb +1 -0
- data/test/models/status_test.rb +2 -1
- data/test/models/task_definitions_test.rb +7 -6
- data/test/models/tasks_test.rb +5 -4
- data/test/models/team_test.rb +5 -4
- data/test/models/undeployed_commits_test.rb +10 -9
- data/test/models/users_test.rb +21 -20
- data/test/test_command_integration.rb +1 -1
- data/test/test_helper.rb +11 -9
- data/test/unit/anonymous_user_serializer_test.rb +1 -0
- data/test/unit/command_test.rb +10 -1
- data/test/unit/commands_test.rb +1 -0
- data/test/unit/commit_serializer_test.rb +1 -0
- data/test/unit/csv_serializer_test.rb +3 -2
- data/test/unit/deploy_commands_test.rb +33 -23
- data/test/unit/deploy_serializer_test.rb +1 -0
- data/test/unit/environment_variables_test.rb +2 -1
- data/test/unit/github_app_test.rb +10 -9
- data/test/unit/github_apps_test.rb +19 -18
- data/test/unit/github_url_helper_test.rb +1 -0
- data/test/unit/line_buffer_test.rb +1 -1
- data/test/unit/rollback_commands_test.rb +2 -1
- data/test/unit/shipit_helper_test.rb +1 -0
- data/test/unit/shipit_test.rb +47 -1
- data/test/unit/user_serializer_test.rb +1 -0
- data/test/unit/variable_definition_test.rb +4 -3
- metadata +53 -43
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module Shipit
|
3
4
|
class CommitDeployment < Record
|
4
5
|
belongs_to :task
|
@@ -11,8 +12,8 @@ module Shipit
|
|
11
12
|
def create_on_github!
|
12
13
|
create_deployment_on_github!
|
13
14
|
statuses.order(id: :asc).each(&:create_on_github!)
|
14
|
-
rescue Octokit::NotFound, Octokit::Forbidden =>
|
15
|
-
Rails.logger.warn("Got #{
|
15
|
+
rescue Octokit::NotFound, Octokit::Forbidden => e
|
16
|
+
Rails.logger.warn("Got #{e.class.name} creating deployment or statuses: #{e.message}")
|
16
17
|
# If no one can create the deployment we can only give up
|
17
18
|
end
|
18
19
|
|
@@ -23,6 +24,7 @@ module Shipit
|
|
23
24
|
create_deployment_on_github(stack.github_api)
|
24
25
|
rescue Octokit::ClientError
|
25
26
|
raise if Shipit.github(organization: stack.repository.owner).api == stack.github_api
|
27
|
+
|
26
28
|
# If the deploy author didn't gave us the permission to create the deployment we falback the the main shipit
|
27
29
|
# user.
|
28
30
|
#
|
@@ -55,9 +57,9 @@ module Shipit
|
|
55
57
|
shipit: {
|
56
58
|
task_id: task.id,
|
57
59
|
from_sha: task.since_commit.sha,
|
58
|
-
to_sha: task.until_commit.sha
|
59
|
-
}
|
60
|
-
}.to_json
|
60
|
+
to_sha: task.until_commit.sha
|
61
|
+
}
|
62
|
+
}.to_json
|
61
63
|
)
|
62
64
|
end
|
63
65
|
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module Shipit
|
3
4
|
class CommitDeploymentStatus < Record
|
4
5
|
DESCRIPTION_CHARACTER_LIMIT_ON_GITHUB = 140
|
@@ -11,10 +12,12 @@ module Shipit
|
|
11
12
|
|
12
13
|
def create_on_github!
|
13
14
|
return if github_id?
|
15
|
+
|
14
16
|
response = begin
|
15
17
|
create_status_on_github(stack.github_api)
|
16
18
|
rescue Octokit::ClientError
|
17
19
|
raise if Shipit.github(organization: stack.repository.owner).api == stack.github_api
|
20
|
+
|
18
21
|
# If the deploy author didn't gave us the permission to create the deployment we falback the the main shipit
|
19
22
|
# user.
|
20
23
|
#
|
@@ -30,7 +33,7 @@ module Shipit
|
|
30
33
|
"deployment_description.#{task_type}.#{status}",
|
31
34
|
sha: task.until_commit.short_sha,
|
32
35
|
author: task.author.login,
|
33
|
-
stack: stack.to_param
|
36
|
+
stack: stack.to_param
|
34
37
|
)
|
35
38
|
end
|
36
39
|
|
@@ -50,7 +53,7 @@ module Shipit
|
|
50
53
|
status,
|
51
54
|
target_url: url_helpers.stack_deploy_url(stack, task),
|
52
55
|
description: description.truncate(DESCRIPTION_CHARACTER_LIMIT_ON_GITHUB),
|
53
|
-
environment_url: stack.deploy_url
|
56
|
+
environment_url: stack.deploy_url
|
54
57
|
)
|
55
58
|
end
|
56
59
|
|
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module Shipit
|
3
4
|
class CommitMessage
|
4
5
|
GITHUB_MERGE_COMMIT_PATTERN = /\AMerge pull request #(?<pr_id>\d+) from \S+\n\n(?<pr_title>.*)/
|
@@ -27,6 +28,7 @@ module Shipit
|
|
27
28
|
|
28
29
|
def parsed
|
29
30
|
return @parsed if defined?(@parsed)
|
31
|
+
|
30
32
|
@parsed = to_s.match(GITHUB_MERGE_COMMIT_PATTERN)
|
31
33
|
end
|
32
34
|
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Shipit
|
4
|
+
class ContinuousDeliverySchedule < Record
|
5
|
+
belongs_to(:stack)
|
6
|
+
|
7
|
+
DAYS = %w[sunday monday tuesday wednesday thursday friday saturday].freeze
|
8
|
+
|
9
|
+
validates(
|
10
|
+
*DAYS.map { |day| "#{day}_enabled" },
|
11
|
+
inclusion: [true, false]
|
12
|
+
)
|
13
|
+
|
14
|
+
validates(
|
15
|
+
*DAYS.product([:start, :end]).map { |parts| parts.join("_") },
|
16
|
+
presence: true
|
17
|
+
)
|
18
|
+
|
19
|
+
validate(:validate_time_windows)
|
20
|
+
|
21
|
+
DeploymentWindow = Struct.new(:starts_at, :ends_at, :enabled) do
|
22
|
+
alias_method :enabled?, :enabled
|
23
|
+
end
|
24
|
+
|
25
|
+
def can_deploy?(now = Time.current)
|
26
|
+
# Make sure time is in the default time zone so weekdays match what is
|
27
|
+
# stored in the database.
|
28
|
+
now = now.in_time_zone(Time.zone)
|
29
|
+
|
30
|
+
deployment_window = get_deployment_window(now.to_date)
|
31
|
+
|
32
|
+
deployment_window.enabled? &&
|
33
|
+
now >= deployment_window.starts_at &&
|
34
|
+
now <= deployment_window.ends_at
|
35
|
+
end
|
36
|
+
|
37
|
+
def get_deployment_window(date)
|
38
|
+
wday_name = DAYS.fetch(date.wday)
|
39
|
+
|
40
|
+
enabled = read_attribute("#{wday_name}_enabled")
|
41
|
+
|
42
|
+
starts_at, ends_at = [:start, :end].map do |bound|
|
43
|
+
raw_time = read_attribute("#{wday_name}_#{bound}")
|
44
|
+
|
45
|
+
# `ActiveRecord::Type::Time` attributes are stored as timestamps
|
46
|
+
# normalized to 2000-01-01 so they can't be used for comparisons without
|
47
|
+
# having their dates adjusted.
|
48
|
+
# https://github.com/rails/rails/blob/ec667e5f114df58087493096253541f1034815af/activemodel/lib/active_model/type/time.rb#L23
|
49
|
+
Time.zone.local(
|
50
|
+
date.year,
|
51
|
+
date.month,
|
52
|
+
date.day,
|
53
|
+
raw_time.hour,
|
54
|
+
raw_time.min
|
55
|
+
)
|
56
|
+
end
|
57
|
+
|
58
|
+
DeploymentWindow.new(
|
59
|
+
starts_at,
|
60
|
+
# Includes the full minute in the configured range. This is required so
|
61
|
+
# that a window configured to end at 17:59 actually ends at 17:59:59
|
62
|
+
# instead of 17:59:00.
|
63
|
+
ends_at.at_end_of_minute,
|
64
|
+
enabled
|
65
|
+
)
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
# Make sure every `*_end` attribute comes after its matching `*_start`
|
71
|
+
# attribute
|
72
|
+
def validate_time_windows
|
73
|
+
DAYS.each do |day|
|
74
|
+
day_start, day_end = [:start, :end].map { |bound| read_attribute("#{day}_#{bound}") }
|
75
|
+
|
76
|
+
next unless day_start && day_end
|
77
|
+
|
78
|
+
next if day_start <= day_end
|
79
|
+
|
80
|
+
errors.add("#{day}_end", :must_be_after_start, start: day_start.strftime("%I:%M %p"))
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -1,8 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module Shipit
|
3
4
|
class Delivery < Record
|
4
|
-
STATUSES = %w
|
5
|
-
enum status
|
5
|
+
STATUSES = %w[pending scheduled sent].freeze
|
6
|
+
enum :status, STATUSES.zip(STATUSES).to_h
|
6
7
|
|
7
8
|
belongs_to :hook
|
8
9
|
|
@@ -47,7 +48,7 @@ module Shipit
|
|
47
48
|
'Content-Type' => content_type,
|
48
49
|
'X-Shipit-Event' => event,
|
49
50
|
'X-Shipit-Delivery' => id.to_s,
|
50
|
-
'Accept' => '*/*'
|
51
|
+
'Accept' => '*/*'
|
51
52
|
}
|
52
53
|
end
|
53
54
|
end
|
data/app/models/shipit/deploy.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'fileutils'
|
3
4
|
|
4
5
|
module Shipit
|
@@ -26,7 +27,7 @@ module Shipit
|
|
26
27
|
'success' => 'success',
|
27
28
|
'faulty' => 'error',
|
28
29
|
'error' => 'error',
|
29
|
-
'aborted' => 'error'
|
30
|
+
'aborted' => 'error'
|
30
31
|
}.freeze
|
31
32
|
|
32
33
|
def append_status(task_status)
|
@@ -37,7 +38,7 @@ module Shipit
|
|
37
38
|
"Creating #{github_status} deploy status for deployment #{deployment.id}. "\
|
38
39
|
"Commit: #{deployment.sha}, Github id: #{deployment.github_id}, "\
|
39
40
|
"Repo: #{deployment.stack.repo_name}, Environment: #{deployment.stack.environment}, "\
|
40
|
-
"API Url: #{deployment.api_url}."
|
41
|
+
"API Url: #{deployment.api_url}."
|
41
42
|
)
|
42
43
|
deployment.statuses.create!(status: github_status)
|
43
44
|
end
|
@@ -47,7 +48,7 @@ module Shipit
|
|
47
48
|
"No GitHub status for task status #{task_status}. "\
|
48
49
|
"Commit: #{deployment.sha}, Github id: #{deployment.github_id}, "\
|
49
50
|
"Repo: #{deployment.stack.repo_name}, Environment: #{deployment.stack.environment}, "\
|
50
|
-
"API Url: #{deployment.api_url}."
|
51
|
+
"API Url: #{deployment.api_url}."
|
51
52
|
)
|
52
53
|
end
|
53
54
|
end
|
@@ -64,70 +65,75 @@ module Shipit
|
|
64
65
|
|
65
66
|
def self.newer_than(deploy)
|
66
67
|
return all unless deploy
|
68
|
+
|
67
69
|
where('id > ?', deploy.try(:id) || deploy)
|
68
70
|
end
|
69
71
|
|
70
72
|
def self.older_than(deploy)
|
71
73
|
return all unless deploy
|
74
|
+
|
72
75
|
where('id < ?', deploy.try(:id) || deploy)
|
73
76
|
end
|
74
77
|
|
75
78
|
def self.since(deploy)
|
76
79
|
return all unless deploy
|
80
|
+
|
77
81
|
where('id >= ?', deploy.try(:id) || deploy)
|
78
82
|
end
|
79
83
|
|
80
84
|
def self.until(deploy)
|
81
85
|
return all unless deploy
|
86
|
+
|
82
87
|
where('id <= ?', deploy.try(:id) || deploy)
|
83
88
|
end
|
84
89
|
|
85
90
|
def build_rollback(user = nil, env: nil, force: false)
|
86
91
|
Rollback.new(
|
87
92
|
user_id: user&.id,
|
88
|
-
stack_id
|
93
|
+
stack_id:,
|
89
94
|
parent_id: id,
|
90
95
|
since_commit: stack.last_deployed_commit,
|
91
|
-
until_commit
|
92
|
-
env: env
|
96
|
+
until_commit:,
|
97
|
+
env: env.to_h,
|
93
98
|
allow_concurrency: force,
|
94
99
|
ignored_safeties: force,
|
95
|
-
max_retries: stack.retries_on_rollback
|
100
|
+
max_retries: stack.retries_on_rollback
|
96
101
|
)
|
97
102
|
end
|
98
103
|
|
99
104
|
# Rolls the stack back to this deploy
|
100
105
|
def trigger_rollback(user = AnonymousUser.new, env: nil, force: false, lock: true)
|
101
|
-
rollback = build_rollback(user, env
|
106
|
+
rollback = build_rollback(user, env:, force:)
|
102
107
|
rollback.save!
|
103
108
|
rollback.enqueue
|
104
109
|
|
105
110
|
if lock
|
106
111
|
lock_reason = "A rollback for #{rollback.since_commit.sha} has been triggered. " \
|
107
112
|
"Please make sure the reason for the rollback has been addressed before deploying again."
|
108
|
-
stack.update!(lock_reason
|
113
|
+
stack.update!(lock_reason:, lock_author_id: user.id)
|
109
114
|
end
|
110
115
|
|
111
116
|
rollback
|
112
117
|
end
|
113
118
|
|
114
119
|
# Rolls the stack back to the most recent **previous** successful deploy
|
115
|
-
def trigger_revert(force: false, rollback_to: nil)
|
120
|
+
def trigger_revert(force: false, rollback_to: nil, env: nil)
|
116
121
|
previous_successful_commit = rollback_to&.until_commit || commit_to_rollback_to
|
117
122
|
|
118
123
|
rollback = Rollback.create!(
|
119
|
-
user_id
|
120
|
-
stack_id
|
124
|
+
user_id:,
|
125
|
+
stack_id:,
|
121
126
|
parent_id: id,
|
122
127
|
since_commit: until_commit,
|
123
128
|
until_commit: previous_successful_commit,
|
124
|
-
|
129
|
+
env: env || self.env,
|
130
|
+
allow_concurrency: force
|
125
131
|
)
|
126
132
|
|
127
133
|
rollback.enqueue
|
128
134
|
lock_reason = "A rollback for #{until_commit.sha} has been triggered. " \
|
129
135
|
"Please make sure the reason for the rollback has been addressed before deploying again."
|
130
|
-
stack.update!(lock_reason
|
136
|
+
stack.update!(lock_reason:, lock_author_id: user_id)
|
131
137
|
stack.emit_lock_hooks
|
132
138
|
rollback
|
133
139
|
end
|
@@ -176,6 +182,7 @@ module Shipit
|
|
176
182
|
|
177
183
|
def reject!
|
178
184
|
return if failed? || aborted?
|
185
|
+
|
179
186
|
transaction do
|
180
187
|
flap! unless flapping?
|
181
188
|
update!(confirmations: [confirmations - 1, -1].min)
|
@@ -185,6 +192,7 @@ module Shipit
|
|
185
192
|
|
186
193
|
def accept!
|
187
194
|
return if success?
|
195
|
+
|
188
196
|
transaction do
|
189
197
|
flap! unless flapping?
|
190
198
|
update!(confirmations: [confirmations + 1, 1].max)
|
@@ -198,13 +206,12 @@ module Shipit
|
|
198
206
|
|
199
207
|
delegate :last_release_status, to: :until_commit
|
200
208
|
def append_release_status(state, description, user: self.user)
|
201
|
-
|
209
|
+
until_commit.create_release_status!(
|
202
210
|
state,
|
203
211
|
user: user.presence,
|
204
212
|
target_url: permalink,
|
205
|
-
description:
|
213
|
+
description:
|
206
214
|
)
|
207
|
-
status
|
208
215
|
end
|
209
216
|
|
210
217
|
def permalink
|
@@ -225,7 +232,7 @@ module Shipit
|
|
225
232
|
append_release_status(
|
226
233
|
'success',
|
227
234
|
description,
|
228
|
-
user:
|
235
|
+
user:
|
229
236
|
)
|
230
237
|
end
|
231
238
|
end
|
@@ -236,7 +243,7 @@ module Shipit
|
|
236
243
|
append_release_status(
|
237
244
|
'failure',
|
238
245
|
description,
|
239
|
-
user:
|
246
|
+
user:
|
240
247
|
)
|
241
248
|
end
|
242
249
|
end
|
@@ -254,6 +261,7 @@ module Shipit
|
|
254
261
|
# Create one for each pull request in the batch, to give feedback on the PR timeline
|
255
262
|
commits.select(&:pull_request?).each do |commit|
|
256
263
|
next if commit.pull_request_head_sha.blank? # This attribute was not always populated
|
264
|
+
|
257
265
|
commit_deployments.create!(sha: commit.pull_request_head_sha)
|
258
266
|
end
|
259
267
|
|
@@ -272,13 +280,17 @@ module Shipit
|
|
272
280
|
when 'aborted', 'aborting'
|
273
281
|
append_release_status('failure', "The deploy on #{stack.environment} was canceled")
|
274
282
|
when 'validating'
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
283
|
+
unless stack.release_status_delay.zero?
|
284
|
+
append_release_status(
|
285
|
+
'pending',
|
286
|
+
"The deploy on #{stack.environment} succeeded"
|
287
|
+
)
|
288
|
+
end
|
279
289
|
|
280
|
-
|
281
|
-
.
|
290
|
+
if stack.release_status_delay.positive?
|
291
|
+
MarkDeployHealthyJob.set(wait: stack.release_status_delay)
|
292
|
+
.perform_later(self)
|
293
|
+
end
|
282
294
|
when 'success'
|
283
295
|
if stack.release_status_delay.zero?
|
284
296
|
append_release_status('success', "The deploy on #{stack.environment} succeeded")
|
@@ -289,11 +301,17 @@ module Shipit
|
|
289
301
|
def trigger_revert_if_required
|
290
302
|
return unless rollback_once_aborted?
|
291
303
|
return unless supports_rollback?
|
292
|
-
|
304
|
+
|
305
|
+
if rollback_once_aborted_to
|
306
|
+
rollback_once_aborted_to.trigger_rollback(aborted_by, env:, force: true)
|
307
|
+
else
|
308
|
+
trigger_revert(force: true, env:)
|
309
|
+
end
|
293
310
|
end
|
294
311
|
|
295
312
|
def default_since_commit_id
|
296
313
|
return unless stack
|
314
|
+
|
297
315
|
@default_since_commit_id ||= stack.last_completed_deploy&.until_commit_id
|
298
316
|
end
|
299
317
|
|
@@ -308,6 +326,7 @@ module Shipit
|
|
308
326
|
|
309
327
|
def schedule_continuous_delivery
|
310
328
|
return unless stack.continuous_deployment?
|
329
|
+
|
311
330
|
ContinuousDeliveryJob.perform_later(stack)
|
312
331
|
end
|
313
332
|
|
@@ -321,6 +340,7 @@ module Shipit
|
|
321
340
|
|
322
341
|
def update_latest_deployed_ref
|
323
342
|
return unless previous_changes.include?(:status)
|
343
|
+
|
324
344
|
stack.update_latest_deployed_ref if previous_changes[:status].last == 'success'
|
325
345
|
end
|
326
346
|
end
|
@@ -1,8 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module Shipit
|
3
4
|
class DeploySpec
|
4
5
|
module BundlerDiscovery
|
5
|
-
DEFAULT_BUNDLER_WITHOUT = %w
|
6
|
+
DEFAULT_BUNDLER_WITHOUT = %w[default production development test staging benchmark debug].freeze
|
6
7
|
|
7
8
|
def discover_dependencies_steps
|
8
9
|
discover_bundler || super
|
@@ -43,6 +44,7 @@ module Shipit
|
|
43
44
|
def frozen_flag
|
44
45
|
return unless gemfile_lock_exists?
|
45
46
|
return if config('dependencies', 'bundler', 'frozen') == false
|
47
|
+
|
46
48
|
'--frozen'
|
47
49
|
end
|
48
50
|
|
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module Shipit
|
3
4
|
class DeploySpec
|
4
5
|
class FileSystem < DeploySpec
|
@@ -10,9 +11,12 @@ module Shipit
|
|
10
11
|
include BundlerDiscovery
|
11
12
|
include KubernetesDiscovery
|
12
13
|
|
13
|
-
|
14
|
+
attr_reader :stack
|
15
|
+
|
16
|
+
def initialize(app_dir, stack)
|
14
17
|
@app_dir = Pathname(app_dir)
|
15
|
-
@env =
|
18
|
+
@env = stack.environment
|
19
|
+
@stack = stack
|
16
20
|
super(nil)
|
17
21
|
end
|
18
22
|
|
@@ -39,29 +43,29 @@ module Shipit
|
|
39
43
|
'method' => merge_request_merge_method,
|
40
44
|
'max_divergence' => {
|
41
45
|
'commits' => max_divergence_commits&.to_i,
|
42
|
-
'age' => max_divergence_age&.to_i
|
43
|
-
}
|
46
|
+
'age' => max_divergence_age&.to_i
|
47
|
+
}
|
44
48
|
},
|
45
49
|
'ci' => {
|
46
50
|
'hide' => hidden_statuses,
|
47
51
|
'allow_failures' => soft_failing_statuses,
|
48
52
|
'require' => required_statuses,
|
49
|
-
'blocking' => blocking_statuses
|
53
|
+
'blocking' => blocking_statuses
|
50
54
|
},
|
51
55
|
'machine' => {
|
52
56
|
'environment' => discover_machine_env.merge(machine_env),
|
53
57
|
'directory' => directory,
|
54
|
-
'cleanup' => true
|
58
|
+
'cleanup' => true
|
55
59
|
},
|
56
60
|
'review' => {
|
57
61
|
'checklist' => review_checklist,
|
58
62
|
'monitoring' => review_monitoring,
|
59
|
-
'checks' => review_checks
|
63
|
+
'checks' => review_checks
|
60
64
|
},
|
61
65
|
'plugins' => plugins,
|
62
66
|
'status' => {
|
63
67
|
'context' => release_status_context,
|
64
|
-
'delay' => release_status_delay
|
68
|
+
'delay' => release_status_delay
|
65
69
|
},
|
66
70
|
'dependencies' => { 'override' => dependencies_steps },
|
67
71
|
'provision' => { 'handler_name' => provisioning_handler_name },
|
@@ -70,19 +74,19 @@ module Shipit
|
|
70
74
|
'variables' => deploy_variables.map(&:to_h),
|
71
75
|
'max_commits' => maximum_commits_per_deploy,
|
72
76
|
'interval' => pause_between_deploys,
|
73
|
-
'retries' => retries_on_deploy
|
77
|
+
'retries' => retries_on_deploy
|
74
78
|
},
|
75
79
|
'rollback' => {
|
76
80
|
'override' => rollback_steps,
|
77
|
-
'retries' => retries_on_rollback
|
81
|
+
'retries' => retries_on_rollback
|
78
82
|
},
|
79
83
|
'fetch' => fetch_deployed_revision_steps,
|
80
|
-
'tasks' => cacheable_tasks
|
84
|
+
'tasks' => cacheable_tasks
|
81
85
|
)
|
82
86
|
end
|
83
87
|
|
84
88
|
def cacheable_tasks
|
85
|
-
discover_task_definitions.
|
89
|
+
discover_task_definitions.transform_values { |c| coerce_task_definition(c) }
|
86
90
|
end
|
87
91
|
|
88
92
|
def config(*)
|
@@ -97,7 +101,8 @@ module Shipit
|
|
97
101
|
return { 'deploy' => { 'pre' => [shipit_not_obeying_bare_file_echo_command, 'exit 1'] } }
|
98
102
|
end
|
99
103
|
|
100
|
-
read_config(config_file_path)
|
104
|
+
config_obj = read_config(config_file_path)
|
105
|
+
build_config(config_file_path, config_obj)
|
101
106
|
end
|
102
107
|
|
103
108
|
def shipit_file_names_in_priority_order
|
@@ -112,7 +117,7 @@ module Shipit
|
|
112
117
|
".shipit/#{@env}.yml",
|
113
118
|
|
114
119
|
"shipit.yml",
|
115
|
-
".shipit/shipit.yml"
|
120
|
+
".shipit/shipit.yml"
|
116
121
|
].uniq
|
117
122
|
end
|
118
123
|
|
@@ -133,16 +138,30 @@ module Shipit
|
|
133
138
|
@app_name ||= Shipit.app_name.downcase
|
134
139
|
end
|
135
140
|
|
141
|
+
SHIPIT_CONFIG_INHERIT_FROM_KEY = "inherit_from"
|
142
|
+
def build_config(path, config_obj)
|
143
|
+
return config_obj if config_obj.blank? || !config_obj.key?(SHIPIT_CONFIG_INHERIT_FROM_KEY)
|
144
|
+
|
145
|
+
inherits_from_path = path.dirname.join(config_obj.delete(SHIPIT_CONFIG_INHERIT_FROM_KEY))
|
146
|
+
if inherits_from_path.exist?
|
147
|
+
inherits_config_obj = read_config(inherits_from_path)
|
148
|
+
config_obj = inherits_config_obj.deep_merge(config_obj)
|
149
|
+
path = inherits_from_path
|
150
|
+
end
|
151
|
+
|
152
|
+
build_config(path, config_obj)
|
153
|
+
end
|
154
|
+
|
136
155
|
def read_config(path)
|
137
156
|
SafeYAML.load(path.read) if path.exist?
|
138
157
|
end
|
139
158
|
|
140
159
|
def shipit_not_obeying_bare_file_echo_command
|
141
|
-
<<~
|
160
|
+
<<~WARNING_MESSAGE
|
142
161
|
echo \"\e[1;31mShipit is configured to ignore the bare '#{app_name}.yml' file.
|
143
162
|
Please rename this file to more specifically include the environment name.
|
144
163
|
Deployments will fail until a valid '#{app_name}.#{@env}.yml' file is found.\e[0m\"
|
145
|
-
|
164
|
+
WARNING_MESSAGE
|
146
165
|
end
|
147
166
|
end
|
148
167
|
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module Shipit
|
3
4
|
class DeploySpec
|
4
5
|
module KubernetesDiscovery
|
@@ -16,8 +17,8 @@ module Shipit
|
|
16
17
|
'restart' => {
|
17
18
|
'action' => "Restart application",
|
18
19
|
'description' => "Simulates a rollout of Kubernetes deployments by using kubernetes-restart utility",
|
19
|
-
'steps' => [kubernetes_restart_cmd]
|
20
|
-
}
|
20
|
+
'steps' => [kubernetes_restart_cmd]
|
21
|
+
}
|
21
22
|
}.merge!(super)
|
22
23
|
else
|
23
24
|
super
|
@@ -55,7 +56,7 @@ module Shipit
|
|
55
56
|
cmd = [
|
56
57
|
"kubernetes-restart",
|
57
58
|
kube_config.fetch('namespace'),
|
58
|
-
kube_config.fetch('context')
|
59
|
+
kube_config.fetch('context')
|
59
60
|
]
|
60
61
|
cmd += ["--max-watch-seconds", timeout_duration] if timeout_duration
|
61
62
|
Shellwords.join(cmd)
|