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.
Files changed (235) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +13 -2
  3. data/app/assets/images/magic-solid.svg +1 -0
  4. data/app/assets/javascripts/shipit/repositories_search.js.coffee +60 -0
  5. data/app/assets/javascripts/shipit/{search.js.coffee → stack_search.js.coffee} +0 -0
  6. data/app/assets/stylesheets/_pages/_deploy.scss +2 -3
  7. data/app/assets/stylesheets/_pages/_repositories.scss +148 -0
  8. data/app/assets/stylesheets/_pages/_stacks.scss +19 -0
  9. data/app/assets/stylesheets/shipit.scss +1 -0
  10. data/app/controllers/shipit/api/ccmenu_controller.rb +1 -1
  11. data/app/controllers/shipit/api/deploys_controller.rb +2 -0
  12. data/app/controllers/shipit/api/{pull_requests_controller.rb → merge_requests_controller.rb} +8 -8
  13. data/app/controllers/shipit/api/rollbacks_controller.rb +2 -1
  14. data/app/controllers/shipit/api/stacks_controller.rb +15 -1
  15. data/app/controllers/shipit/deploys_controller.rb +1 -1
  16. data/app/controllers/shipit/merge_requests_controller.rb +31 -0
  17. data/app/controllers/shipit/merge_status_controller.rb +15 -15
  18. data/app/controllers/shipit/repositories_controller.rb +74 -0
  19. data/app/controllers/shipit/stacks_controller.rb +2 -2
  20. data/app/controllers/shipit/tasks_controller.rb +2 -2
  21. data/app/controllers/shipit/webhooks_controller.rb +23 -4
  22. data/app/helpers/shipit/chunks_helper.rb +2 -2
  23. data/app/helpers/shipit/github_url_helper.rb +8 -0
  24. data/app/helpers/shipit/shipit_helper.rb +0 -1
  25. data/app/helpers/shipit/stacks_helper.rb +4 -0
  26. data/app/jobs/shipit/create_on_github_job.rb +1 -0
  27. data/app/jobs/shipit/deliver_hook_job.rb +1 -1
  28. data/app/jobs/shipit/destroy_repository_job.rb +24 -0
  29. data/app/jobs/shipit/destroy_stack_job.rb +2 -2
  30. data/app/jobs/shipit/github_sync_job.rb +13 -9
  31. data/app/jobs/shipit/perform_task_job.rb +4 -98
  32. data/app/jobs/shipit/process_merge_requests_job.rb +32 -0
  33. data/app/jobs/shipit/refresh_merge_request_job.rb +11 -0
  34. data/app/jobs/shipit/update_github_last_deployed_ref_job.rb +1 -1
  35. data/app/models/shipit/anonymous_user.rb +10 -2
  36. data/app/models/shipit/check_run.rb +38 -2
  37. data/app/models/shipit/command_line_user.rb +4 -0
  38. data/app/models/shipit/commit.rb +31 -20
  39. data/app/models/shipit/commit_checks.rb +14 -13
  40. data/app/models/shipit/commit_deployment.rb +3 -3
  41. data/app/models/shipit/commit_deployment_status.rb +3 -3
  42. data/app/models/shipit/deploy.rb +17 -11
  43. data/app/models/shipit/deploy_spec/file_system.rb +11 -5
  44. data/app/models/shipit/deploy_spec/lerna_discovery.rb +12 -4
  45. data/app/models/shipit/deploy_spec.rb +16 -4
  46. data/app/models/shipit/duration.rb +2 -0
  47. data/app/models/shipit/hook.rb +28 -2
  48. data/app/models/shipit/merge_request.rb +304 -0
  49. data/app/models/shipit/provisioning_handler/base.rb +30 -0
  50. data/app/models/shipit/provisioning_handler/unregistered_provisioning_handler.rb +35 -0
  51. data/app/models/shipit/provisioning_handler.rb +32 -0
  52. data/app/models/shipit/pull_request.rb +26 -265
  53. data/app/models/shipit/pull_request_assignment.rb +10 -0
  54. data/app/models/shipit/release_status.rb +1 -1
  55. data/app/models/shipit/repository.rb +63 -3
  56. data/app/models/shipit/review_stack.rb +130 -0
  57. data/app/models/shipit/review_stack_provisioning_queue.rb +39 -0
  58. data/app/models/shipit/rollback.rb +5 -0
  59. data/app/models/shipit/stack.rb +78 -30
  60. data/app/models/shipit/status/group.rb +1 -1
  61. data/app/models/shipit/task.rb +62 -9
  62. data/app/models/shipit/task_execution_strategy/base.rb +20 -0
  63. data/app/models/shipit/task_execution_strategy/default.rb +109 -0
  64. data/app/models/shipit/team.rb +4 -2
  65. data/app/models/shipit/user.rb +10 -1
  66. data/app/models/shipit/webhooks/handlers/pull_request/assigned_handler.rb +74 -0
  67. data/app/models/shipit/webhooks/handlers/pull_request/closed_handler.rb +68 -0
  68. data/app/models/shipit/webhooks/handlers/pull_request/edited_handler.rb +74 -0
  69. data/app/models/shipit/webhooks/handlers/pull_request/label_capturing_handler.rb +127 -0
  70. data/app/models/shipit/webhooks/handlers/pull_request/labeled_handler.rb +106 -0
  71. data/app/models/shipit/webhooks/handlers/pull_request/opened_handler.rb +83 -0
  72. data/app/models/shipit/webhooks/handlers/pull_request/reopened_handler.rb +88 -0
  73. data/app/models/shipit/webhooks/handlers/pull_request/review_stack_adapter.rb +103 -0
  74. data/app/models/shipit/webhooks/handlers/pull_request/unlabeled_handler.rb +107 -0
  75. data/app/models/shipit/webhooks/handlers/push_handler.rb +4 -1
  76. data/app/models/shipit/webhooks.rb +10 -0
  77. data/app/serializers/shipit/deploy_serializer.rb +6 -0
  78. data/app/serializers/shipit/merge_request_serializer.rb +21 -0
  79. data/app/serializers/shipit/pull_request_serializer.rb +5 -8
  80. data/app/serializers/shipit/review_stack_serializer.rb +7 -0
  81. data/app/serializers/shipit/stack_serializer.rb +7 -6
  82. data/app/serializers/shipit/tail_task_serializer.rb +10 -2
  83. data/app/serializers/shipit/task_serializer.rb +1 -1
  84. data/app/validators/subset_validator.rb +1 -1
  85. data/app/views/layouts/merge_status.html.erb +1 -1
  86. data/app/views/shipit/merge_requests/_merge_request.html.erb +29 -0
  87. data/app/views/shipit/{pull_requests → merge_requests}/index.html.erb +2 -2
  88. data/app/views/shipit/merge_requests/merge_requests/_pull_request.html.erb +29 -0
  89. data/app/views/shipit/merge_requests/merge_requests/index.html.erb +20 -0
  90. data/app/views/shipit/merge_status/_merge_queue_button.html.erb +3 -3
  91. data/app/views/shipit/merge_status/backlogged.html.erb +1 -1
  92. data/app/views/shipit/merge_status/failure.html.erb +1 -1
  93. data/app/views/shipit/merge_status/locked.html.erb +1 -1
  94. data/app/views/shipit/merge_status/success.html.erb +2 -2
  95. data/app/views/shipit/repositories/_header.html.erb +19 -0
  96. data/app/views/shipit/repositories/index.html.erb +31 -0
  97. data/app/views/shipit/repositories/new.html.erb +23 -0
  98. data/app/views/shipit/repositories/settings.html.erb +53 -0
  99. data/app/views/shipit/repositories/show.html.erb +30 -0
  100. data/app/views/shipit/stacks/_banners.html.erb +15 -1
  101. data/app/views/shipit/stacks/_header.html.erb +5 -2
  102. data/app/views/shipit/stacks/_stack.html.erb +8 -0
  103. data/app/views/shipit/stacks/index.html.erb +2 -1
  104. data/app/views/shipit/stacks/new.html.erb +1 -1
  105. data/app/views/shipit/stacks/settings.html.erb +5 -5
  106. data/app/views/shipit/stacks/show.html.erb +1 -1
  107. data/app/views/shipit/tasks/_task_output.html.erb +1 -1
  108. data/config/routes.rb +15 -5
  109. data/config/secrets.development.example.yml +24 -0
  110. data/config/secrets.development.shopify.yml +20 -9
  111. data/db/migrate/20200706145406_add_review_stacks.rb +12 -0
  112. data/db/migrate/20200804144639_rename_pull_request_to_merge_request.rb +7 -0
  113. data/db/migrate/20200804161512_rename_commits_pull_request_id_to_merge_request_id.rb +5 -0
  114. data/db/migrate/20200813134712_recreate_shipit_pull_requests.rb +22 -0
  115. data/db/migrate/20200813194056_create_pull_request_assignments.rb +8 -0
  116. data/db/migrate/20201001125502_add_provision_pr_stacks_flag_to_repositories.rb +7 -0
  117. data/db/migrate/20201008145809_add_retry_attempt_to_tasks.rb +5 -0
  118. data/db/migrate/20201008152744_add_max_retries_to_tasks.rb +5 -0
  119. data/db/migrate/20210325194053_remove_stacks_branch_default.rb +5 -0
  120. data/db/migrate/20210504200438_add_github_updated_at_to_check_runs.rb +5 -0
  121. data/db/migrate/20210823075617_change_check_runs_github_updated_at_default.rb +5 -0
  122. data/lib/shipit/command.rb +7 -6
  123. data/lib/shipit/commands.rb +18 -5
  124. data/lib/shipit/engine.rb +2 -0
  125. data/lib/shipit/flock.rb +8 -1
  126. data/lib/shipit/github_app.rb +8 -6
  127. data/lib/shipit/octokit_iterator.rb +3 -3
  128. data/lib/shipit/review_stack_commands.rb +8 -0
  129. data/lib/shipit/simple_message_verifier.rb +2 -2
  130. data/lib/shipit/stack_commands.rb +36 -7
  131. data/lib/shipit/task_commands.rb +8 -1
  132. data/lib/shipit/version.rb +1 -1
  133. data/lib/shipit.rb +50 -16
  134. data/lib/snippets/publish-lerna-independent-packages +35 -34
  135. data/lib/snippets/publish-lerna-independent-packages-legacy +39 -0
  136. data/lib/tasks/cron.rake +11 -2
  137. data/test/controllers/api/ccmenu_controller_test.rb +1 -1
  138. data/test/controllers/api/deploys_controller_test.rb +17 -0
  139. data/test/controllers/api/{pull_requests_controller_test.rb → merge_requests_controller_test.rb} +12 -12
  140. data/test/controllers/api/outputs_controller_test.rb +1 -0
  141. data/test/controllers/api/rollback_controller_test.rb +1 -1
  142. data/test/controllers/api/stacks_controller_test.rb +42 -8
  143. data/test/controllers/{pull_requests_controller_test.rb → merge_requests_controller_test.rb} +6 -6
  144. data/test/controllers/repositories_controller_test.rb +71 -0
  145. data/test/controllers/stacks_controller_test.rb +9 -1
  146. data/test/controllers/tasks_controller_test.rb +14 -2
  147. data/test/controllers/webhooks_controller_test.rb +27 -12
  148. data/test/dummy/app/assets/config/manifest.js +3 -0
  149. data/test/dummy/config/application.rb +7 -2
  150. data/test/dummy/config/database.yml +9 -0
  151. data/test/dummy/config/environments/development.rb +1 -4
  152. data/test/dummy/config/environments/test.rb +0 -5
  153. data/test/dummy/config/secrets_double_github_app.yml +79 -0
  154. data/test/dummy/db/schema.rb +56 -17
  155. data/test/dummy/db/seeds.rb +2 -1
  156. data/test/fixtures/payloads/check_suite_master.json +4 -32
  157. data/test/fixtures/payloads/invalid_pull_request.json +117 -0
  158. data/test/fixtures/payloads/provision_disabled_pull_request.json +454 -0
  159. data/test/fixtures/payloads/pull_request_assigned.json +480 -0
  160. data/test/fixtures/payloads/pull_request_closed.json +454 -0
  161. data/test/fixtures/payloads/pull_request_labeled.json +461 -0
  162. data/test/fixtures/payloads/pull_request_opened.json +454 -0
  163. data/test/fixtures/payloads/pull_request_reopened.json +454 -0
  164. data/test/fixtures/payloads/pull_request_unlabeled.json +454 -0
  165. data/test/fixtures/payloads/pull_request_with_no_repo.json +454 -0
  166. data/test/fixtures/payloads/push_master.json +1 -1
  167. data/test/fixtures/payloads/push_not_master.json +1 -1
  168. data/test/fixtures/shipit/commits.yml +17 -4
  169. data/test/fixtures/shipit/hooks.yml +1 -0
  170. data/test/fixtures/shipit/merge_requests.yml +141 -0
  171. data/test/fixtures/shipit/pull_request_assignments.yml +3 -0
  172. data/test/fixtures/shipit/pull_requests.yml +10 -131
  173. data/test/fixtures/shipit/repositories.yml +1 -0
  174. data/test/fixtures/shipit/stacks.yml +145 -0
  175. data/test/fixtures/shipit/statuses.yml +9 -0
  176. data/test/fixtures/shipit/tasks.yml +4 -1
  177. data/test/fixtures/shipit/users.yml +7 -0
  178. data/test/helpers/json_helper.rb +5 -1
  179. data/test/helpers/payloads_helper.rb +4 -0
  180. data/test/jobs/chunk_rollup_job_test.rb +15 -1
  181. data/test/jobs/destroy_repository_job_test.rb +27 -0
  182. data/test/jobs/github_sync_job_test.rb +2 -1
  183. data/test/jobs/perform_task_job_test.rb +8 -8
  184. data/test/jobs/{merge_pull_requests_job_test.rb → process_merge_requests_job_test.rb} +18 -18
  185. data/test/lib/shipit/deploy_commands_test.rb +16 -0
  186. data/test/lib/shipit/task_commands_test.rb +17 -0
  187. data/test/models/commit_deployment_status_test.rb +3 -3
  188. data/test/models/commits_test.rb +24 -13
  189. data/test/models/deploy_spec_test.rb +64 -24
  190. data/test/models/deploys_test.rb +188 -14
  191. data/test/models/hook_test.rb +30 -1
  192. data/test/models/{pull_request_test.rb → merge_request_test.rb} +49 -34
  193. data/test/models/pull_request_assignment_test.rb +16 -0
  194. data/test/models/shipit/check_run_test.rb +124 -5
  195. data/test/models/shipit/provisioning_handler/base_test.rb +33 -0
  196. data/test/models/shipit/provisioning_handler/unregistered_provisioning_handler_test.rb +49 -0
  197. data/test/models/shipit/provisioning_handler_test.rb +64 -0
  198. data/test/models/shipit/pull_request_test.rb +52 -0
  199. data/test/models/shipit/repository_test.rb +5 -1
  200. data/test/models/shipit/review_stack_provision_status_test.rb +77 -0
  201. data/test/models/shipit/review_stack_provisioning_queue_test.rb +63 -0
  202. data/test/models/shipit/review_stack_test.rb +91 -0
  203. data/test/models/{stacks_test.rb → shipit/stacks_test.rb} +52 -8
  204. data/test/models/shipit/webhooks/handlers/pull_request/assigned_handler_test.rb +45 -0
  205. data/test/models/shipit/webhooks/handlers/pull_request/closed_handler_test.rb +192 -0
  206. data/test/models/shipit/webhooks/handlers/pull_request/edited_handler_test.rb +47 -0
  207. data/test/models/shipit/webhooks/handlers/pull_request/label_capturing_handler_test.rb +209 -0
  208. data/test/models/shipit/webhooks/handlers/pull_request/labeled_handler_test.rb +332 -0
  209. data/test/models/shipit/webhooks/handlers/pull_request/opened_handler_test.rb +238 -0
  210. data/test/models/shipit/webhooks/handlers/pull_request/reopened_handler_test.rb +282 -0
  211. data/test/models/shipit/webhooks/handlers/pull_request/review_stack_adapter_test.rb +107 -0
  212. data/test/models/shipit/webhooks/handlers/pull_request/unlabeled_handler_test.rb +324 -0
  213. data/test/models/shipit/{wehbooks → webhooks}/handlers_test.rb +0 -0
  214. data/test/models/tasks_test.rb +66 -3
  215. data/test/serializers/shipit/pull_request_serializer_test.rb +29 -0
  216. data/test/test_helper.rb +15 -0
  217. data/test/unit/anonymous_user_serializer_test.rb +1 -1
  218. data/test/unit/command_test.rb +8 -3
  219. data/test/unit/commit_serializer_test.rb +1 -1
  220. data/test/unit/deploy_commands_test.rb +73 -17
  221. data/test/unit/deploy_serializer_test.rb +1 -1
  222. data/test/unit/github_app_test.rb +2 -3
  223. data/test/unit/github_apps_test.rb +416 -0
  224. data/test/unit/github_url_helper_test.rb +5 -0
  225. data/test/unit/shipit_deployment_checks_test.rb +77 -0
  226. data/test/unit/shipit_task_execution_strategy_test.rb +47 -0
  227. data/test/unit/shipit_test.rb +14 -0
  228. data/test/unit/user_serializer_test.rb +1 -1
  229. metadata +306 -188
  230. data/app/controllers/shipit/pull_requests_controller.rb +0 -31
  231. data/app/jobs/shipit/merge_pull_requests_job.rb +0 -32
  232. data/app/jobs/shipit/refresh_pull_request_job.rb +0 -11
  233. data/app/views/shipit/pull_requests/_pull_request.html.erb +0 -29
  234. data/test/fixtures/shipit/output_chunks.yml +0 -47
  235. data/test/models/output_chunk_test.rb +0 -21
