shipit-engine 0.30.0 → 0.34.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.
Files changed (410) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +19 -4
  3. data/Rakefile +4 -2
  4. data/app/assets/images/magic-solid.svg +1 -0
  5. data/app/assets/javascripts/shipit/repositories_search.js.coffee +60 -0
  6. data/app/assets/javascripts/shipit/{search.js.coffee → stack_search.js.coffee} +0 -0
  7. data/app/assets/stylesheets/_pages/_deploy.scss +0 -2
  8. data/app/assets/stylesheets/_pages/_repositories.scss +148 -0
  9. data/app/assets/stylesheets/_pages/_stacks.scss +19 -3
  10. data/app/assets/stylesheets/merge_status.scss +0 -3
  11. data/app/assets/stylesheets/shipit.scss +1 -0
  12. data/app/controllers/concerns/shipit/active_model_serializers_patch.rb +1 -0
  13. data/app/controllers/concerns/shipit/api/cacheable.rb +1 -0
  14. data/app/controllers/concerns/shipit/api/paginable.rb +3 -2
  15. data/app/controllers/concerns/shipit/api/rendering.rb +5 -4
  16. data/app/controllers/concerns/shipit/authentication.rb +3 -2
  17. data/app/controllers/concerns/shipit/pagination.rb +2 -1
  18. data/app/controllers/shipit/api/base_controller.rb +11 -6
  19. data/app/controllers/shipit/api/ccmenu_controller.rb +2 -1
  20. data/app/controllers/shipit/api/commits_controller.rb +2 -1
  21. data/app/controllers/shipit/api/deploys_controller.rb +6 -3
  22. data/app/controllers/shipit/api/hooks_controller.rb +6 -5
  23. data/app/controllers/shipit/api/locks_controller.rb +5 -4
  24. data/app/controllers/shipit/api/merge_requests_controller.rb +37 -0
  25. data/app/controllers/shipit/api/outputs_controller.rb +2 -1
  26. data/app/controllers/shipit/api/release_statuses_controller.rb +3 -2
  27. data/app/controllers/shipit/api/rollbacks_controller.rb +34 -0
  28. data/app/controllers/shipit/api/stacks_controller.rb +32 -5
  29. data/app/controllers/shipit/api/tasks_controller.rb +6 -5
  30. data/app/controllers/shipit/api_clients_controller.rb +4 -3
  31. data/app/controllers/shipit/ccmenu_url_controller.rb +4 -3
  32. data/app/controllers/shipit/commit_checks_controller.rb +2 -1
  33. data/app/controllers/shipit/commits_controller.rb +2 -1
  34. data/app/controllers/shipit/deploys_controller.rb +4 -3
  35. data/app/controllers/shipit/github_authentication_controller.rb +4 -3
  36. data/app/controllers/shipit/merge_requests_controller.rb +31 -0
  37. data/app/controllers/shipit/merge_status_controller.rb +31 -30
  38. data/app/controllers/shipit/release_statuses_controller.rb +3 -2
  39. data/app/controllers/shipit/repositories_controller.rb +74 -0
  40. data/app/controllers/shipit/rollbacks_controller.rb +3 -2
  41. data/app/controllers/shipit/shipit_controller.rb +2 -1
  42. data/app/controllers/shipit/stacks_controller.rb +24 -9
  43. data/app/controllers/shipit/status_controller.rb +2 -1
  44. data/app/controllers/shipit/tasks_controller.rb +7 -6
  45. data/app/controllers/shipit/webhooks_controller.rb +26 -6
  46. data/app/helpers/shipit/chunks_helper.rb +3 -2
  47. data/app/helpers/shipit/deploys_helper.rb +4 -3
  48. data/app/helpers/shipit/github_url_helper.rb +9 -0
  49. data/app/helpers/shipit/merge_status_helper.rb +1 -0
  50. data/app/helpers/shipit/shipit_helper.rb +1 -1
  51. data/app/helpers/shipit/stacks_helper.rb +5 -0
  52. data/app/helpers/shipit/tasks_helper.rb +1 -0
  53. data/app/jobs/shipit/background_job.rb +4 -0
  54. data/app/jobs/shipit/background_job/unique.rb +1 -0
  55. data/app/jobs/shipit/cache_deploy_spec_job.rb +1 -0
  56. data/app/jobs/shipit/chunk_rollup_job.rb +4 -0
  57. data/app/jobs/shipit/clear_git_cache_job.rb +1 -0
  58. data/app/jobs/shipit/continuous_delivery_job.rb +2 -1
  59. data/app/jobs/shipit/create_on_github_job.rb +7 -1
  60. data/app/jobs/shipit/create_release_statuses_job.rb +1 -0
  61. data/app/jobs/shipit/deferred_touch_job.rb +4 -0
  62. data/app/jobs/shipit/deliver_hook_job.rb +2 -1
  63. data/app/jobs/shipit/destroy_job.rb +1 -0
  64. data/app/jobs/shipit/destroy_repository_job.rb +24 -0
  65. data/app/jobs/shipit/destroy_stack_job.rb +3 -2
  66. data/app/jobs/shipit/emit_event_job.rb +2 -1
  67. data/app/jobs/shipit/fetch_commit_stats_job.rb +1 -0
  68. data/app/jobs/shipit/fetch_deployed_revision_job.rb +1 -0
  69. data/app/jobs/shipit/github_sync_job.rb +15 -10
  70. data/app/jobs/shipit/mark_deploy_healthy_job.rb +1 -0
  71. data/app/jobs/shipit/perform_commit_checks_job.rb +1 -0
  72. data/app/jobs/shipit/perform_task_job.rb +5 -92
  73. data/app/jobs/shipit/process_merge_requests_job.rb +32 -0
  74. data/app/jobs/shipit/purge_old_deliveries_job.rb +1 -0
  75. data/app/jobs/shipit/reap_dead_tasks_job.rb +21 -0
  76. data/app/jobs/shipit/refresh_check_runs_job.rb +1 -0
  77. data/app/jobs/shipit/refresh_github_user_job.rb +1 -0
  78. data/app/jobs/shipit/refresh_merge_request_job.rb +11 -0
  79. data/app/jobs/shipit/refresh_statuses_job.rb +1 -0
  80. data/app/jobs/shipit/setup_github_hook_job.rb +1 -0
  81. data/app/jobs/shipit/update_estimated_deploy_duration_job.rb +1 -0
  82. data/app/jobs/shipit/update_github_last_deployed_ref_job.rb +5 -4
  83. data/app/models/concerns/shipit/deferred_touch.rb +4 -3
  84. data/app/models/shipit/anonymous_user.rb +15 -2
  85. data/app/models/shipit/api_client.rb +3 -2
  86. data/app/models/shipit/application_record.rb +2 -1
  87. data/app/models/shipit/check_run.rb +41 -4
  88. data/app/models/shipit/command_line_user.rb +5 -0
  89. data/app/models/shipit/commit.rb +42 -24
  90. data/app/models/shipit/commit_checks.rb +15 -13
  91. data/app/models/shipit/commit_deployment.rb +6 -5
  92. data/app/models/shipit/commit_deployment_status.rb +5 -4
  93. data/app/models/shipit/commit_message.rb +1 -0
  94. data/app/models/shipit/delivery.rb +4 -3
  95. data/app/models/shipit/deploy.rb +23 -28
  96. data/app/models/shipit/deploy_spec.rb +38 -7
  97. data/app/models/shipit/deploy_spec/bundler_discovery.rb +1 -0
  98. data/app/models/shipit/deploy_spec/capistrano_discovery.rb +1 -0
  99. data/app/models/shipit/deploy_spec/file_system.rb +20 -7
  100. data/app/models/shipit/deploy_spec/kubernetes_discovery.rb +1 -0
  101. data/app/models/shipit/deploy_spec/lerna_discovery.rb +13 -4
  102. data/app/models/shipit/deploy_spec/npm_discovery.rb +5 -4
  103. data/app/models/shipit/deploy_spec/pypi_discovery.rb +1 -0
  104. data/app/models/shipit/deploy_spec/rubygems_discovery.rb +1 -0
  105. data/app/models/shipit/deploy_stats.rb +2 -1
  106. data/app/models/shipit/duration.rb +5 -2
  107. data/app/models/shipit/ephemeral_commit_checks.rb +1 -0
  108. data/app/models/shipit/github_hook.rb +2 -1
  109. data/app/models/shipit/github_status.rb +2 -1
  110. data/app/models/shipit/hook.rb +34 -7
  111. data/app/models/shipit/membership.rb +3 -2
  112. data/app/models/shipit/merge_request.rb +304 -0
  113. data/app/models/shipit/output_chunk.rb +7 -2
  114. data/app/models/shipit/provisioning_handler.rb +32 -0
  115. data/app/models/shipit/provisioning_handler/base.rb +30 -0
  116. data/app/models/shipit/provisioning_handler/unregistered_provisioning_handler.rb +35 -0
  117. data/app/models/shipit/pull_request.rb +28 -266
  118. data/app/models/shipit/pull_request_assignment.rb +10 -0
  119. data/app/models/shipit/record.rb +18 -0
  120. data/app/models/shipit/release_status.rb +4 -3
  121. data/app/models/shipit/repository.rb +71 -6
  122. data/app/models/shipit/review_stack.rb +130 -0
  123. data/app/models/shipit/review_stack_provisioning_queue.rb +39 -0
  124. data/app/models/shipit/rollback.rb +1 -0
  125. data/app/models/shipit/stack.rb +144 -44
  126. data/app/models/shipit/status.rb +3 -2
  127. data/app/models/shipit/status/common.rb +7 -6
  128. data/app/models/shipit/status/group.rb +2 -1
  129. data/app/models/shipit/status/missing.rb +2 -1
  130. data/app/models/shipit/status/unknown.rb +2 -1
  131. data/app/models/shipit/task.rb +98 -12
  132. data/app/models/shipit/task_definition.rb +1 -0
  133. data/app/models/shipit/task_execution_strategy/base.rb +20 -0
  134. data/app/models/shipit/task_execution_strategy/default.rb +109 -0
  135. data/app/models/shipit/team.rb +6 -3
  136. data/app/models/shipit/undeployed_commit.rb +1 -0
  137. data/app/models/shipit/unlimited_api_client.rb +1 -0
  138. data/app/models/shipit/user.rb +19 -8
  139. data/app/models/shipit/variable_definition.rb +1 -0
  140. data/app/models/shipit/webhooks.rb +11 -0
  141. data/app/models/shipit/webhooks/handlers/check_suite_handler.rb +1 -0
  142. data/app/models/shipit/webhooks/handlers/handler.rb +1 -0
  143. data/app/models/shipit/webhooks/handlers/membership_handler.rb +1 -0
  144. data/app/models/shipit/webhooks/handlers/pull_request/assigned_handler.rb +74 -0
  145. data/app/models/shipit/webhooks/handlers/pull_request/closed_handler.rb +68 -0
  146. data/app/models/shipit/webhooks/handlers/pull_request/edited_handler.rb +74 -0
  147. data/app/models/shipit/webhooks/handlers/pull_request/label_capturing_handler.rb +127 -0
  148. data/app/models/shipit/webhooks/handlers/pull_request/labeled_handler.rb +106 -0
  149. data/app/models/shipit/webhooks/handlers/pull_request/opened_handler.rb +83 -0
  150. data/app/models/shipit/webhooks/handlers/pull_request/reopened_handler.rb +88 -0
  151. data/app/models/shipit/webhooks/handlers/pull_request/review_stack_adapter.rb +103 -0
  152. data/app/models/shipit/webhooks/handlers/pull_request/unlabeled_handler.rb +107 -0
  153. data/app/models/shipit/webhooks/handlers/push_handler.rb +5 -1
  154. data/app/models/shipit/webhooks/handlers/status_handler.rb +1 -0
  155. data/app/serializers/concerns/shipit/conditional_attributes.rb +1 -0
  156. data/app/serializers/shipit/anonymous_user_serializer.rb +1 -0
  157. data/app/serializers/shipit/command_line_user_serializer.rb +1 -0
  158. data/app/serializers/shipit/commit_serializer.rb +1 -0
  159. data/app/serializers/shipit/deploy_serializer.rb +8 -1
  160. data/app/serializers/shipit/hook_serializer.rb +1 -0
  161. data/app/serializers/shipit/merge_request_serializer.rb +21 -0
  162. data/app/serializers/shipit/pull_request_serializer.rb +6 -8
  163. data/app/serializers/shipit/review_stack_serializer.rb +7 -0
  164. data/app/serializers/shipit/rollback_serializer.rb +1 -0
  165. data/app/serializers/shipit/short_commit_serializer.rb +1 -0
  166. data/app/serializers/shipit/stack_serializer.rb +8 -6
  167. data/app/serializers/shipit/tail_task_serializer.rb +11 -2
  168. data/app/serializers/shipit/task_serializer.rb +2 -17
  169. data/app/serializers/shipit/user_serializer.rb +6 -1
  170. data/app/validators/ascii_only_validator.rb +1 -0
  171. data/app/validators/subset_validator.rb +2 -1
  172. data/app/views/layouts/merge_status.html.erb +1 -1
  173. data/app/views/layouts/shipit.html.erb +1 -1
  174. data/app/views/shipit/_variables.html.erb +1 -1
  175. data/app/views/shipit/ccmenu/project.xml.builder +2 -1
  176. data/app/views/shipit/deploys/show.html.erb +2 -2
  177. data/app/views/shipit/merge_requests/_merge_request.html.erb +29 -0
  178. data/app/views/shipit/{pull_requests → merge_requests}/index.html.erb +2 -2
  179. data/app/views/shipit/merge_requests/merge_requests/_pull_request.html.erb +29 -0
  180. data/app/views/shipit/merge_requests/merge_requests/index.html.erb +20 -0
  181. data/app/views/shipit/merge_status/_merge_queue_button.html.erb +3 -3
  182. data/app/views/shipit/merge_status/backlogged.html.erb +1 -1
  183. data/app/views/shipit/merge_status/failure.html.erb +1 -1
  184. data/app/views/shipit/merge_status/locked.html.erb +1 -1
  185. data/app/views/shipit/merge_status/success.html.erb +2 -2
  186. data/app/views/shipit/repositories/_header.html.erb +19 -0
  187. data/app/views/shipit/repositories/index.html.erb +31 -0
  188. data/app/views/shipit/repositories/new.html.erb +23 -0
  189. data/app/views/shipit/repositories/settings.html.erb +53 -0
  190. data/app/views/shipit/repositories/show.html.erb +30 -0
  191. data/app/views/shipit/stacks/_banners.html.erb +15 -1
  192. data/app/views/shipit/stacks/_header.html.erb +20 -7
  193. data/app/views/shipit/stacks/_stack.html.erb +8 -0
  194. data/app/views/shipit/stacks/all_tasks.html.erb +28 -0
  195. data/app/views/shipit/stacks/index.html.erb +3 -2
  196. data/app/views/shipit/stacks/new.html.erb +1 -1
  197. data/app/views/shipit/stacks/settings.html.erb +5 -5
  198. data/app/views/shipit/stacks/show.html.erb +1 -1
  199. data/app/views/shipit/tasks/_task_output.html.erb +1 -1
  200. data/app/views/shipit/tasks/show.html.erb +1 -1
  201. data/config/initializers/inflections.rb +2 -1
  202. data/config/locales/en.yml +4 -3
  203. data/config/routes.rb +25 -7
  204. data/config/secrets.development.example.yml +24 -0
  205. data/config/secrets.development.shopify.yml +20 -9
  206. data/db/migrate/20200226211925_add_index_to_tasks_status.rb +5 -0
  207. data/db/migrate/20200427135152_add_pull_request_head_sha_to_commit.rb +5 -0
  208. data/db/migrate/20200615181558_add_rollback_once_aborted_to.rb +5 -0
  209. data/db/migrate/20200706145406_add_review_stacks.rb +12 -0
  210. data/db/migrate/20200804144639_rename_pull_request_to_merge_request.rb +7 -0
  211. data/db/migrate/20200804161512_rename_commits_pull_request_id_to_merge_request_id.rb +5 -0
  212. data/db/migrate/20200813134712_recreate_shipit_pull_requests.rb +22 -0
  213. data/db/migrate/20200813194056_create_pull_request_assignments.rb +8 -0
  214. data/db/migrate/20201001125502_add_provision_pr_stacks_flag_to_repositories.rb +7 -0
  215. data/db/migrate/20201008145809_add_retry_attempt_to_tasks.rb +5 -0
  216. data/db/migrate/20201008152744_add_max_retries_to_tasks.rb +5 -0
  217. data/db/migrate/20210325194053_remove_stacks_branch_default.rb +5 -0
  218. data/db/migrate/20210504200438_add_github_updated_at_to_check_runs.rb +5 -0
  219. data/lib/shipit.rb +61 -17
  220. data/lib/shipit/cast_value.rb +1 -0
  221. data/lib/shipit/command.rb +20 -21
  222. data/lib/shipit/commands.rb +14 -6
  223. data/lib/shipit/csv_serializer.rb +1 -0
  224. data/lib/shipit/deploy_commands.rb +1 -0
  225. data/lib/shipit/engine.rb +9 -2
  226. data/lib/shipit/environment_variables.rb +11 -1
  227. data/lib/shipit/first_parent_commits_iterator.rb +1 -0
  228. data/lib/shipit/flock.rb +9 -1
  229. data/lib/shipit/github_app.rb +15 -12
  230. data/lib/shipit/github_http_cache_middleware.rb +1 -0
  231. data/lib/shipit/null_serializer.rb +1 -0
  232. data/lib/shipit/octokit_check_runs.rb +3 -2
  233. data/lib/shipit/octokit_iterator.rb +4 -3
  234. data/lib/shipit/paginator.rb +3 -2
  235. data/lib/shipit/review_stack_commands.rb +8 -0
  236. data/lib/shipit/rollback_commands.rb +1 -0
  237. data/lib/shipit/same_site_cookie_middleware.rb +29 -0
  238. data/lib/shipit/simple_message_verifier.rb +3 -2
  239. data/lib/shipit/stack_commands.rb +37 -7
  240. data/lib/shipit/stat.rb +1 -0
  241. data/lib/shipit/task_commands.rb +23 -16
  242. data/lib/shipit/version.rb +2 -1
  243. data/lib/snippets/publish-lerna-independent-packages +35 -34
  244. data/lib/snippets/publish-lerna-independent-packages-legacy +39 -0
  245. data/lib/snippets/release-gem +5 -1
  246. data/lib/tasks/cron.rake +13 -2
  247. data/lib/tasks/dev.rake +3 -2
  248. data/lib/tasks/shipit.rake +15 -14
  249. data/lib/tasks/teams.rake +1 -0
  250. data/test/controllers/api/base_controller_test.rb +3 -2
  251. data/test/controllers/api/ccmenu_controller_test.rb +9 -8
  252. data/test/controllers/api/commits_controller_test.rb +3 -2
  253. data/test/controllers/api/deploys_controller_test.rb +32 -14
  254. data/test/controllers/api/hooks_controller_test.rb +8 -7
  255. data/test/controllers/api/locks_controller_test.rb +7 -6
  256. data/test/controllers/api/{pull_requests_controller_test.rb → merge_requests_controller_test.rb} +17 -16
  257. data/test/controllers/api/outputs_controller_test.rb +3 -1
  258. data/test/controllers/api/release_statuses_controller_test.rb +2 -1
  259. data/test/controllers/api/rollback_controller_test.rb +113 -0
  260. data/test/controllers/api/stacks_controller_test.rb +71 -16
  261. data/test/controllers/api/tasks_controller_test.rb +13 -12
  262. data/test/controllers/api_clients_controller_test.rb +5 -4
  263. data/test/controllers/ccmenu_controller_test.rb +4 -3
  264. data/test/controllers/commit_checks_controller_test.rb +4 -3
  265. data/test/controllers/commits_controller_test.rb +3 -2
  266. data/test/controllers/deploys_controller_test.rb +32 -21
  267. data/test/controllers/github_authentication_controller_test.rb +1 -0
  268. data/test/controllers/merge_requests_controller_test.rb +32 -0
  269. data/test/controllers/merge_status_controller_test.rb +7 -6
  270. data/test/controllers/release_statuses_controller_test.rb +3 -2
  271. data/test/controllers/repositories_controller_test.rb +71 -0
  272. data/test/controllers/rollbacks_controller_test.rb +9 -8
  273. data/test/controllers/stacks_controller_test.rb +41 -19
  274. data/test/controllers/status_controller_test.rb +1 -0
  275. data/test/controllers/tasks_controller_test.rb +32 -19
  276. data/test/controllers/webhooks_controller_test.rb +33 -17
  277. data/test/dummy/app/assets/config/manifest.js +3 -0
  278. data/test/dummy/config/application.rb +7 -2
  279. data/test/dummy/config/database.yml +9 -0
  280. data/test/dummy/config/environments/development.rb +3 -4
  281. data/test/dummy/config/environments/test.rb +2 -5
  282. data/test/dummy/config/secrets_double_github_app.yml +79 -0
  283. data/test/dummy/db/schema.rb +59 -17
  284. data/test/dummy/db/seeds.rb +2 -1
  285. data/test/fixtures/payloads/check_suite_master.json +4 -32
  286. data/test/fixtures/payloads/invalid_pull_request.json +117 -0
  287. data/test/fixtures/payloads/provision_disabled_pull_request.json +454 -0
  288. data/test/fixtures/payloads/pull_request_assigned.json +480 -0
  289. data/test/fixtures/payloads/pull_request_closed.json +454 -0
  290. data/test/fixtures/payloads/pull_request_labeled.json +461 -0
  291. data/test/fixtures/payloads/pull_request_opened.json +454 -0
  292. data/test/fixtures/payloads/pull_request_reopened.json +454 -0
  293. data/test/fixtures/payloads/pull_request_unlabeled.json +454 -0
  294. data/test/fixtures/payloads/pull_request_with_no_repo.json +454 -0
  295. data/test/fixtures/payloads/push_master.json +1 -1
  296. data/test/fixtures/payloads/push_not_master.json +1 -1
  297. data/test/fixtures/shipit/commits.yml +31 -3
  298. data/test/fixtures/shipit/hooks.yml +1 -0
  299. data/test/fixtures/shipit/merge_requests.yml +141 -0
  300. data/test/fixtures/shipit/pull_request_assignments.yml +3 -0
  301. data/test/fixtures/shipit/pull_requests.yml +10 -131
  302. data/test/fixtures/shipit/repositories.yml +5 -0
  303. data/test/fixtures/shipit/stacks.yml +235 -14
  304. data/test/fixtures/shipit/statuses.yml +9 -0
  305. data/test/fixtures/shipit/tasks.yml +4 -1
  306. data/test/fixtures/shipit/users.yml +7 -0
  307. data/test/fixtures/timeout +2 -1
  308. data/test/helpers/api_helper.rb +1 -0
  309. data/test/helpers/fixture_aliases_helper.rb +1 -0
  310. data/test/helpers/hooks_helper.rb +2 -1
  311. data/test/helpers/json_helper.rb +20 -12
  312. data/test/helpers/links_helper.rb +4 -3
  313. data/test/helpers/payloads_helper.rb +5 -0
  314. data/test/helpers/queries_helper.rb +3 -2
  315. data/test/jobs/cache_deploy_spec_job_test.rb +2 -1
  316. data/test/jobs/chunk_rollup_job_test.rb +16 -1
  317. data/test/jobs/deliver_hook_job_test.rb +1 -0
  318. data/test/jobs/destroy_repository_job_test.rb +27 -0
  319. data/test/jobs/destroy_stack_job_test.rb +1 -0
  320. data/test/jobs/emit_event_job_test.rb +2 -1
  321. data/test/jobs/fetch_commit_stats_job_test.rb +1 -0
  322. data/test/jobs/fetch_deployed_revision_job_test.rb +1 -0
  323. data/test/jobs/github_sync_job_test.rb +3 -1
  324. data/test/jobs/mark_deploy_healthy_job_test.rb +1 -0
  325. data/test/jobs/perform_task_job_test.rb +12 -11
  326. data/test/jobs/{merge_pull_requests_job_test.rb → process_merge_requests_job_test.rb} +19 -18
  327. data/test/jobs/purge_old_deliveries_job_test.rb +1 -0
  328. data/test/jobs/reap_dead_tasks_job_test.rb +68 -0
  329. data/test/jobs/refresh_github_user_job_test.rb +1 -0
  330. data/test/jobs/refresh_status_job_test.rb +1 -0
  331. data/test/jobs/unique_job_test.rb +1 -0
  332. data/test/jobs/update_github_last_deployed_ref_job_test.rb +1 -0
  333. data/test/lib/shipit/deploy_commands_test.rb +16 -0
  334. data/test/lib/shipit/task_commands_test.rb +17 -0
  335. data/test/middleware/same_site_cookie_middleware_test.rb +52 -0
  336. data/test/models/api_client_test.rb +1 -0
  337. data/test/models/commit_checks_test.rb +1 -0
  338. data/test/models/commit_deployment_status_test.rb +4 -3
  339. data/test/models/commit_deployment_test.rb +2 -1
  340. data/test/models/commits_test.rb +96 -19
  341. data/test/models/delivery_test.rb +2 -1
  342. data/test/models/deploy_spec_test.rb +110 -65
  343. data/test/models/deploy_stats_test.rb +1 -0
  344. data/test/models/deploys_test.rb +197 -36
  345. data/test/models/duration_test.rb +1 -0
  346. data/test/models/github_hook_test.rb +1 -0
  347. data/test/models/hook_test.rb +47 -10
  348. data/test/models/membership_test.rb +1 -0
  349. data/test/models/{pull_request_test.rb → merge_request_test.rb} +53 -37
  350. data/test/models/pull_request_assignment_test.rb +16 -0
  351. data/test/models/release_statuses_test.rb +1 -0
  352. data/test/models/rollbacks_test.rb +1 -0
  353. data/test/models/shipit/check_run_test.rb +125 -5
  354. data/test/models/shipit/provisioning_handler/base_test.rb +33 -0
  355. data/test/models/shipit/provisioning_handler/unregistered_provisioning_handler_test.rb +49 -0
  356. data/test/models/shipit/provisioning_handler_test.rb +64 -0
  357. data/test/models/shipit/pull_request_test.rb +52 -0
  358. data/test/models/shipit/repository_test.rb +6 -1
  359. data/test/models/shipit/review_stack_provision_status_test.rb +77 -0
  360. data/test/models/shipit/review_stack_provisioning_queue_test.rb +63 -0
  361. data/test/models/shipit/review_stack_test.rb +91 -0
  362. data/test/models/{stacks_test.rb → shipit/stacks_test.rb} +121 -16
  363. data/test/models/shipit/webhooks/handlers/pull_request/assigned_handler_test.rb +45 -0
  364. data/test/models/shipit/webhooks/handlers/pull_request/closed_handler_test.rb +192 -0
  365. data/test/models/shipit/webhooks/handlers/pull_request/edited_handler_test.rb +47 -0
  366. data/test/models/shipit/webhooks/handlers/pull_request/label_capturing_handler_test.rb +209 -0
  367. data/test/models/shipit/webhooks/handlers/pull_request/labeled_handler_test.rb +332 -0
  368. data/test/models/shipit/webhooks/handlers/pull_request/opened_handler_test.rb +238 -0
  369. data/test/models/shipit/webhooks/handlers/pull_request/reopened_handler_test.rb +282 -0
  370. data/test/models/shipit/webhooks/handlers/pull_request/review_stack_adapter_test.rb +107 -0
  371. data/test/models/shipit/webhooks/handlers/pull_request/unlabeled_handler_test.rb +324 -0
  372. data/test/models/shipit/{wehbooks → webhooks}/handlers_test.rb +1 -0
  373. data/test/models/status/group_test.rb +1 -0
  374. data/test/models/status/missing_test.rb +1 -0
  375. data/test/models/status_test.rb +1 -0
  376. data/test/models/task_definitions_test.rb +9 -8
  377. data/test/models/tasks_test.rb +81 -1
  378. data/test/models/team_test.rb +4 -2
  379. data/test/models/undeployed_commits_test.rb +1 -0
  380. data/test/models/users_test.rb +13 -5
  381. data/test/serializers/shipit/pull_request_serializer_test.rb +29 -0
  382. data/test/test_command_integration.rb +3 -2
  383. data/test/test_helper.rb +49 -31
  384. data/test/unit/anonymous_user_serializer_test.rb +14 -0
  385. data/test/unit/command_test.rb +16 -10
  386. data/test/unit/commands_test.rb +1 -0
  387. data/test/unit/commit_serializer_test.rb +16 -0
  388. data/test/unit/csv_serializer_test.rb +3 -2
  389. data/test/unit/deploy_commands_test.rb +75 -18
  390. data/test/unit/deploy_serializer_test.rb +17 -0
  391. data/test/unit/environment_variables_test.rb +5 -4
  392. data/test/unit/github_app_test.rb +3 -3
  393. data/test/unit/github_apps_test.rb +416 -0
  394. data/test/unit/github_url_helper_test.rb +6 -0
  395. data/test/unit/rollback_commands_test.rb +2 -1
  396. data/test/unit/shipit_deployment_checks_test.rb +77 -0
  397. data/test/unit/shipit_helper_test.rb +17 -0
  398. data/test/unit/shipit_task_execution_strategy_test.rb +47 -0
  399. data/test/unit/shipit_test.rb +15 -0
  400. data/test/unit/user_serializer_test.rb +14 -0
  401. data/test/unit/variable_definition_test.rb +1 -0
  402. metadata +320 -178
  403. data/app/controllers/shipit/api/pull_requests_controller.rb +0 -36
  404. data/app/controllers/shipit/pull_requests_controller.rb +0 -30
  405. data/app/jobs/shipit/merge_pull_requests_job.rb +0 -31
  406. data/app/jobs/shipit/refresh_pull_request_job.rb +0 -10
  407. data/app/views/shipit/pull_requests/_pull_request.html.erb +0 -29
  408. data/test/controllers/pull_requests_controller_test.rb +0 -31
  409. data/test/fixtures/shipit/output_chunks.yml +0 -47
  410. data/test/models/output_chunk_test.rb +0 -20
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'test_helper'
2
3
 
