shipit-engine 0.32.0 → 0.35.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +13 -2
- data/app/assets/images/magic-solid.svg +1 -0
- data/app/assets/javascripts/shipit/repositories_search.js.coffee +60 -0
- data/app/assets/javascripts/shipit/{search.js.coffee → stack_search.js.coffee} +0 -0
- data/app/assets/stylesheets/_pages/_deploy.scss +2 -3
- data/app/assets/stylesheets/_pages/_repositories.scss +148 -0
- data/app/assets/stylesheets/_pages/_stacks.scss +19 -0
- data/app/assets/stylesheets/shipit.scss +1 -0
- data/app/controllers/shipit/api/ccmenu_controller.rb +1 -1
- data/app/controllers/shipit/api/deploys_controller.rb +2 -0
- data/app/controllers/shipit/api/{pull_requests_controller.rb → merge_requests_controller.rb} +8 -8
- data/app/controllers/shipit/api/rollbacks_controller.rb +2 -1
- data/app/controllers/shipit/api/stacks_controller.rb +15 -1
- data/app/controllers/shipit/deploys_controller.rb +1 -1
- data/app/controllers/shipit/merge_requests_controller.rb +31 -0
- data/app/controllers/shipit/merge_status_controller.rb +15 -15
- data/app/controllers/shipit/repositories_controller.rb +74 -0
- data/app/controllers/shipit/stacks_controller.rb +2 -2
- data/app/controllers/shipit/tasks_controller.rb +2 -2
- data/app/controllers/shipit/webhooks_controller.rb +23 -4
- data/app/helpers/shipit/chunks_helper.rb +2 -2
- data/app/helpers/shipit/github_url_helper.rb +8 -0
- data/app/helpers/shipit/shipit_helper.rb +0 -1
- data/app/helpers/shipit/stacks_helper.rb +4 -0
- data/app/jobs/shipit/create_on_github_job.rb +1 -0
- data/app/jobs/shipit/deliver_hook_job.rb +1 -1
- data/app/jobs/shipit/destroy_repository_job.rb +24 -0
- data/app/jobs/shipit/destroy_stack_job.rb +2 -2
- data/app/jobs/shipit/github_sync_job.rb +13 -9
- data/app/jobs/shipit/perform_task_job.rb +4 -98
- data/app/jobs/shipit/process_merge_requests_job.rb +32 -0
- data/app/jobs/shipit/refresh_merge_request_job.rb +11 -0
- data/app/jobs/shipit/update_github_last_deployed_ref_job.rb +1 -1
- data/app/models/shipit/anonymous_user.rb +10 -2
- data/app/models/shipit/check_run.rb +38 -2
- data/app/models/shipit/command_line_user.rb +4 -0
- data/app/models/shipit/commit.rb +31 -20
- data/app/models/shipit/commit_checks.rb +14 -13
- data/app/models/shipit/commit_deployment.rb +3 -3
- data/app/models/shipit/commit_deployment_status.rb +3 -3
- data/app/models/shipit/deploy.rb +17 -11
- data/app/models/shipit/deploy_spec/file_system.rb +11 -5
- data/app/models/shipit/deploy_spec/lerna_discovery.rb +12 -4
- data/app/models/shipit/deploy_spec.rb +16 -4
- data/app/models/shipit/duration.rb +2 -0
- data/app/models/shipit/hook.rb +28 -2
- data/app/models/shipit/merge_request.rb +304 -0
- data/app/models/shipit/provisioning_handler/base.rb +30 -0
- data/app/models/shipit/provisioning_handler/unregistered_provisioning_handler.rb +35 -0
- data/app/models/shipit/provisioning_handler.rb +32 -0
- data/app/models/shipit/pull_request.rb +26 -265
- data/app/models/shipit/pull_request_assignment.rb +10 -0
- data/app/models/shipit/release_status.rb +1 -1
- data/app/models/shipit/repository.rb +63 -3
- data/app/models/shipit/review_stack.rb +130 -0
- data/app/models/shipit/review_stack_provisioning_queue.rb +39 -0
- data/app/models/shipit/rollback.rb +5 -0
- data/app/models/shipit/stack.rb +78 -30
- data/app/models/shipit/status/group.rb +1 -1
- data/app/models/shipit/task.rb +62 -9
- data/app/models/shipit/task_execution_strategy/base.rb +20 -0
- data/app/models/shipit/task_execution_strategy/default.rb +109 -0
- data/app/models/shipit/team.rb +4 -2
- data/app/models/shipit/user.rb +10 -1
- data/app/models/shipit/webhooks/handlers/pull_request/assigned_handler.rb +74 -0
- data/app/models/shipit/webhooks/handlers/pull_request/closed_handler.rb +68 -0
- data/app/models/shipit/webhooks/handlers/pull_request/edited_handler.rb +74 -0
- data/app/models/shipit/webhooks/handlers/pull_request/label_capturing_handler.rb +127 -0
- data/app/models/shipit/webhooks/handlers/pull_request/labeled_handler.rb +106 -0
- data/app/models/shipit/webhooks/handlers/pull_request/opened_handler.rb +83 -0
- data/app/models/shipit/webhooks/handlers/pull_request/reopened_handler.rb +88 -0
- data/app/models/shipit/webhooks/handlers/pull_request/review_stack_adapter.rb +103 -0
- data/app/models/shipit/webhooks/handlers/pull_request/unlabeled_handler.rb +107 -0
- data/app/models/shipit/webhooks/handlers/push_handler.rb +4 -1
- data/app/models/shipit/webhooks.rb +10 -0
- data/app/serializers/shipit/deploy_serializer.rb +6 -0
- data/app/serializers/shipit/merge_request_serializer.rb +21 -0
- data/app/serializers/shipit/pull_request_serializer.rb +5 -8
- data/app/serializers/shipit/review_stack_serializer.rb +7 -0
- data/app/serializers/shipit/stack_serializer.rb +7 -6
- data/app/serializers/shipit/tail_task_serializer.rb +10 -2
- data/app/serializers/shipit/task_serializer.rb +1 -1
- data/app/validators/subset_validator.rb +1 -1
- data/app/views/layouts/merge_status.html.erb +1 -1
- data/app/views/shipit/merge_requests/_merge_request.html.erb +29 -0
- data/app/views/shipit/{pull_requests → merge_requests}/index.html.erb +2 -2
- data/app/views/shipit/merge_requests/merge_requests/_pull_request.html.erb +29 -0
- data/app/views/shipit/merge_requests/merge_requests/index.html.erb +20 -0
- data/app/views/shipit/merge_status/_merge_queue_button.html.erb +3 -3
- data/app/views/shipit/merge_status/backlogged.html.erb +1 -1
- data/app/views/shipit/merge_status/failure.html.erb +1 -1
- data/app/views/shipit/merge_status/locked.html.erb +1 -1
- data/app/views/shipit/merge_status/success.html.erb +2 -2
- data/app/views/shipit/repositories/_header.html.erb +19 -0
- data/app/views/shipit/repositories/index.html.erb +31 -0
- data/app/views/shipit/repositories/new.html.erb +23 -0
- data/app/views/shipit/repositories/settings.html.erb +53 -0
- data/app/views/shipit/repositories/show.html.erb +30 -0
- data/app/views/shipit/stacks/_banners.html.erb +15 -1
- data/app/views/shipit/stacks/_header.html.erb +5 -2
- data/app/views/shipit/stacks/_stack.html.erb +8 -0
- data/app/views/shipit/stacks/index.html.erb +2 -1
- data/app/views/shipit/stacks/new.html.erb +1 -1
- data/app/views/shipit/stacks/settings.html.erb +5 -5
- data/app/views/shipit/stacks/show.html.erb +1 -1
- data/app/views/shipit/tasks/_task_output.html.erb +1 -1
- data/config/routes.rb +15 -5
- data/config/secrets.development.example.yml +24 -0
- data/config/secrets.development.shopify.yml +20 -9
- data/db/migrate/20200706145406_add_review_stacks.rb +12 -0
- data/db/migrate/20200804144639_rename_pull_request_to_merge_request.rb +7 -0
- data/db/migrate/20200804161512_rename_commits_pull_request_id_to_merge_request_id.rb +5 -0
- data/db/migrate/20200813134712_recreate_shipit_pull_requests.rb +22 -0
- data/db/migrate/20200813194056_create_pull_request_assignments.rb +8 -0
- data/db/migrate/20201001125502_add_provision_pr_stacks_flag_to_repositories.rb +7 -0
- data/db/migrate/20201008145809_add_retry_attempt_to_tasks.rb +5 -0
- data/db/migrate/20201008152744_add_max_retries_to_tasks.rb +5 -0
- data/db/migrate/20210325194053_remove_stacks_branch_default.rb +5 -0
- data/db/migrate/20210504200438_add_github_updated_at_to_check_runs.rb +5 -0
- data/db/migrate/20210823075617_change_check_runs_github_updated_at_default.rb +5 -0
- data/lib/shipit/command.rb +7 -6
- data/lib/shipit/commands.rb +18 -5
- data/lib/shipit/engine.rb +2 -0
- data/lib/shipit/flock.rb +8 -1
- data/lib/shipit/github_app.rb +8 -6
- data/lib/shipit/octokit_iterator.rb +3 -3
- data/lib/shipit/review_stack_commands.rb +8 -0
- data/lib/shipit/simple_message_verifier.rb +2 -2
- data/lib/shipit/stack_commands.rb +36 -7
- data/lib/shipit/task_commands.rb +8 -1
- data/lib/shipit/version.rb +1 -1
- data/lib/shipit.rb +50 -16
- data/lib/snippets/publish-lerna-independent-packages +35 -34
- data/lib/snippets/publish-lerna-independent-packages-legacy +39 -0
- data/lib/tasks/cron.rake +11 -2
- data/test/controllers/api/ccmenu_controller_test.rb +1 -1
- data/test/controllers/api/deploys_controller_test.rb +17 -0
- data/test/controllers/api/{pull_requests_controller_test.rb → merge_requests_controller_test.rb} +12 -12
- data/test/controllers/api/outputs_controller_test.rb +1 -0
- data/test/controllers/api/rollback_controller_test.rb +1 -1
- data/test/controllers/api/stacks_controller_test.rb +42 -8
- data/test/controllers/{pull_requests_controller_test.rb → merge_requests_controller_test.rb} +6 -6
- data/test/controllers/repositories_controller_test.rb +71 -0
- data/test/controllers/stacks_controller_test.rb +9 -1
- data/test/controllers/tasks_controller_test.rb +14 -2
- data/test/controllers/webhooks_controller_test.rb +27 -12
- data/test/dummy/app/assets/config/manifest.js +3 -0
- data/test/dummy/config/application.rb +7 -2
- data/test/dummy/config/database.yml +9 -0
- data/test/dummy/config/environments/development.rb +1 -4
- data/test/dummy/config/environments/test.rb +0 -5
- data/test/dummy/config/secrets_double_github_app.yml +79 -0
- data/test/dummy/db/schema.rb +56 -17
- data/test/dummy/db/seeds.rb +2 -1
- data/test/fixtures/payloads/check_suite_master.json +4 -32
- data/test/fixtures/payloads/invalid_pull_request.json +117 -0
- data/test/fixtures/payloads/provision_disabled_pull_request.json +454 -0
- data/test/fixtures/payloads/pull_request_assigned.json +480 -0
- data/test/fixtures/payloads/pull_request_closed.json +454 -0
- data/test/fixtures/payloads/pull_request_labeled.json +461 -0
- data/test/fixtures/payloads/pull_request_opened.json +454 -0
- data/test/fixtures/payloads/pull_request_reopened.json +454 -0
- data/test/fixtures/payloads/pull_request_unlabeled.json +454 -0
- data/test/fixtures/payloads/pull_request_with_no_repo.json +454 -0
- data/test/fixtures/payloads/push_master.json +1 -1
- data/test/fixtures/payloads/push_not_master.json +1 -1
- data/test/fixtures/shipit/commits.yml +17 -4
- data/test/fixtures/shipit/hooks.yml +1 -0
- data/test/fixtures/shipit/merge_requests.yml +141 -0
- data/test/fixtures/shipit/pull_request_assignments.yml +3 -0
- data/test/fixtures/shipit/pull_requests.yml +10 -131
- data/test/fixtures/shipit/repositories.yml +1 -0
- data/test/fixtures/shipit/stacks.yml +145 -0
- data/test/fixtures/shipit/statuses.yml +9 -0
- data/test/fixtures/shipit/tasks.yml +4 -1
- data/test/fixtures/shipit/users.yml +7 -0
- data/test/helpers/json_helper.rb +5 -1
- data/test/helpers/payloads_helper.rb +4 -0
- data/test/jobs/chunk_rollup_job_test.rb +15 -1
- data/test/jobs/destroy_repository_job_test.rb +27 -0
- data/test/jobs/github_sync_job_test.rb +2 -1
- data/test/jobs/perform_task_job_test.rb +8 -8
- data/test/jobs/{merge_pull_requests_job_test.rb → process_merge_requests_job_test.rb} +18 -18
- data/test/lib/shipit/deploy_commands_test.rb +16 -0
- data/test/lib/shipit/task_commands_test.rb +17 -0
- data/test/models/commit_deployment_status_test.rb +3 -3
- data/test/models/commits_test.rb +24 -13
- data/test/models/deploy_spec_test.rb +64 -24
- data/test/models/deploys_test.rb +188 -14
- data/test/models/hook_test.rb +30 -1
- data/test/models/{pull_request_test.rb → merge_request_test.rb} +49 -34
- data/test/models/pull_request_assignment_test.rb +16 -0
- data/test/models/shipit/check_run_test.rb +124 -5
- data/test/models/shipit/provisioning_handler/base_test.rb +33 -0
- data/test/models/shipit/provisioning_handler/unregistered_provisioning_handler_test.rb +49 -0
- data/test/models/shipit/provisioning_handler_test.rb +64 -0
- data/test/models/shipit/pull_request_test.rb +52 -0
- data/test/models/shipit/repository_test.rb +5 -1
- data/test/models/shipit/review_stack_provision_status_test.rb +77 -0
- data/test/models/shipit/review_stack_provisioning_queue_test.rb +63 -0
- data/test/models/shipit/review_stack_test.rb +91 -0
- data/test/models/{stacks_test.rb → shipit/stacks_test.rb} +52 -8
- data/test/models/shipit/webhooks/handlers/pull_request/assigned_handler_test.rb +45 -0
- data/test/models/shipit/webhooks/handlers/pull_request/closed_handler_test.rb +192 -0
- data/test/models/shipit/webhooks/handlers/pull_request/edited_handler_test.rb +47 -0
- data/test/models/shipit/webhooks/handlers/pull_request/label_capturing_handler_test.rb +209 -0
- data/test/models/shipit/webhooks/handlers/pull_request/labeled_handler_test.rb +332 -0
- data/test/models/shipit/webhooks/handlers/pull_request/opened_handler_test.rb +238 -0
- data/test/models/shipit/webhooks/handlers/pull_request/reopened_handler_test.rb +282 -0
- data/test/models/shipit/webhooks/handlers/pull_request/review_stack_adapter_test.rb +107 -0
- data/test/models/shipit/webhooks/handlers/pull_request/unlabeled_handler_test.rb +324 -0
- data/test/models/shipit/{wehbooks → webhooks}/handlers_test.rb +0 -0
- data/test/models/tasks_test.rb +66 -3
- data/test/serializers/shipit/pull_request_serializer_test.rb +29 -0
- data/test/test_helper.rb +15 -0
- data/test/unit/anonymous_user_serializer_test.rb +1 -1
- data/test/unit/command_test.rb +8 -3
- data/test/unit/commit_serializer_test.rb +1 -1
- data/test/unit/deploy_commands_test.rb +73 -17
- data/test/unit/deploy_serializer_test.rb +1 -1
- data/test/unit/github_app_test.rb +2 -3
- data/test/unit/github_apps_test.rb +416 -0
- data/test/unit/github_url_helper_test.rb +5 -0
- data/test/unit/shipit_deployment_checks_test.rb +77 -0
- data/test/unit/shipit_task_execution_strategy_test.rb +47 -0
- data/test/unit/shipit_test.rb +14 -0
- data/test/unit/user_serializer_test.rb +1 -1
- metadata +306 -188
- data/app/controllers/shipit/pull_requests_controller.rb +0 -31
- data/app/jobs/shipit/merge_pull_requests_job.rb +0 -32
- data/app/jobs/shipit/refresh_pull_request_job.rb +0 -11
- data/app/views/shipit/pull_requests/_pull_request.html.erb +0 -29
- data/test/fixtures/shipit/output_chunks.yml +0 -47
- data/test/models/output_chunk_test.rb +0 -21
|
File without changes
|
data/test/models/tasks_test.rb
CHANGED
|
@@ -34,9 +34,9 @@ module Shipit
|
|
|
34
34
|
|
|
35
35
|
test "#chunk_output truncates output exceeding the storage limit" do
|
|
36
36
|
task = shipit_tasks(:shipit)
|
|
37
|
-
task.
|
|
38
|
-
|
|
39
|
-
task.
|
|
37
|
+
Shipit.redis.del(task.send(:output_key))
|
|
38
|
+
|
|
39
|
+
task.write('a' * (Task::OUTPUT_SIZE_LIMIT * 1.1))
|
|
40
40
|
|
|
41
41
|
output = task.chunk_output
|
|
42
42
|
|
|
@@ -47,5 +47,68 @@ module Shipit
|
|
|
47
47
|
"'#{Task::OUTPUT_TRUNCATED_MESSAGE.chomp}' was not present in the output",
|
|
48
48
|
)
|
|
49
49
|
end
|
|
50
|
+
|
|
51
|
+
test "#retry_if_necessary creates a duplicated task object with pending status and nil created_at and ended_at" do
|
|
52
|
+
task = shipit_tasks(:shipit)
|
|
53
|
+
task_stack = task.stack
|
|
54
|
+
task.retry_if_necessary
|
|
55
|
+
|
|
56
|
+
retried_task = task_stack.deploys.last
|
|
57
|
+
|
|
58
|
+
assert_not_equal task.id, retried_task.id
|
|
59
|
+
assert_nil retried_task.started_at
|
|
60
|
+
assert_nil retried_task.ended_at
|
|
61
|
+
assert_equal 'pending', retried_task.status
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
test "#retry_if_necessary does not create a new task object if max_retries is nil" do
|
|
65
|
+
task = shipit_tasks(:shipit2)
|
|
66
|
+
|
|
67
|
+
assert_no_difference 'Task.count', 'No new task should be created' do
|
|
68
|
+
task.retry_if_necessary
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
test "#retry_if_necessary does not create a new task object if the stack is locked" do
|
|
73
|
+
task = shipit_tasks(:shipit2)
|
|
74
|
+
task.stack.lock("test", task.user)
|
|
75
|
+
|
|
76
|
+
assert_no_difference 'Task.count', 'No new task should be created' do
|
|
77
|
+
task.retry_if_necessary
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
test "#retries_configured? returns true when max_retries is not nil and is greater than zero" do
|
|
82
|
+
task_with_three_retries = shipit_tasks(:shipit)
|
|
83
|
+
assert_predicate task_with_three_retries, :retries_configured?
|
|
84
|
+
|
|
85
|
+
task_with_nil_retries = shipit_tasks(:shipit2)
|
|
86
|
+
refute_predicate task_with_nil_retries, :retries_configured?
|
|
87
|
+
|
|
88
|
+
task_with_zero_retries = shipit_tasks(:shipit_restart)
|
|
89
|
+
refute_predicate task_with_zero_retries, :retries_configured?
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
test ".due_for_rollup includes tasks in successful terminal states" do
|
|
93
|
+
task = shipit_tasks(:shipit)
|
|
94
|
+
task.update(
|
|
95
|
+
rolled_up: false,
|
|
96
|
+
created_at: (60 + 1).minutes.ago.to_s(:db),
|
|
97
|
+
status: "success",
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
assert_includes Shipit::Task.due_for_rollup, task
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
test ".due_for_rollup includes tasks in unsuccessful terminal states" do
|
|
104
|
+
task = shipit_tasks(:shipit)
|
|
105
|
+
task.update(
|
|
106
|
+
rolled_up: false,
|
|
107
|
+
created_at: (60 + 1).minutes.ago.to_s(:db),
|
|
108
|
+
status: "error",
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
assert_includes Shipit::Task.due_for_rollup, task
|
|
112
|
+
end
|
|
50
113
|
end
|
|
51
114
|
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "test_helper"
|
|
4
|
+
|
|
5
|
+
module Shipit
|
|
6
|
+
class PulLRequestSerializerTest < ActiveSupport::TestCase
|
|
7
|
+
test "structure" do
|
|
8
|
+
pull_request = shipit_pull_requests(:review_stack_review)
|
|
9
|
+
|
|
10
|
+
serialized = serializer.new(pull_request).as_json
|
|
11
|
+
|
|
12
|
+
assert_includes serialized.keys, :id
|
|
13
|
+
assert_includes serialized.keys, :number
|
|
14
|
+
assert_includes serialized.keys, :title
|
|
15
|
+
assert_includes serialized.keys, :github_id
|
|
16
|
+
assert_includes serialized.keys, :additions
|
|
17
|
+
assert_includes serialized.keys, :deletions
|
|
18
|
+
assert_includes serialized.keys, :state
|
|
19
|
+
assert_includes serialized.keys, :html_url
|
|
20
|
+
assert_includes serialized.keys, :user
|
|
21
|
+
assert_includes serialized.keys, :assignees
|
|
22
|
+
assert_includes serialized.keys, :head
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def serializer
|
|
26
|
+
Shipit::PullRequestSerializer
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
data/test/test_helper.rb
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
ENV["RAILS_ENV"] ||= "test"
|
|
3
3
|
|
|
4
|
+
if Warning.respond_to?(:[]=)
|
|
5
|
+
Warning[:deprecated] = true
|
|
6
|
+
end
|
|
7
|
+
|
|
4
8
|
require 'simplecov'
|
|
5
9
|
SimpleCov.start('rails') do
|
|
6
10
|
enable_coverage :branch
|
|
@@ -32,6 +36,17 @@ begin
|
|
|
32
36
|
rescue LoadError
|
|
33
37
|
end
|
|
34
38
|
|
|
39
|
+
# FIXME: We need to get rid of active_model_serializers
|
|
40
|
+
# This is a monkey patch for Ruby 2.7+ compatibility
|
|
41
|
+
module ActionController
|
|
42
|
+
module SerializationAssertions
|
|
43
|
+
def process(*, **)
|
|
44
|
+
@serializers = Hash.new(0)
|
|
45
|
+
super
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
35
50
|
module ActiveSupport
|
|
36
51
|
class TestCase
|
|
37
52
|
include PayloadsHelper
|
|
@@ -8,7 +8,7 @@ module Shipit
|
|
|
8
8
|
serializer = ActiveModel::Serializer.serializer_for(user)
|
|
9
9
|
assert_equal AnonymousUserSerializer, serializer
|
|
10
10
|
serialized = serializer.new(user).to_json
|
|
11
|
-
|
|
11
|
+
assert_json_document(serialized, "anonymous", true)
|
|
12
12
|
end
|
|
13
13
|
end
|
|
14
14
|
end
|
data/test/unit/command_test.rb
CHANGED
|
@@ -34,6 +34,11 @@ module Shipit
|
|
|
34
34
|
ENV['SHIPIT_TEST'] = previous
|
|
35
35
|
end
|
|
36
36
|
|
|
37
|
+
test "#env cast to strings except for `nil`" do
|
|
38
|
+
command = Command.new('echo foo', env: { 'SOME_PATH' => Pathname.new('/foo'), 'HOST' => nil }, chdir: '.')
|
|
39
|
+
assert_equal({ 'SOME_PATH' => '/foo', 'HOST' => nil }, command.env)
|
|
40
|
+
end
|
|
41
|
+
|
|
37
42
|
test "#timeout is 5 minutes by default" do
|
|
38
43
|
command = Command.new('cap $LANG deploy', env: { 'ENVIRONMENT' => 'production' }, chdir: '.')
|
|
39
44
|
assert_equal 5.minutes.to_i, command.timeout
|
|
@@ -59,14 +64,14 @@ module Shipit
|
|
|
59
64
|
end
|
|
60
65
|
|
|
61
66
|
test "command not found" do
|
|
62
|
-
error = assert_raises
|
|
67
|
+
error = assert_raises(Command::NotFound) do
|
|
63
68
|
Command.new('does-not-exist foo bar', env: {}, chdir: '.').run
|
|
64
69
|
end
|
|
65
70
|
assert_equal 'does-not-exist: command not found', error.message
|
|
66
71
|
end
|
|
67
72
|
|
|
68
73
|
test "permission denied" do
|
|
69
|
-
error = assert_raises
|
|
74
|
+
error = assert_raises(Command::Denied) do
|
|
70
75
|
Command.new('/etc/passwd foo bar', env: {}, chdir: '.').run
|
|
71
76
|
end
|
|
72
77
|
assert_equal '/etc/passwd: Permission denied', error.message
|
|
@@ -121,7 +126,7 @@ module Shipit
|
|
|
121
126
|
signalled = true
|
|
122
127
|
break
|
|
123
128
|
end
|
|
124
|
-
sleep
|
|
129
|
+
sleep(0.1)
|
|
125
130
|
end
|
|
126
131
|
signalled
|
|
127
132
|
end
|
|
@@ -10,7 +10,7 @@ module Shipit
|
|
|
10
10
|
assert_equal CommitSerializer, serializer
|
|
11
11
|
serialized = serializer.new(commit).to_json
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
assert_json_document(serialized, "author.name", commit.author.name)
|
|
14
14
|
end
|
|
15
15
|
end
|
|
16
16
|
end
|
|
@@ -4,8 +4,9 @@ require 'test_helper'
|
|
|
4
4
|
module Shipit
|
|
5
5
|
class DeployCommandsTest < ActiveSupport::TestCase
|
|
6
6
|
def setup
|
|
7
|
-
@stack = shipit_stacks(:shipit)
|
|
8
7
|
@deploy = shipit_deploys(:shipit_pending)
|
|
8
|
+
@stack = @deploy.stack
|
|
9
|
+
@stack.stubs(:clear_git_cache!)
|
|
9
10
|
@commands = DeployCommands.new(@deploy)
|
|
10
11
|
@deploy_spec = stub(
|
|
11
12
|
dependencies_steps!: ['bundle install --some-args'],
|
|
@@ -21,42 +22,97 @@ module Shipit
|
|
|
21
22
|
end
|
|
22
23
|
|
|
23
24
|
test "#fetch calls git fetch if repository cache already exist" do
|
|
24
|
-
|
|
25
|
+
@stack.git_path.stubs(:exist?).returns(true)
|
|
26
|
+
@stack.git_path.stubs(:empty?).returns(false)
|
|
27
|
+
|
|
25
28
|
command = @commands.fetch
|
|
29
|
+
|
|
26
30
|
assert_equal %w(git fetch origin --tags master), command.args
|
|
27
31
|
end
|
|
28
32
|
|
|
29
33
|
test "#fetch calls git fetch in git_path directory if repository cache already exist" do
|
|
30
|
-
|
|
34
|
+
@stack.git_path.stubs(:exist?).returns(true)
|
|
35
|
+
@stack.git_path.stubs(:empty?).returns(false)
|
|
36
|
+
|
|
31
37
|
command = @commands.fetch
|
|
32
|
-
|
|
38
|
+
|
|
39
|
+
assert_equal @stack.git_path.to_s, command.chdir
|
|
33
40
|
end
|
|
34
41
|
|
|
35
42
|
test "#fetch calls git clone if repository cache do not exist" do
|
|
36
|
-
|
|
43
|
+
@stack.git_path.stubs(:exist?).returns(false)
|
|
44
|
+
|
|
45
|
+
command = @commands.fetch
|
|
46
|
+
|
|
47
|
+
expected = %W(git clone --quiet --single-branch --recursive --branch master #{@stack.repo_git_url} #{@stack.git_path})
|
|
48
|
+
assert_equal expected, command.args.map(&:to_s)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
test "#fetch calls git clone if repository cache is empty" do
|
|
52
|
+
@stack.git_path.stubs(:exist?).returns(true)
|
|
53
|
+
@stack.git_path.stubs(:empty?).returns(true)
|
|
54
|
+
|
|
37
55
|
command = @commands.fetch
|
|
38
|
-
|
|
56
|
+
|
|
57
|
+
expected = %W(git clone --quiet --single-branch --recursive --branch master #{@stack.repo_git_url} #{@stack.git_path})
|
|
58
|
+
assert_equal expected, command.args
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
test "#fetch calls git clone if repository cache corrupt" do
|
|
62
|
+
@stack.git_path.stubs(:exist?).returns(true)
|
|
63
|
+
@stack.git_path.stubs(:empty?).returns(false)
|
|
64
|
+
StackCommands.any_instance.expects(:git_cmd_succeeds?)
|
|
65
|
+
.with(@stack.git_path)
|
|
66
|
+
.returns(false)
|
|
67
|
+
|
|
68
|
+
command = @commands.fetch
|
|
69
|
+
|
|
70
|
+
expected = %W(git clone --quiet --single-branch --recursive --branch master #{@stack.repo_git_url} #{@stack.git_path})
|
|
71
|
+
assert_equal expected, command.args
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
test "#fetch clears a corrupted git stash before cloning" do
|
|
75
|
+
@stack.expects(:clear_git_cache!)
|
|
76
|
+
@stack.git_path.stubs(:exist?).returns(true)
|
|
77
|
+
@stack.git_path.stubs(:empty?).returns(false)
|
|
78
|
+
StackCommands.any_instance.expects(:git_cmd_succeeds?)
|
|
79
|
+
.with(@stack.git_path)
|
|
80
|
+
.returns(false)
|
|
81
|
+
|
|
82
|
+
command = @commands.fetch
|
|
83
|
+
|
|
84
|
+
expected = %W(git clone --quiet --single-branch --recursive --branch master #{@stack.repo_git_url} #{@stack.git_path})
|
|
39
85
|
assert_equal expected, command.args
|
|
40
86
|
end
|
|
41
87
|
|
|
42
88
|
test "#fetch does not use --single-branch if git is outdated" do
|
|
43
|
-
|
|
89
|
+
@stack.git_path.stubs(:exist?).returns(false)
|
|
44
90
|
StackCommands.stubs(git_version: Gem::Version.new('1.7.2.30'))
|
|
91
|
+
|
|
45
92
|
command = @commands.fetch
|
|
46
|
-
|
|
47
|
-
|
|
93
|
+
|
|
94
|
+
expected = %W(git clone --quiet --recursive --branch master #{@stack.repo_git_url} #{@stack.git_path})
|
|
95
|
+
assert_equal expected, command.args.map(&:to_s)
|
|
48
96
|
end
|
|
49
97
|
|
|
50
98
|
test "#fetch calls git fetch in base_path directory if repository cache do not exist" do
|
|
51
|
-
|
|
99
|
+
@stack.git_path.stubs(:exist?).returns(false)
|
|
100
|
+
|
|
52
101
|
command = @commands.fetch
|
|
53
|
-
|
|
102
|
+
|
|
103
|
+
assert_equal @stack.deploys_path.to_s, command.chdir
|
|
54
104
|
end
|
|
55
105
|
|
|
56
106
|
test "#fetch merges Shipit.env in ENVIRONMENT" do
|
|
57
107
|
Shipit.stubs(:env).returns("SPECIFIC_CONFIG" => 5)
|
|
58
108
|
command = @commands.fetch
|
|
59
|
-
assert_equal 5, command.env["SPECIFIC_CONFIG"]
|
|
109
|
+
assert_equal '5', command.env["SPECIFIC_CONFIG"]
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
test "#env uses the correct Github token for a stack" do
|
|
113
|
+
Shipit.github(organization: 'shopify').stubs(:token).returns('aS3cr3Tt0kEn')
|
|
114
|
+
command = @commands.fetch
|
|
115
|
+
assert_equal 'aS3cr3Tt0kEn', command.env["GITHUB_TOKEN"]
|
|
60
116
|
end
|
|
61
117
|
|
|
62
118
|
test "#clone clones the repository cache into the working directory" do
|
|
@@ -65,20 +121,20 @@ module Shipit
|
|
|
65
121
|
clone_args = [
|
|
66
122
|
'git', 'clone', '--quiet',
|
|
67
123
|
'--local', '--origin', 'cache',
|
|
68
|
-
@stack.git_path, @deploy.working_directory
|
|
124
|
+
@stack.git_path.to_s, @deploy.working_directory,
|
|
69
125
|
]
|
|
70
126
|
assert_equal clone_args, commands.first.args
|
|
71
|
-
assert_equal ['git', 'remote', 'add', 'origin', @stack.repo_git_url], commands.second.args
|
|
127
|
+
assert_equal ['git', 'remote', 'add', 'origin', @stack.repo_git_url.to_s], commands.second.args
|
|
72
128
|
end
|
|
73
129
|
|
|
74
130
|
test "#clone clones the repository cache from the deploys_path" do
|
|
75
131
|
commands = @commands.clone
|
|
76
|
-
assert_equal @stack.deploys_path, commands.first.chdir
|
|
132
|
+
assert_equal @stack.deploys_path.to_s, commands.first.chdir
|
|
77
133
|
end
|
|
78
134
|
|
|
79
135
|
test "#checkout checks out the deployed commit" do
|
|
80
136
|
command = @commands.checkout(@deploy.until_commit)
|
|
81
|
-
assert_equal ['git', 'checkout', @deploy.until_commit.sha], command.args
|
|
137
|
+
assert_equal ['git', '-c', 'advice.detachedHead=false', 'checkout', @deploy.until_commit.sha], command.args
|
|
82
138
|
end
|
|
83
139
|
|
|
84
140
|
test "#checkout checks out the deployed commit from the working directory" do
|
|
@@ -182,7 +238,7 @@ module Shipit
|
|
|
182
238
|
test "#install_dependencies merges Shipit.env in ENVIRONMENT" do
|
|
183
239
|
Shipit.stubs(:env).returns("SPECIFIC_CONFIG" => 5)
|
|
184
240
|
command = @commands.install_dependencies.first
|
|
185
|
-
assert_equal 5, command.env["SPECIFIC_CONFIG"]
|
|
241
|
+
assert_equal '5', command.env["SPECIFIC_CONFIG"]
|
|
186
242
|
end
|
|
187
243
|
|
|
188
244
|
test "#install_dependencies merges machine_env in ENVIRONMENT" do
|
|
@@ -11,7 +11,7 @@ module Shipit
|
|
|
11
11
|
assert_equal DeploySerializer, serializer
|
|
12
12
|
serialized = serializer.new(deploy).to_json
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
assert_json_document(serialized, "commits.0.author.name", first_commit_author.name)
|
|
15
15
|
end
|
|
16
16
|
end
|
|
17
17
|
end
|
|
@@ -18,7 +18,7 @@ module Shipit
|
|
|
18
18
|
|
|
19
19
|
test "#initialize doesn't raise if given an empty config" do
|
|
20
20
|
assert_nothing_raised do
|
|
21
|
-
GitHubApp.new({})
|
|
21
|
+
GitHubApp.new(nil, {})
|
|
22
22
|
end
|
|
23
23
|
end
|
|
24
24
|
|
|
@@ -183,7 +183,6 @@ module Shipit
|
|
|
183
183
|
.any_instance
|
|
184
184
|
.expects(:create_app_installation_access_token).with(config[:installation_id], anything)
|
|
185
185
|
.returns(second_token)
|
|
186
|
-
|
|
187
186
|
first_token = valid_app.token
|
|
188
187
|
|
|
189
188
|
first_cached_token = Rails.cache.fetch(@token_cache_key)
|
|
@@ -199,7 +198,7 @@ module Shipit
|
|
|
199
198
|
private
|
|
200
199
|
|
|
201
200
|
def app(extra_config = {})
|
|
202
|
-
GitHubApp.new(default_config.deep_merge(extra_config))
|
|
201
|
+
GitHubApp.new(nil, default_config.deep_merge(extra_config))
|
|
203
202
|
end
|
|
204
203
|
|
|
205
204
|
def default_config
|
|
@@ -0,0 +1,416 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require 'test_helper'
|
|
3
|
+
|
|
4
|
+
module Shipit
|
|
5
|
+
class GitHubAppsTestOrgOne < ActiveSupport::TestCase
|
|
6
|
+
setup do
|
|
7
|
+
@organization = "OrgOne"
|
|
8
|
+
@github = app(@organization)
|
|
9
|
+
@enterprise = app(@organization, domain: 'github.example.com')
|
|
10
|
+
@rails_env = Rails.env
|
|
11
|
+
@token_cache_key = "github:integration:#{@organization.downcase}:access-token"
|
|
12
|
+
Rails.cache.delete(@token_cache_key)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
teardown do
|
|
16
|
+
Rails.env = @rails_env
|
|
17
|
+
Rails.cache.delete(@token_cache_key)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
test "#domain defaults to github.com" do
|
|
21
|
+
assert_equal 'github.com', @github.domain
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
test "#url returns the HTTPS url to the github installation" do
|
|
25
|
+
assert_equal 'https://github.example.com', @enterprise.url
|
|
26
|
+
assert_equal 'https://github.example.com/foo/bar', @enterprise.url('/foo/bar')
|
|
27
|
+
assert_equal 'https://github.example.com/foo/bar/baz', @enterprise.url('foo/bar', 'baz')
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
test "#new_client retruns an Octokit::Client configured to use the github installation" do
|
|
31
|
+
assert_equal 'https://github.example.com/', @enterprise.new_client.web_endpoint
|
|
32
|
+
assert_equal 'https://github.example.com/api/v3/', @enterprise.new_client.api_endpoint
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
test "#oauth_config.last[:client_options] is nil if domain is not overriden" do
|
|
36
|
+
assert_nil @github.oauth_config.last[:client_options][:site]
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
test "#oauth_config.last[:client_options] returns Enterprise endpoint if domain is overriden" do
|
|
40
|
+
assert_equal 'https://github.example.com/api/v3/', @enterprise.oauth_config.last[:client_options][:site]
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
test "#initialize doesn't raise if given an empty config" do
|
|
44
|
+
assert_nothing_raised do
|
|
45
|
+
GitHubApp.new(@organization, {})
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
test "#api_status" do
|
|
50
|
+
stub_request(:get, "https://www.githubstatus.com/api/v2/components.json").to_return(
|
|
51
|
+
status: 200,
|
|
52
|
+
body: %(
|
|
53
|
+
{
|
|
54
|
+
"page":{},
|
|
55
|
+
"components":[
|
|
56
|
+
{
|
|
57
|
+
"id":"brv1bkgrwx7q",
|
|
58
|
+
"name":"API Requests",
|
|
59
|
+
"status":"operational",
|
|
60
|
+
"created_at":"2017-01-31T20:01:46.621Z",
|
|
61
|
+
"updated_at":"2019-07-23T18:41:18.197Z",
|
|
62
|
+
"position":2,
|
|
63
|
+
"description":"Requests for GitHub APIs",
|
|
64
|
+
"showcase":false,
|
|
65
|
+
"group_id":null,
|
|
66
|
+
"page_id":"kctbh9vrtdwd",
|
|
67
|
+
"group":false,
|
|
68
|
+
"only_show_if_degraded":false
|
|
69
|
+
}
|
|
70
|
+
]
|
|
71
|
+
}
|
|
72
|
+
),
|
|
73
|
+
)
|
|
74
|
+
assert_equal "operational", app(@organization).api_status[:status]
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
test "#github token is refreshed after expiration" do
|
|
78
|
+
Rails.env = 'not_test'
|
|
79
|
+
config = {
|
|
80
|
+
app_id: "test_id",
|
|
81
|
+
installation_id: "test_installation_id",
|
|
82
|
+
private_key: "test_private_key",
|
|
83
|
+
}
|
|
84
|
+
initial_token = OpenStruct.new(
|
|
85
|
+
token: "some_initial_github_token",
|
|
86
|
+
expires_at: Time.now.utc + 60.minutes,
|
|
87
|
+
)
|
|
88
|
+
second_token = OpenStruct.new(
|
|
89
|
+
token: "some_new_github_token",
|
|
90
|
+
expires_at: initial_token.expires_at + 60.minutes,
|
|
91
|
+
)
|
|
92
|
+
auth_payload = "test_auth_payload"
|
|
93
|
+
|
|
94
|
+
GitHubApp.any_instance.expects(:authentication_payload).twice.returns(auth_payload)
|
|
95
|
+
valid_app = app(@organization, config)
|
|
96
|
+
|
|
97
|
+
freeze_time do
|
|
98
|
+
Octokit::Client
|
|
99
|
+
.any_instance
|
|
100
|
+
.expects(:create_app_installation_access_token).twice.with(config[:installation_id], anything)
|
|
101
|
+
.returns(initial_token, second_token)
|
|
102
|
+
|
|
103
|
+
initial_token = valid_app.token
|
|
104
|
+
initial_cached_token = Rails.cache.fetch(@token_cache_key)
|
|
105
|
+
assert_equal initial_token, initial_cached_token.to_s
|
|
106
|
+
|
|
107
|
+
travel 5.minutes
|
|
108
|
+
assert_equal initial_token, valid_app.token
|
|
109
|
+
|
|
110
|
+
travel_to initial_cached_token.expires_at + 5.minutes
|
|
111
|
+
assert_equal second_token.token, valid_app.token
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
test "#github token is refreshed in refresh window before expiry" do
|
|
116
|
+
Rails.env = 'not_test'
|
|
117
|
+
config = {
|
|
118
|
+
app_id: "test_id",
|
|
119
|
+
installation_id: "test_installation_id",
|
|
120
|
+
private_key: "test_private_key",
|
|
121
|
+
}
|
|
122
|
+
initial_token = OpenStruct.new(
|
|
123
|
+
token: "some_initial_github_token",
|
|
124
|
+
expires_at: Time.now.utc + 60.minutes,
|
|
125
|
+
)
|
|
126
|
+
second_token = OpenStruct.new(
|
|
127
|
+
token: "some_new_github_token",
|
|
128
|
+
expires_at: initial_token.expires_at + 60.minutes,
|
|
129
|
+
)
|
|
130
|
+
auth_payload = "test_auth_payload"
|
|
131
|
+
|
|
132
|
+
GitHubApp.any_instance.expects(:authentication_payload).twice.returns(auth_payload)
|
|
133
|
+
valid_app = app(@organization, config)
|
|
134
|
+
|
|
135
|
+
freeze_time do
|
|
136
|
+
Octokit::Client
|
|
137
|
+
.any_instance
|
|
138
|
+
.expects(:create_app_installation_access_token).twice.with(config[:installation_id], anything)
|
|
139
|
+
.returns(initial_token, second_token)
|
|
140
|
+
|
|
141
|
+
initial_token = valid_app.token
|
|
142
|
+
initial_cached_token = Rails.cache.fetch(@token_cache_key)
|
|
143
|
+
assert_equal initial_token, initial_cached_token.to_s
|
|
144
|
+
|
|
145
|
+
# Travel forward, but before the token is refreshed, so the cached value should be the same.
|
|
146
|
+
travel 40.minutes
|
|
147
|
+
assert_equal initial_token, valid_app.token
|
|
148
|
+
|
|
149
|
+
# Travel to when the token should refresh, but is not expired, which should result in our cache.fetch update block.
|
|
150
|
+
travel 15.minutes
|
|
151
|
+
updated_token = valid_app.token
|
|
152
|
+
assert_not_equal initial_token, updated_token
|
|
153
|
+
|
|
154
|
+
cached_token = Rails.cache.fetch(@token_cache_key)
|
|
155
|
+
assert_operator cached_token.expires_at, :>, initial_cached_token.expires_at
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
test "#github token is missing refresh_at field" do
|
|
160
|
+
# $debugging = true
|
|
161
|
+
Rails.env = 'not_test'
|
|
162
|
+
config = {
|
|
163
|
+
app_id: "test_id",
|
|
164
|
+
installation_id: "test_installation_id",
|
|
165
|
+
private_key: "test_private_key",
|
|
166
|
+
}
|
|
167
|
+
initial_cached_token = Shipit::GitHubApp::Token.new("some_initial_github_token", Time.now.utc - 1.minute)
|
|
168
|
+
initial_cached_token.instance_variable_set(:@refresh_at, nil)
|
|
169
|
+
|
|
170
|
+
second_token = OpenStruct.new(
|
|
171
|
+
token: "some_new_github_token",
|
|
172
|
+
expires_at: initial_cached_token.expires_at + 60.minutes,
|
|
173
|
+
)
|
|
174
|
+
auth_payload = "test_auth_payload"
|
|
175
|
+
|
|
176
|
+
GitHubApp.any_instance.expects(:authentication_payload).returns(auth_payload)
|
|
177
|
+
valid_app = app(@organization, config)
|
|
178
|
+
|
|
179
|
+
freeze_time do
|
|
180
|
+
valid_app.instance_variable_set(:@token, initial_cached_token)
|
|
181
|
+
Rails.cache.write(@token_cache_key, initial_cached_token, expires_in: 1.minute)
|
|
182
|
+
|
|
183
|
+
Octokit::Client
|
|
184
|
+
.any_instance
|
|
185
|
+
.expects(:create_app_installation_access_token).with(config[:installation_id], anything)
|
|
186
|
+
.returns(second_token)
|
|
187
|
+
|
|
188
|
+
first_token = valid_app.token
|
|
189
|
+
|
|
190
|
+
first_cached_token = Rails.cache.fetch(@token_cache_key)
|
|
191
|
+
assert_equal first_token, first_cached_token.to_s
|
|
192
|
+
|
|
193
|
+
travel_to first_cached_token.expires_at + 5.minutes
|
|
194
|
+
new_token = valid_app.token
|
|
195
|
+
|
|
196
|
+
assert_equal second_token.token, new_token
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
private
|
|
201
|
+
|
|
202
|
+
def app(organization, extra_config = {})
|
|
203
|
+
GitHubApp.new(organization, double_github_app_config.deep_merge(extra_config))
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
def double_github_app_config
|
|
207
|
+
YAML.load_file('test/dummy/config/secrets_double_github_app.yml')
|
|
208
|
+
end
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
class GitHubAppsTestOrgTwo < ActiveSupport::TestCase
|
|
212
|
+
setup do
|
|
213
|
+
@organization = "OrgTwo"
|
|
214
|
+
@github = app(@organization)
|
|
215
|
+
@enterprise = app(@organization, domain: 'github.example.com')
|
|
216
|
+
@rails_env = Rails.env
|
|
217
|
+
@token_cache_key = "github:integration:#{@organization.downcase}:access-token"
|
|
218
|
+
Rails.cache.delete(@token_cache_key)
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
teardown do
|
|
222
|
+
Rails.env = @rails_env
|
|
223
|
+
Rails.cache.delete(@token_cache_key)
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
test "#domain defaults to github.com" do
|
|
227
|
+
assert_equal 'github.com', @github.domain
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
test "#url returns the HTTPS url to the github installation" do
|
|
231
|
+
assert_equal 'https://github.example.com', @enterprise.url
|
|
232
|
+
assert_equal 'https://github.example.com/foo/bar', @enterprise.url('/foo/bar')
|
|
233
|
+
assert_equal 'https://github.example.com/foo/bar/baz', @enterprise.url('foo/bar', 'baz')
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
test "#new_client retruns an Octokit::Client configured to use the github installation" do
|
|
237
|
+
assert_equal 'https://github.example.com/', @enterprise.new_client.web_endpoint
|
|
238
|
+
assert_equal 'https://github.example.com/api/v3/', @enterprise.new_client.api_endpoint
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
test "#oauth_config.last[:client_options] is nil if domain is not overriden" do
|
|
242
|
+
assert_nil @github.oauth_config.last[:client_options][:site]
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
test "#oauth_config.last[:client_options] returns Enterprise endpoint if domain is overriden" do
|
|
246
|
+
assert_equal 'https://github.example.com/api/v3/', @enterprise.oauth_config.last[:client_options][:site]
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
test "#initialize doesn't raise if given an empty config" do
|
|
250
|
+
assert_nothing_raised do
|
|
251
|
+
GitHubApp.new(@organization, {})
|
|
252
|
+
end
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
test "#api_status" do
|
|
256
|
+
stub_request(:get, "https://www.githubstatus.com/api/v2/components.json").to_return(
|
|
257
|
+
status: 200,
|
|
258
|
+
body: %(
|
|
259
|
+
{
|
|
260
|
+
"page":{},
|
|
261
|
+
"components":[
|
|
262
|
+
{
|
|
263
|
+
"id":"brv1bkgrwx7q",
|
|
264
|
+
"name":"API Requests",
|
|
265
|
+
"status":"operational",
|
|
266
|
+
"created_at":"2017-01-31T20:01:46.621Z",
|
|
267
|
+
"updated_at":"2019-07-23T18:41:18.197Z",
|
|
268
|
+
"position":2,
|
|
269
|
+
"description":"Requests for GitHub APIs",
|
|
270
|
+
"showcase":false,
|
|
271
|
+
"group_id":null,
|
|
272
|
+
"page_id":"kctbh9vrtdwd",
|
|
273
|
+
"group":false,
|
|
274
|
+
"only_show_if_degraded":false
|
|
275
|
+
}
|
|
276
|
+
]
|
|
277
|
+
}
|
|
278
|
+
),
|
|
279
|
+
)
|
|
280
|
+
assert_equal "operational", app(@organization).api_status[:status]
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
test "#github token is refreshed after expiration" do
|
|
284
|
+
Rails.env = 'not_test'
|
|
285
|
+
config = {
|
|
286
|
+
app_id: "test_id",
|
|
287
|
+
installation_id: "test_installation_id",
|
|
288
|
+
private_key: "test_private_key",
|
|
289
|
+
}
|
|
290
|
+
initial_token = OpenStruct.new(
|
|
291
|
+
token: "some_initial_github_token",
|
|
292
|
+
expires_at: Time.now.utc + 60.minutes,
|
|
293
|
+
)
|
|
294
|
+
second_token = OpenStruct.new(
|
|
295
|
+
token: "some_new_github_token",
|
|
296
|
+
expires_at: initial_token.expires_at + 60.minutes,
|
|
297
|
+
)
|
|
298
|
+
auth_payload = "test_auth_payload"
|
|
299
|
+
|
|
300
|
+
GitHubApp.any_instance.expects(:authentication_payload).twice.returns(auth_payload)
|
|
301
|
+
valid_app = app(@organization, config)
|
|
302
|
+
|
|
303
|
+
freeze_time do
|
|
304
|
+
Octokit::Client
|
|
305
|
+
.any_instance
|
|
306
|
+
.expects(:create_app_installation_access_token).twice.with(config[:installation_id], anything)
|
|
307
|
+
.returns(initial_token, second_token)
|
|
308
|
+
|
|
309
|
+
initial_token = valid_app.token
|
|
310
|
+
initial_cached_token = Rails.cache.fetch(@token_cache_key)
|
|
311
|
+
assert_equal initial_token, initial_cached_token.to_s
|
|
312
|
+
|
|
313
|
+
travel 5.minutes
|
|
314
|
+
assert_equal initial_token, valid_app.token
|
|
315
|
+
|
|
316
|
+
travel_to initial_cached_token.expires_at + 5.minutes
|
|
317
|
+
assert_equal second_token.token, valid_app.token
|
|
318
|
+
end
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
test "#github token is refreshed in refresh window before expiry" do
|
|
322
|
+
Rails.env = 'not_test'
|
|
323
|
+
config = {
|
|
324
|
+
app_id: "test_id",
|
|
325
|
+
installation_id: "test_installation_id",
|
|
326
|
+
private_key: "test_private_key",
|
|
327
|
+
}
|
|
328
|
+
initial_token = OpenStruct.new(
|
|
329
|
+
token: "some_initial_github_token",
|
|
330
|
+
expires_at: Time.now.utc + 60.minutes,
|
|
331
|
+
)
|
|
332
|
+
second_token = OpenStruct.new(
|
|
333
|
+
token: "some_new_github_token",
|
|
334
|
+
expires_at: initial_token.expires_at + 60.minutes,
|
|
335
|
+
)
|
|
336
|
+
auth_payload = "test_auth_payload"
|
|
337
|
+
|
|
338
|
+
GitHubApp.any_instance.expects(:authentication_payload).twice.returns(auth_payload)
|
|
339
|
+
valid_app = app(@organization, config)
|
|
340
|
+
|
|
341
|
+
freeze_time do
|
|
342
|
+
Octokit::Client
|
|
343
|
+
.any_instance
|
|
344
|
+
.expects(:create_app_installation_access_token).twice.with(config[:installation_id], anything)
|
|
345
|
+
.returns(initial_token, second_token)
|
|
346
|
+
|
|
347
|
+
initial_token = valid_app.token
|
|
348
|
+
initial_cached_token = Rails.cache.fetch(@token_cache_key)
|
|
349
|
+
assert_equal initial_token, initial_cached_token.to_s
|
|
350
|
+
|
|
351
|
+
# Travel forward, but before the token is refreshed, so the cached value should be the same.
|
|
352
|
+
travel 40.minutes
|
|
353
|
+
assert_equal initial_token, valid_app.token
|
|
354
|
+
|
|
355
|
+
# Travel to when the token should refresh, but is not expired, which should result in our cache.fetch update block.
|
|
356
|
+
travel 15.minutes
|
|
357
|
+
updated_token = valid_app.token
|
|
358
|
+
assert_not_equal initial_token, updated_token
|
|
359
|
+
|
|
360
|
+
cached_token = Rails.cache.fetch(@token_cache_key)
|
|
361
|
+
assert_operator cached_token.expires_at, :>, initial_cached_token.expires_at
|
|
362
|
+
end
|
|
363
|
+
end
|
|
364
|
+
|
|
365
|
+
test "#github token is missing refresh_at field" do
|
|
366
|
+
# $debugging = true
|
|
367
|
+
Rails.env = 'not_test'
|
|
368
|
+
config = {
|
|
369
|
+
app_id: "test_id",
|
|
370
|
+
installation_id: "test_installation_id",
|
|
371
|
+
private_key: "test_private_key",
|
|
372
|
+
}
|
|
373
|
+
initial_cached_token = Shipit::GitHubApp::Token.new("some_initial_github_token", Time.now.utc - 1.minute)
|
|
374
|
+
initial_cached_token.instance_variable_set(:@refresh_at, nil)
|
|
375
|
+
|
|
376
|
+
second_token = OpenStruct.new(
|
|
377
|
+
token: "some_new_github_token",
|
|
378
|
+
expires_at: initial_cached_token.expires_at + 60.minutes,
|
|
379
|
+
)
|
|
380
|
+
auth_payload = "test_auth_payload"
|
|
381
|
+
|
|
382
|
+
GitHubApp.any_instance.expects(:authentication_payload).returns(auth_payload)
|
|
383
|
+
valid_app = app(@organization, config)
|
|
384
|
+
|
|
385
|
+
freeze_time do
|
|
386
|
+
valid_app.instance_variable_set(:@token, initial_cached_token)
|
|
387
|
+
Rails.cache.write(@token_cache_key, initial_cached_token, expires_in: 1.minute)
|
|
388
|
+
|
|
389
|
+
Octokit::Client
|
|
390
|
+
.any_instance
|
|
391
|
+
.expects(:create_app_installation_access_token).with(config[:installation_id], anything)
|
|
392
|
+
.returns(second_token)
|
|
393
|
+
|
|
394
|
+
first_token = valid_app.token
|
|
395
|
+
|
|
396
|
+
first_cached_token = Rails.cache.fetch(@token_cache_key)
|
|
397
|
+
assert_equal first_token, first_cached_token.to_s
|
|
398
|
+
|
|
399
|
+
travel_to first_cached_token.expires_at + 5.minutes
|
|
400
|
+
new_token = valid_app.token
|
|
401
|
+
|
|
402
|
+
assert_equal second_token.token, new_token
|
|
403
|
+
end
|
|
404
|
+
end
|
|
405
|
+
|
|
406
|
+
private
|
|
407
|
+
|
|
408
|
+
def app(organization, extra_config = {})
|
|
409
|
+
GitHubApp.new(organization, double_github_app_config.deep_merge(extra_config))
|
|
410
|
+
end
|
|
411
|
+
|
|
412
|
+
def double_github_app_config
|
|
413
|
+
YAML.load_file('test/dummy/config/secrets_double_github_app.yml')
|
|
414
|
+
end
|
|
415
|
+
end
|
|
416
|
+
end
|