@@ -1,8 +1,10 @@
1
1
  host: 'localhost:3000'
2
2
  redis_url: 'redis://127.0.0.1:6379/0'
3
3
 
4
+ # For creating an app see: https://github.com/Shopify/shipit-engine/blob/master/docs/setup.md#creating-the-github-app
4
5
  # Can be obtained there: https://github.com/settings/apps
5
6
  # Set the "Authorization callback URL" as `<host>/github/auth/github/callback`
7
+
6
8
  github:
7
9
  app_id:
8
10
  installation_id:
@@ -12,3 +14,25 @@ github:
12
14
  id:
13
15
  secret:
14
16
  teams: # Optional
17
+
18
+ # Use this configuration schema if you are configuring multiple Github applications for different Github organizations
19
+
20
+ # github:
21
+ # somegithuborg:
22
+ # app_id:
23
+ # installation_id:
24
+ # webhook_secret: # nil
25
+ # private_key:
26
+ # oauth:
27
+ # id:
28
+ # secret:
29
+ # teams: # Optional
30
+ # someothergithuborg:
31
+ # app_id:
32
+ # installation_id:
33
+ # webhook_secret: # nil
34
+ # private_key:
35
+ # oauth:
36
+ # id:
37
+ # secret:
38
+ # teams: # Optional
@@ -1,13 +1,24 @@
1
1
  host: 'shipit-engine.myshopify.io'