3
4
  module Shipit
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+ require 'test_helper'
3
+
4
+ module Shipit
5
+ class CommitSerializerTest < ActiveSupport::TestCase
6
+ test 'commit includes author object' do
7
+ commit = shipit_commits(:first)
8
+
9
+ serializer = ActiveModel::Serializer.serializer_for(commit)
10
+ assert_equal CommitSerializer, serializer
11
+ serialized = serializer.new(commit).to_json
12
+
13
+ assert_json_document(serialized, "author.name", commit.author.name)
14
+ end
15
+ end
16
+ end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'test_helper'
2
3
 
3
4
  module Shipit
@@ -28,7 +29,7 @@ module Shipit
28
29
  def assert_dumped(expected, object)
29
30
  message = "Expected CSVSerializer.dump(#{object.inspect}) to eq #{expected.inspect}"
30
31
  if expected.nil?
31
- assert_nil Shipit::CSVSerializer.dump(object), message
32
+ assert_nil(Shipit::CSVSerializer.dump(object), message)
32
33
  else
33
34
  assert_equal(expected, Shipit::CSVSerializer.dump(object), message)
34
35
  end
@@ -37,7 +38,7 @@ module Shipit
37
38
  def assert_loaded(expected, payload)
38
39
  message = "Expected CSVSerializer.load(#{payload.inspect}) to eq #{expected.inspect}"
