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
data/lib/shipit/cast_value.rb
CHANGED
data/lib/shipit/command.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'pty'
|
2
3
|
require 'shellwords'
|
3
4
|
require 'fileutils'
|
@@ -27,7 +28,7 @@ module Shipit
|
|
27
28
|
|
28
29
|
def initialize(*args, default_timeout: Shipit.default_inactivity_timeout, env: {}, chdir:)
|
29
30
|
@args, options = parse_arguments(args)
|
30
|
-
@timeout = options['timeout'
|
31
|
+
@timeout = options['timeout'] || options[:timeout] || default_timeout
|
31
32
|
@env = env
|
32
33
|
@chdir = chdir.to_s
|
33
34
|
@timed_out = false
|
@@ -48,10 +49,7 @@ module Shipit
|
|
48
49
|
def interpolate_environment_variables(argument)
|
49
50
|
return argument.map { |a| interpolate_environment_variables(a) } if argument.is_a?(Array)
|
50
51
|
|
51
|
-
|
52
|
-
variable.sub!('$', '')
|
53
|
-
Shellwords.escape(@env.fetch(variable) { ENV[variable] })
|
54
|
-
end
|
52
|
+
EnvironmentVariables.with(env).interpolate(argument)
|
55
53
|
end
|
56
54
|
|
57
55
|
def success?
|
@@ -149,18 +147,16 @@ module Shipit
|
|
149
147
|
def read_stream(io)
|
150
148
|
touch_last_output_at
|
151
149
|
loop do
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
raise TimedOut
|
160
|
-
end
|
161
|
-
IO.select([io], nil, nil, 1)
|
162
|
-
retry
|
150
|
+
yield_control
|
151
|
+
yield io.read_nonblock(MAX_READ)
|
152
|
+
touch_last_output_at
|
153
|
+
rescue IO::WaitReadable
|
154
|
+
if output_timed_out?
|
155
|
+
@timed_out = true
|
156
|
+
raise TimedOut
|
163
157
|
end
|
158
|
+
IO.select([io], nil, nil, 1)
|
159
|
+
retry
|
164
160
|
end
|
165
161
|
rescue EOFError
|
166
162
|
end
|
@@ -196,7 +192,7 @@ module Shipit
|
|
196
192
|
# If we let the child a little bit of time, it solves it.
|
197
193
|
retry_count -= 1
|
198
194
|
if retry_count > 0
|
199
|
-
sleep
|
195
|
+
sleep(0.05)
|
200
196
|
retry
|
201
197
|
end
|
202
198
|
end
|
@@ -220,7 +216,7 @@ module Shipit
|
|
220
216
|
argument
|
221
217
|
end
|
222
218
|
end
|
223
|
-
|
219
|
+
[args, options]
|
224
220
|
end
|
225
221
|
|
226
222
|
def running?
|
data/lib/shipit/commands.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module Shipit
|
2
3
|
class Commands
|
3
4
|
class << self
|
@@ -6,13 +7,13 @@ module Shipit
|
|
6
7
|
end
|
7
8
|
|
8
9
|
def git_version
|
9
|
-
@git_version ||= parse_git_version(
|
10
|
+
@git_version ||= parse_git_version(%x(git --version))
|
10
11
|
end
|
11
12
|
|
12
13
|
def parse_git_version(raw_git_version)
|
13
|
-
|
14
|
-
raise 'git command not found' unless
|
15
|
-
Gem::Version.new(
|
14
|
+
match_info = raw_git_version.match(/(\d+\.\d+\.\d+)/)
|
15
|
+
raise 'git command not found' unless match_info
|
16
|
+
Gem::Version.new(match_info[1])
|
16
17
|
end
|
17
18
|
end
|
18
19
|
|
data/lib/shipit/engine.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module Shipit
|
2
3
|
class Engine < ::Rails::Engine
|
3
4
|
isolate_namespace Shipit
|
@@ -32,11 +33,19 @@ module Shipit
|
|
32
33
|
ActiveModel::Serializer.include(Engine.routes.url_helpers)
|
33
34
|
|
34
35
|
if Shipit.github.oauth?
|
35
|
-
OmniAuth::Strategies::GitHub.configure
|
36
|
-
app.middleware.use
|
36
|
+
OmniAuth::Strategies::GitHub.configure(path_prefix: '/github/auth')
|
37
|
+
app.middleware.use(OmniAuth::Builder) do
|
37
38
|
provider(:github, *Shipit.github.oauth_config)
|
38
39
|
end
|
39
40
|
end
|
41
|
+
|
42
|
+
if Shipit.enable_samesite_middleware?
|
43
|
+
app.config.middleware.insert_after(::Rack::Runtime, Shipit::SameSiteCookieMiddleware)
|
44
|
+
end
|
45
|
+
|
46
|
+
app.config.after_initialize do
|
47
|
+
ActionController::Base.include(Shipit::ActiveModelSerializersPatch)
|
48
|
+
end
|
40
49
|
end
|
41
50
|
end
|
42
51
|
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module Shipit
|
2
3
|
class EnvironmentVariables
|
3
4
|
NotPermitted = Class.new(StandardError)
|
@@ -14,6 +15,15 @@ module Shipit
|
|
14
15
|
sanitize_env_vars(variable_definitions)
|
15
16
|
end
|
16
17
|
|
18
|
+
def interpolate(argument)
|
19
|
+
return argument unless @env
|
20
|
+
|
21
|
+
argument.gsub(/(\$\w+)/) do |variable|
|
22
|
+
variable.sub!('$', '')
|
23
|
+
Shellwords.escape(@env.fetch(variable) { ENV[variable] })
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
17
27
|
private
|
18
28
|
|
19
29
|
def initialize(env)
|
@@ -26,7 +36,7 @@ module Shipit
|
|
26
36
|
allowed, disallowed = @env.partition { |k, _| allowed_variables.include?(k) }.map(&:to_h)
|
27
37
|
|
28
38
|
error_message = "Variables #{disallowed.keys.to_sentence} have not been whitelisted"
|
29
|
-
raise NotPermitted
|
39
|
+
raise NotPermitted, error_message unless disallowed.empty?
|
30
40
|
|
31
41
|
allowed
|
32
42
|
end
|
data/lib/shipit/flock.rb
CHANGED
data/lib/shipit/github_app.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module Shipit
|
2
3
|
class GitHubApp
|
3
4
|
include Mutex_m
|
@@ -9,6 +10,8 @@ module Shipit
|
|
9
10
|
end
|
10
11
|
end
|
11
12
|
|
13
|
+
attr_reader :expires_at, :refresh_at
|
14
|
+
|
12
15
|
def to_s
|
13
16
|
@token
|
14
17
|
end
|
@@ -16,15 +19,26 @@ module Shipit
|
|
16
19
|
def initialize(token, expires_at)
|
17
20
|
@token = token
|
18
21
|
@expires_at = expires_at
|
22
|
+
|
23
|
+
# This needs to be lower than the token's lifetime, but higher than the cache expiry setting.
|
24
|
+
@refresh_at = expires_at - GITHUB_TOKEN_REFRESH_WINDOW
|
19
25
|
end
|
20
26
|
|
21
27
|
def blank?
|
22
|
-
@
|
28
|
+
# Old tokens missing @refresh_at may be used upon deploy, so we should auto-correct for now.
|
29
|
+
# TODO: Remove this assignment at a later date.
|
30
|
+
@refresh_at ||= @expires_at - GITHUB_TOKEN_REFRESH_WINDOW
|
31
|
+
@refresh_at.past?
|
23
32
|
end
|
24
33
|
end
|
25
34
|
|
26
|
-
DOMAIN = 'github.com'
|
35
|
+
DOMAIN = 'github.com'
|
27
36
|
AuthenticationFailed = Class.new(StandardError)
|
37
|
+
API_STATUS_ID = 'brv1bkgrwx7q'
|
38
|
+
|
39
|
+
GITHUB_EXPECTED_TOKEN_LIFETIME = 60.minutes
|
40
|
+
GITHUB_TOKEN_RAILS_CACHE_LIFETIME = 50.minutes
|
41
|
+
GITHUB_TOKEN_REFRESH_WINDOW = GITHUB_EXPECTED_TOKEN_LIFETIME - GITHUB_TOKEN_RAILS_CACHE_LIFETIME - 2.minutes
|
28
42
|
|
29
43
|
attr_reader :oauth_teams, :domain, :bot_login
|
30
44
|
|
@@ -53,6 +67,13 @@ module Shipit
|
|
53
67
|
client
|
54
68
|
end
|
55
69
|
|
70
|
+
def api_status
|
71
|
+
conn = Faraday.new(url: 'https://www.githubstatus.com')
|
72
|
+
response = conn.get('/api/v2/components.json')
|
73
|
+
parsed = JSON.parse(response.body, symbolize_names: true)
|
74
|
+
parsed[:components].find { |c| c[:id] == API_STATUS_ID }
|
75
|
+
end
|
76
|
+
|
56
77
|
def verify_webhook_signature(signature, message)
|
57
78
|
return true unless webhook_secret
|
58
79
|
|
@@ -71,13 +92,21 @@ module Shipit
|
|
71
92
|
end
|
72
93
|
|
73
94
|
def fetch_new_token
|
74
|
-
Rails
|
95
|
+
# Rails can add 5 minutes to the cache entry expiration time when any TTL is provided,
|
96
|
+
# so our TTL setting can be lower, and TTL + expires_in should be lower than the GitHub token expiration.
|
97
|
+
Rails.cache.fetch(
|
98
|
+
'github:integration:access-token',
|
99
|
+
expires_in: GITHUB_TOKEN_RAILS_CACHE_LIFETIME,
|
100
|
+
race_condition_ttl: 4.minutes,
|
101
|
+
) do
|
75
102
|
response = new_client(bearer_token: authentication_payload).create_app_installation_access_token(
|
76
103
|
installation_id,
|
77
104
|
accept: 'application/vnd.github.machine-man-preview+json',
|
78
105
|
)
|
79
106
|
token = Token.from_github(response)
|
80
107
|
raise AuthenticationFailed if token.blank?
|
108
|
+
Rails.logger.info("Created GitHub access token ending #{token.to_s[-5..-1]}, expires at #{token.expires_at}"\
|
109
|
+
" and will be refreshed at #{token&.refresh_at}")
|
81
110
|
token
|
82
111
|
end
|
83
112
|
end
|
@@ -104,7 +133,7 @@ module Shipit
|
|
104
133
|
end
|
105
134
|
|
106
135
|
def url(*path)
|
107
|
-
@url ||= "https://#{domain}"
|
136
|
+
@url ||= "https://#{domain}"
|
108
137
|
path.empty? ? @url : File.join(@url, *path.map(&:to_s))
|
109
138
|
end
|
110
139
|
|
@@ -112,13 +141,23 @@ module Shipit
|
|
112
141
|
url('/api/v3/') if enterprise?
|
113
142
|
end
|
114
143
|
|
144
|
+
def web_endpoint
|
145
|
+
url if enterprise?
|
146
|
+
end
|
147
|
+
|
115
148
|
def enterprise?
|
116
149
|
domain != DOMAIN
|
117
150
|
end
|
118
151
|
|
119
152
|
def new_client(options = {})
|
120
|
-
|
121
|
-
|
153
|
+
if enterprise?
|
154
|
+
options = options.reverse_merge(
|
155
|
+
api_endpoint: api_endpoint,
|
156
|
+
web_endpoint: web_endpoint,
|
157
|
+
)
|
158
|
+
end
|
159
|
+
client = Octokit::Client.new(options)
|
160
|
+
client.middleware = faraday_stack
|
122
161
|
client
|
123
162
|
end
|
124
163
|
|
@@ -126,6 +165,21 @@ module Shipit
|
|
126
165
|
|
127
166
|
attr_reader :webhook_secret, :oauth_id, :oauth_secret
|
128
167
|
|
168
|
+
def faraday_stack
|
169
|
+
@faraday_stack ||= Faraday::RackBuilder.new do |builder|
|
170
|
+
builder.use(
|
171
|
+
Faraday::HttpCache,
|
172
|
+
shared_cache: false,
|
173
|
+
store: Rails.cache,
|
174
|
+
logger: Rails.logger,
|
175
|
+
serializer: NullSerializer,
|
176
|
+
)
|
177
|
+
builder.use(GitHubHTTPCacheMiddleware)
|
178
|
+
builder.use(Octokit::Response::RaiseError)
|
179
|
+
builder.adapter(Faraday.default_adapter)
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
129
183
|
def app_id
|
130
184
|
@app_id ||= @config.fetch(:app_id)
|
131
185
|
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Shipit
|
3
|
+
class GitHubHTTPCacheMiddleware < Faraday::Middleware
|
4
|
+
def call(request_env)
|
5
|
+
@app.call(request_env).on_complete do |response_env|
|
6
|
+
if headers = response_env[:response_headers]
|
7
|
+
|
8
|
+
# We're removing max-age and s-maxage because some endpoints,
|
9
|
+
# especially /<repo>/commits, returns a max-age=0. This means that
|
10
|
+
# if two commits are pushed within 1 minute of each others, we won't
|
11
|
+
# see the second one. So instead we still issue the request, but we
|
12
|
+
# revalidate it.
|
13
|
+
cache_control = parse(headers['cache-control'].to_s)
|
14
|
+
cache_control.delete('max-age')
|
15
|
+
cache_control.delete('s-maxage')
|
16
|
+
cache_control['no-cache'] = true
|
17
|
+
cache_control['must-revalidate'] = true
|
18
|
+
headers['cache-control'] = dump(cache_control)
|
19
|
+
|
20
|
+
# We're removing `Authorization` from the `Vary` header because
|
21
|
+
# Faraday::HttpCache has a very limited garbage collection support
|
22
|
+
# and this cause cache entries to grow indefinitely.
|
23
|
+
# See https://github.com/Shopify/shipit-engine/issues/935 for
|
24
|
+
# more details.
|
25
|
+
vary = parse(headers['vary'].to_s)
|
26
|
+
vary.delete('authorization')
|
27
|
+
headers['vary'] = dump(vary)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def dump(directives)
|
35
|
+
directives.map do |k, v|
|
36
|
+
if v == true
|
37
|
+
k
|
38
|
+
else
|
39
|
+
"#{k}=#{v}"
|
40
|
+
end
|
41
|
+
end.join(', ')
|
42
|
+
end
|
43
|
+
|
44
|
+
def parse(header)
|
45
|
+
directives = {}
|
46
|
+
|
47
|
+
header.delete(' ').split(',').each do |part|
|
48
|
+
next if part.empty?
|
49
|
+
|
50
|
+
name, value = part.split('=', 2)
|
51
|
+
directives[name.downcase] = (value || true) unless name.empty?
|
52
|
+
end
|
53
|
+
|
54
|
+
directives
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -1,8 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module OctokitCheckRuns
|
2
3
|
def check_runs(repo, sha, options = {})
|
3
|
-
paginate
|
4
|
+
paginate("#{Octokit::Repository.path(repo)}/commits/#{sha}/check-runs", options.reverse_merge(
|
4
5
|
accept: 'application/vnd.github.antiope-preview+json',
|
5
|
-
)
|
6
|
+
))
|
6
7
|
end
|
7
8
|
end
|
8
9
|
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module Shipit
|
2
3
|
class OctokitIterator
|
3
4
|
include Enumerable
|
@@ -6,8 +7,8 @@ module Shipit
|
|
6
7
|
if relation
|
7
8
|
@response = relation.get(per_page: 100)
|
8
9
|
else
|
9
|
-
yield Shipit.github.api
|
10
|
-
@response = Shipit.github.api.last_response
|
10
|
+
data = yield Shipit.github.api
|
11
|
+
@response = Shipit.github.api.last_response if data.present?
|
11
12
|
end
|
12
13
|
end
|
13
14
|
|
data/lib/shipit/paginator.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module Shipit
|
2
3
|
class Paginator
|
3
|
-
def initialize(resources, controller, order: {id: :desc}, max_page_size: 100, default_page_size: 30)
|
4
|
+
def initialize(resources, controller, order: { id: :desc }, max_page_size: 100, default_page_size: 30)
|
4
5
|
@order = order
|
5
6
|
@controller = controller
|
6
7
|
@since = controller.params[:since].presence
|
@@ -15,7 +16,7 @@ module Shipit
|
|
15
16
|
end
|
16
17
|
|
17
18
|
def links
|
18
|
-
links = {first: link_to(since: nil, page_size: (page_size if page_size != @default_page_size))}
|
19
|
+
links = { first: link_to(since: nil, page_size: (page_size if page_size != @default_page_size)) }
|
19
20
|
links[:next] = link_to(since: to_a.last.id) unless last_page?
|
20
21
|
links
|
21
22
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Shipit
|
3
|
+
class SameSiteCookieMiddleware
|
4
|
+
COOKIE_SEPARATOR = "\n"
|
5
|
+
|
6
|
+
def initialize(app)
|
7
|
+
@app = app
|
8
|
+
end
|
9
|
+
|
10
|
+
def call(env)
|
11
|
+
status, headers, body = @app.call(env)
|
12
|
+
|
13
|
+
if headers && headers['Set-Cookie'] &&
|
14
|
+
Rack::Request.new(env).ssl?
|
15
|
+
|
16
|
+
set_cookies = headers['Set-Cookie'].split(COOKIE_SEPARATOR).compact
|
17
|
+
set_cookies.map! do |cookie|
|
18
|
+
cookie << '; Secure' if cookie !~ /;\s*secure/i
|
19
|
+
cookie << '; SameSite=None' unless cookie.match?(/;\s*samesite=/i)
|
20
|
+
cookie
|
21
|
+
end
|
22
|
+
|
23
|
+
headers['Set-Cookie'] = set_cookies.join(COOKIE_SEPARATOR)
|
24
|
+
end
|
25
|
+
|
26
|
+
[status, headers, body]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|