2
2
  redis_url: 'redis://shipit-engine.railgun:6379'
3
3
 
4
- # TODO: document creating a dev app
4
+ # For creating an app see: https://github.com/Shopify/shipit-engine/blob/master/docs/setup.md#creating-the-github-app
5
+
5
6
  github:
6
- app_id:
7
- installation_id:
8
- webhook_secret: # nil
9
- private_key:
10
- oauth:
11
- id:
12
- secret:
13
- teams:
7
+ somegithuborg:
8
+ app_id:
9
+ installation_id:
10
+ webhook_secret: # nil
11
+ private_key:
12
+ oauth:
13
+ id:
14
+ secret:
15
+ teams:
16
+ someothergithuborg:
17
+ app_id:
18
+ installation_id:
19
+ webhook_secret: # nil
20
+ private_key:
21
+ oauth:
22
+ id:
23
+ secret:
24
+ teams:
@@ -0,0 +1,12 @@
1
+ class AddReviewStacks < ActiveRecord::Migration[6.0]
2
+ def change
3
+ add_column :stacks, :provision_status, :string, null: false, default: :deprovisioned
4
+ add_index :stacks, :provision_status
5
+
6
+ add_column :stacks, :type, :string, default: "Shipit::Stack"
7
+ add_index :stacks, :type
8
+
9
+ add_column :stacks, :awaiting_provision, :boolean, null: false, default: false
10
+ add_index :stacks, :awaiting_provision
11
+ end
12
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class RenamePullRequestToMergeRequest < ActiveRecord::Migration[6.0]
4
+ def change
5
+ rename_table :pull_requests, :merge_requests
6
+ end
7
+ end
@@ -0,0 +1,5 @@
1
+ class RenameCommitsPullRequestIdToMergeRequestId < ActiveRecord::Migration[6.0]
2
+ def change
3
+ rename_column :commits, :pull_request_id, :merge_request_id
4
+ end
5
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+ class RecreateShipitPullRequests < ActiveRecord::Migration[6.0]
3
+ def change
4
+ create_table :pull_requests do |t|
5
+ t.references :stack, null: false
6
+ t.integer :number, null: false
7
+ t.string :title, limit: 256
8
+ t.integer :github_id, limit: 8
9
+ t.string :api_url, limit: 1024
10
+ t.string :state
11
+ t.integer :additions, null: false, default: 0
12
+ t.integer :deletions, null: false, default: 0
13
+ t.integer :user_id
14
+ t.text :labels
15
+ t.references :head
16
+ t.timestamps
17
+
18
+ t.index [:stack_id, :number], unique: true
19
+ t.index [:stack_id, :github_id], unique: true
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,8 @@
1
+ class CreatePullRequestAssignments < ActiveRecord::Migration[6.0]
2
+ def change
3
+ create_table :pull_request_assignments do |t|
4
+ t.references :pull_request
5
+ t.references :user
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,7 @@
1
+ class AddProvisionPrStacksFlagToRepositories < ActiveRecord::Migration[6.0]
2
+ def change
3
+ add_column :repositories, :review_stacks_enabled, :boolean, default: false
4
+ add_column :repositories, :provisioning_behavior, :string, default: :allow_all
5
+ add_column :repositories, :provisioning_label_name, :string
6
+ end
7
+ end
@@ -0,0 +1,5 @@
1
+ class AddRetryAttemptToTasks < ActiveRecord::Migration[6.0]
2
+ def change
3
+ add_column :tasks, :retry_attempt, :integer, null: false, default: 0
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class AddMaxRetriesToTasks < ActiveRecord::Migration[6.0]
2
+ def change
3
+ add_column :tasks, :max_retries, :integer, null: true
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class RemoveStacksBranchDefault < ActiveRecord::Migration[6.1]
2
+ def change
3
+ change_column_default(:stacks, :branch, from: 'master', to: nil)
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class AddGithubUpdatedAtToCheckRuns < ActiveRecord::Migration[6.1]
2
+ def change
3
+ add_column :check_runs, :github_updated_at, :datetime, default: nil
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class ChangeCheckRunsGithubUpdatedAtDefault < ActiveRecord::Migration[6.1]
2
+ def change
3
+ change_column_default :check_runs, :github_updated_at, nil
4
+ end
5
+ end
@@ -13,7 +13,8 @@ module Shipit
13
13
  Denied = Class.new(Error)