39
40
  if expected.nil?
40
- assert_nil Shipit::CSVSerializer.load(payload), message
41
+ assert_nil(Shipit::CSVSerializer.load(payload), message)
41
42
  else
42
43
  assert_equal(expected, Shipit::CSVSerializer.load(payload), message)
43
44
  end
@@ -1,16 +1,18 @@
1
+ # frozen_string_literal: true
1
2
  require 'test_helper'
2
3
 
3
4
  module Shipit
4
5
  class DeployCommandsTest < ActiveSupport::TestCase
5
6
  def setup
6
- @stack = shipit_stacks(:shipit)
7
7
  @deploy = shipit_deploys(:shipit_pending)
8
+ @stack = @deploy.stack
9
+ @stack.stubs(:clear_git_cache!)
8
10
  @commands = DeployCommands.new(@deploy)
9
11
  @deploy_spec = stub(
10
12
  dependencies_steps!: ['bundle install --some-args'],
11
13
  deploy_steps!: ['bundle exec cap $ENVIRONMENT deploy'],
12
14
  rollback_steps!: ['bundle exec cap $ENVIRONMENT deploy:rollback'],
13
- machine_env: {'GLOBAL' => '1'},
15
+ machine_env: { 'GLOBAL' => '1' },
14
16
  directory: nil,
15
17
  clear_working_directory?: true,
16
18
  )
@@ -20,59 +22,114 @@ module Shipit
20
22
  end
21
23
 
22
24
  test "#fetch calls git fetch if repository cache already exist" do
23
- Dir.expects(:exist?).with(@stack.git_path).returns(true)
25
+ @stack.git_path.stubs(:exist?).returns(true)
26
+ @stack.git_path.stubs(:empty?).returns(false)
27
+
24
28
  command = @commands.fetch
29
+
25
30
  assert_equal %w(git fetch origin --tags master), command.args
26
31
  end
27
32
 
28
33
  test "#fetch calls git fetch in git_path directory if repository cache already exist" do
29
- Dir.expects(:exist?).with(@stack.git_path).returns(true)
34
+ @stack.git_path.stubs(:exist?).returns(true)
35
+ @stack.git_path.stubs(:empty?).returns(false)
36
+
30
37
  command = @commands.fetch
31
- assert_equal @stack.git_path, command.chdir
38
+
39
+ assert_equal @stack.git_path.to_s, command.chdir
32
40
  end
33
41
 
34
42
  test "#fetch calls git clone if repository cache do not exist" do
35
- Dir.expects(:exist?).with(@stack.git_path).returns(false)
43
+ @stack.git_path.stubs(:exist?).returns(false)
44
+
45
+ command = @commands.fetch
46
+
47
+ expected = %W(git clone --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
+
55
+ command = @commands.fetch
56
+
57
+ expected = %W(git clone --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
+
36
68
  command = @commands.fetch
69
+
70
+ expected = %W(git clone --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
+
37
84
  expected = %W(git clone --single-branch --recursive --branch master #{@stack.repo_git_url} #{@stack.git_path})
38
85
  assert_equal expected, command.args
39
86
  end
40
87
 
41
88
  test "#fetch does not use --single-branch if git is outdated" do
42
- Dir.expects(:exist?).with(@stack.git_path).returns(false)
89
+ @stack.git_path.stubs(:exist?).returns(false)
43
90
  StackCommands.stubs(git_version: Gem::Version.new('1.7.2.30'))
91
+
44
92
  command = @commands.fetch
93
+
45
94
  expected = %W(git clone --recursive --branch master #{@stack.repo_git_url} #{@stack.git_path})
46
- assert_equal expected, command.args
95
+ assert_equal expected, command.args.map(&:to_s)
47
96
  end
48
97
 
49
98
  test "#fetch calls git fetch in base_path directory if repository cache do not exist" do
50
- Dir.expects(:exist?).with(@stack.git_path).returns(false)
99
+ @stack.git_path.stubs(:exist?).returns(false)
100
+
51
101
  command = @commands.fetch
52
- assert_equal @stack.deploys_path, command.chdir
102
+
103
+ assert_equal @stack.deploys_path.to_s, command.chdir
53
104
  end
54
105
 
55
106
  test "#fetch merges Shipit.env in ENVIRONMENT" do
56
107
  Shipit.stubs(:env).returns("SPECIFIC_CONFIG" => 5)
57
108
  command = @commands.fetch
58
- 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"]
59
116
  end
60
117
 
61
118
  test "#clone clones the repository cache into the working directory" do
62
119
  commands = @commands.clone
63
120
  assert_equal 2, commands.size
64
121
  clone_args = [
65
- 'git', 'clone', '--local',
66
- '--origin', 'cache',
67
- @stack.git_path, @deploy.working_directory
122
+ 'git', 'clone', '--quiet',
123
+ '--local', '--origin', 'cache',
124
+ @stack.git_path.to_s, @deploy.working_directory,
68
125
  ]
69
126
  assert_equal clone_args, commands.first.args
70
- 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
71
128
  end
72
129
 
73
130
  test "#clone clones the repository cache from the deploys_path" do
74
131
  commands = @commands.clone
75
- assert_equal @stack.deploys_path, commands.first.chdir
132
+ assert_equal @stack.deploys_path.to_s, commands.first.chdir
76
133
  end
77
134
 
78
135
  test "#checkout checks out the deployed commit" do
@@ -181,7 +238,7 @@ module Shipit
181
238
  test "#install_dependencies merges Shipit.env in ENVIRONMENT" do
182
239
  Shipit.stubs(:env).returns("SPECIFIC_CONFIG" => 5)
183
240
  command = @commands.install_dependencies.first
184
- assert_equal 5, command.env["SPECIFIC_CONFIG"]
241
+ assert_equal '5', command.env["SPECIFIC_CONFIG"]
185
242
  end
186
243
 
187
244
  test "#install_dependencies merges machine_env in ENVIRONMENT" do
@@ -190,7 +247,7 @@ module Shipit
190
247
  end
191
248
 
192
249
  test "the deploy's `env` is merged in ENVIRONMENT" do
193
- @deploy.env = {'FOO' => 'BAR'}
250
+ @deploy.env = { 'FOO' => 'BAR' }
194
251
  command = @commands.install_dependencies.first
195
252
  assert_equal 'BAR', command.env['FOO']
196
253
  end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+ require 'test_helper'
3
+
4
+ module Shipit
5
+ class DeploySerializerTest < ActiveSupport::TestCase
6
+ test 'deploy commits includes author object' do
7
+ deploy = shipit_deploys(:shipit)
8
+ first_commit_author = deploy.commits.first.author
9
+
10
+ serializer = ActiveModel::Serializer.serializer_for(deploy)
11
+ assert_equal DeploySerializer, serializer
12
+ serialized = serializer.new(deploy).to_json
13
+
14
+ assert_json_document(serialized, "commits.0.author.name", first_commit_author.name)
15
+ end
16
+ end
17
+ end
@@ -1,11 +1,12 @@
1
+ # frozen_string_literal: true
1
2
  require 'test_helper'
2
3
 
3
4
  module Shipit
4
5
  class EnvironmentVariablesTest < ActiveSupport::TestCase
5
6
  def setup
6
7
  variable_defs = [
7
- {"name" => "FOO", "title" => "Set to 0 to foo", "default" => 1},
8
- {"name" => "BAR", "title" => "Set to 1 to bar", "default" => 0},
8
+ { "name" => "FOO", "title" => "Set to 0 to foo", "default" => 1 },
9
+ { "name" => "BAR", "title" => "Set to 1 to bar", "default" => 0 },
9
10
  ]
10
11
  @variable_definitions = variable_defs.map(&VariableDefinition.method(:new))
11
12
  end
@@ -16,7 +17,7 @@ module Shipit
16
17
  end
17
18
 
18
19
  test 'correctly sanitizes env variables' do
19
- env = {'FOO' => 1, 'BAR' => 1}
20
+ env = { 'FOO' => 1, 'BAR' => 1 }
20
21
  assert_equal env, EnvironmentVariables.with(env).permit(@variable_definitions)
21
22
  end
22
23
 
@@ -27,7 +28,7 @@ module Shipit
27
28
  end
28
29
 
29
30
  test 'throws an exception when a variable is not whitelisted' do
30
- env = {'UNSAFE_VARIABLE' => 1}
31
+ env = { 'UNSAFE_VARIABLE' => 1 }
31
32
  assert_raises(EnvironmentVariables::NotPermitted) do
32
33
  EnvironmentVariables.with(env).permit(@variable_definitions)
33
34
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'test_helper'
2
3
 
3
4
  module Shipit
@@ -17,7 +18,7 @@ module Shipit
17
18
 
18
19
  test "#initialize doesn't raise if given an empty config" do
19
20
  assert_nothing_raised do
20
- GitHubApp.new({})
21
+ GitHubApp.new(nil, {})
21
22
  end
22
23
  end
23
24
 
@@ -182,7 +183,6 @@ module Shipit
182
183
  .any_instance
183
184
  .expects(:create_app_installation_access_token).with(config[:installation_id], anything)
184
185
  .returns(second_token)
185
-
186
186
  first_token = valid_app.token
187
187
 
188
188
  first_cached_token = Rails.cache.fetch(@token_cache_key)
@@ -198,7 +198,7 @@ module Shipit
198
198
  private
199
199
 
200
200
  def app(extra_config = {})
201
- GitHubApp.new(default_config.deep_merge(extra_config))
201
+ GitHubApp.new(nil, default_config.deep_merge(extra_config))
202
202
  end
203
203
 
204
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