14
14
  TimedOut = Class.new(Error)
15
15
 
16
- BASE_ENV = Bundler.clean_env.merge((ENV.keys - Bundler.clean_env.keys).map { |k| [k, nil] }.to_h)
16
+ unbundled_env = Bundler.respond_to?(:unbundled_env) ? Bundler.unbundled_env : Bundler.clean_env
17
+ BASE_ENV = unbundled_env.merge((ENV.keys - unbundled_env.keys).map { |k| [k, nil] }.to_h)
17
18
 
18
19
  class Failed < Error
19
20
  attr_reader :exit_code
@@ -29,7 +30,7 @@ module Shipit
29
30
  def initialize(*args, default_timeout: Shipit.default_inactivity_timeout, env: {}, chdir:)
30
31
  @args, options = parse_arguments(args)
31
32
  @timeout = options['timeout'] || options[:timeout] || default_timeout
32
- @env = env
33
+ @env = env.transform_values { |v| v&.to_s }
33
34
  @chdir = chdir.to_s
34
35
  @timed_out = false
35
36
  end
@@ -86,7 +87,7 @@ module Shipit
86
87
  @out = @pid = nil
87
88
  FileUtils.mkdir_p(@chdir)
88
89
  begin
89
- @out, child_in, @pid = PTY.spawn(clean_env, *interpolated_arguments, chdir: @chdir)
90
+ @out, child_in, @pid = PTY.spawn(unbundled_env, *interpolated_arguments, chdir: @chdir)
90
91
  child_in.close
91
92
  rescue Errno::ENOENT
92
93
  raise NotFound, "#{Shellwords.split(interpolated_arguments.first).first}: command not found"
@@ -97,8 +98,8 @@ module Shipit
97
98
  self
98
99
  end
99
100
 
100
- def clean_env
101
- BASE_ENV.merge('PATH' => "#{ENV['PATH']}:#{Shipit.shell_paths.join(':')}").merge(@env.stringify_keys)
101
+ def unbundled_env
102
+ BASE_ENV.merge('PATH' => "#{Shipit.shell_paths.join(':')}:#{ENV['PATH']}").merge(@env.stringify_keys)
102
103
  end
103
104
 
104
105
  def stream(&block)
@@ -216,7 +217,7 @@ module Shipit
216
217
  argument
217
218
  end
218
219
  end
219
- [args, options]
220
+ [args.map(&:to_s), options]
220
221
  end
221
222
 
222
223
  def running?
@@ -20,15 +20,28 @@ module Shipit
20
20
  delegate :git_version, to: :class
21
21
 
22
22
  def env
23
- @env ||= Shipit.env.merge(
24
- 'GITHUB_DOMAIN' => Shipit.github.domain,
25
- 'GITHUB_TOKEN' => Shipit.github.token,
23
+ base_env
24
+ end
25
+
26
+ def git(*args)
27
+ kwargs = args.extract_options!
28
+ kwargs[:env] ||= base_env
29
+ Command.new("git", *args, **kwargs)
30
+ end
31
+ ruby2_keywords :git if respond_to?(:ruby2_keywords, true)
32
+
33
+ private
34
+
35
+ def base_env
36
+ @base_env ||= Shipit.env.merge(
37
+ 'GITHUB_DOMAIN' => github.domain,
38
+ 'GITHUB_TOKEN' => github.token,
26
39
  'GIT_ASKPASS' => Shipit::Engine.root.join('lib', 'snippets', 'git-askpass').realpath.to_s,
27
40
  )
28
41
  end
29
42
 
30
- def git(*args)
31
- Command.new("git", *args)
43
+ def github
44
+ Shipit.github
32
45
  end
33
46
  end
34
47
  end
data/lib/shipit/engine.rb CHANGED
@@ -10,6 +10,8 @@ module Shipit
10
10
  Shipit::Engine.routes.default_url_options[:host] = Shipit.host
11
11
  Pubsubstub.redis_url = Shipit.redis_url.to_s
12
12
 
13
+ Rails.application.secrets.deep_symbolize_keys!
14
+
13
15
  app.config.assets.paths << Emoji.images_path
14
16
  app.config.assets.precompile += %w(
15
17
  favicon.ico
data/lib/shipit/flock.rb CHANGED
@@ -11,14 +11,21 @@ module Shipit
11
11
 
12
12
  def initialize(path)
13
13
  @path = Pathname.new(path)
14
+ @acquired = false
14
15
  end
15
16
 
16
17
  def lock(timeout:)
18
+ return yield if @acquired
17
19
  path.parent.mkpath
18
20
  path.open('w') do |file|
19
21
  if retrying(timeout: timeout) { file.flock(File::LOCK_EX | File::LOCK_NB) }
20
22
  file.write($PROCESS_ID.to_s)
21
- return yield
23
+ @acquired = true
24
+ begin
25
+ yield
26
+ ensure
27
+ @acquired = false
28
+ end
22
29
  else
23
30
  raise TimeoutError, "Couldn't acquire lock for #{path} in #{timeout} seconds"
24
31
  end
@@ -42,8 +42,9 @@ module Shipit
42
42
 
43
43
  attr_reader :oauth_teams, :domain, :bot_login
44
44
 
45
- def initialize(config)
45
+ def initialize(organization, config)
46
46
  super()
47
+ @organization = organization
47
48
  @config = (config || {}).with_indifferent_access
48
49
  @domain = @config[:domain] || DOMAIN
49
50
  @webhook_secret = @config[:webhook_secret].presence
@@ -52,7 +53,7 @@ module Shipit
52
53
  oauth = (@config[:oauth] || {}).with_indifferent_access
53
54
  @oauth_id = oauth[:id]
54
55
  @oauth_secret = oauth[:secret]
55
- @oauth_teams = Array.wrap(oauth[:teams] || oauth[:teams])
56
+ @oauth_teams = Array.wrap(oauth[:teams])
56
57
  end
57
58
 
58
59
  def login
@@ -92,10 +93,11 @@ module Shipit
92
93
  end
93
94
 
94
95
  def fetch_new_token
96
+ cache_key = @organization.nil? ? '' : "#{@organization.downcase}:"
95
97
  # Rails can add 5 minutes to the cache entry expiration time when any TTL is provided,
96
98
  # so our TTL setting can be lower, and TTL + expires_in should be lower than the GitHub token expiration.
97
99
  Rails.cache.fetch(
98
- 'github:integration:access-token',
100
+ "github:integration:#{cache_key}access-token",
99
101
  expires_in: GITHUB_TOKEN_RAILS_CACHE_LIFETIME,
100
102
  race_condition_ttl: 4.minutes,
101
103
  ) do
@@ -181,15 +183,15 @@ module Shipit
181
183
  end
182
184
 
183
185
  def app_id
184
- @app_id ||= @config.fetch(:app_id)
186
+ @config.fetch(:app_id)
185
187
  end
186
188
 
187
189
  def installation_id
188
- @installation_id ||= @config.fetch(:installation_id)
190
+ @config.fetch(:installation_id)
189
191
  end
190
192
 
191
193
  def private_key
192
- @private_key ||= @config.fetch(:private_key)
194
+ @config.fetch(:private_key)
193
195
  end
194
196
 
195
197
  def authentication_payload
@@ -3,12 +3,12 @@ module Shipit
3
3
  class OctokitIterator
4
4
  include Enumerable
5
5
 
6
- def initialize(relation = nil)
6
+ def initialize(relation = nil, github_api: nil)
7
7
  if relation
8
8
  @response = relation.get(per_page: 100)
9
9
  else
10
- data = yield Shipit.github.api
11
- @response = Shipit.github.api.last_response if data.present?
10
+ data = yield github_api
11
+ @response = github_api.last_response if data.present?
12
12
  end
13
13
  end
14
14
 
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'shipit/stack_commands'
4
+
5
+ module Shipit
6
+ class ReviewStackCommands < Shipit::StackCommands
7
+ end
8
+ end
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
  module Shipit
3
3
  class SimpleMessageVerifier < ActiveSupport::MessageVerifier
4
- def initialize(secret, options = {})
4
+ def initialize(secret, **options)
5
5
  options[:serializer] ||= ToS
6
- super(secret, options)
6
+ super(secret, **options)
7
7
  end
8
8
 
9
9
  private
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+ # rubocop:disable Lint/MissingSuper
2
3
  require 'pathname'
3
4
  require 'fileutils'
4
5
 
@@ -8,21 +9,31 @@ module Shipit
8
9
  @stack = stack
9
10
  end
10
11
 
12
+ def env
13
+ super.merge(@stack.env)
14
+ end
15
+
11
16
  def fetch
12
17
  create_directories
13
- if Dir.exist?(@stack.git_path)
18
+ if valid_git_repository?(@stack.git_path)
14
19
  git('fetch', 'origin', '--tags', @stack.branch, env: env, chdir: @stack.git_path)
15
20
  else
21
+ @stack.clear_git_cache!
16
22
  git_clone(@stack.repo_git_url, @stack.git_path, branch: @stack.branch, env: env, chdir: @stack.deploys_path)
17
23
  end
18
24
  end
19
25
 
20
26
  def fetched?(commit)
21
- git_dir = File.join(@stack.git_path, '.git')
22
- if Dir.exist?(git_dir)
27
+ if valid_git_repository?(@stack.git_path)
23
28
  git('rev-parse', '--quiet', '--verify', "#{commit.sha}^{commit}", env: env, chdir: @stack.git_path)
24
29
  else
25
- Command.new('test', '-d', git_dir, env: env, chdir: @stack.deploys_path)
30
+ # When the stack's git cache is not valid, the commit is
31
+ # NOT fetched. To keep the interface of this method
32
+ # consistent, we must return a Shipit::Command whose #success?
33
+ # method returns false - has a non-zero exit status. We utilize
34
+ # the POSIX 'test' command with no arguments which should
35
+ # always have an exit status of 1.
36
+ Command.new('test', env: env, chdir: @stack.deploys_path)
26
37
  end
27
38
  end
28
39
 
@@ -56,18 +67,30 @@ module Shipit
56
67
  Dir.mktmpdir do |dir|
57
68
  git(
58
69
  'clone', @stack.git_path, @stack.repo_name,
59
- '--origin', 'cache',
70
+ '--recursive', '--origin', 'cache',
60
71
  chdir: dir
61
72
  ).run!
62
73
 
63
74
  git_dir = File.join(dir, @stack.repo_name)
64
- git('checkout', commit.sha, chdir: git_dir).run! if commit
75
+ git('-c', 'advice.detachedHead=false', 'checkout', commit.sha, chdir: git_dir).run! if commit
65
76
  yield Pathname.new(git_dir)
66
77
  end
67
78
  end
68
79
 
80
+ def valid_git_repository?(path)
81
+ path.exist? &&
82
+ !path.empty? &&
83
+ git_cmd_succeeds?(path)
84
+ end
85
+
86
+ def git_cmd_succeeds?(path)
87
+ git("rev-parse", "--git-dir", chdir: path)
88
+ .tap(&:run)
89
+ .success?
90
+ end
91
+
69
92
  def git_clone(url, path, branch: 'master', **kwargs)
70
- git('clone', *modern_git_args, '--recursive', '--branch', branch, url, path, **kwargs)
93
+ git('clone', '--quiet', *modern_git_args, '--recursive', '--branch', branch, url, path, **kwargs)
71
94
  end
72
95
 
73
96
  def modern_git_args
@@ -78,5 +101,11 @@ module Shipit
78
101
  def create_directories
79
102
  FileUtils.mkdir_p(@stack.deploys_path)
80
103
  end
104
+
105
+ private
106
+
107
+ def github
108
+ Shipit.github(organization: @stack.repository.owner)
109
+ end
81
110
  end
82
111
  end