shipit-engine 0.15.0 → 0.16.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 (111) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +34 -1
  3. data/app/assets/javascripts/shipit/page_updater.js.coffee +63 -0
  4. data/app/assets/javascripts/shipit/stacks.js.coffee +9 -21
  5. data/app/assets/stylesheets/_base/_base.scss +2 -2
  6. data/app/assets/stylesheets/_base/_colors.scss +0 -1
  7. data/app/assets/stylesheets/_base/_forms.scss +14 -0
  8. data/app/assets/stylesheets/_pages/_commits.scss +16 -6
  9. data/app/assets/stylesheets/_pages/_settings.scss +8 -0
  10. data/app/assets/stylesheets/_pages/_stacks.scss +1 -1
  11. data/app/controllers/shipit/api/base_controller.rb +7 -3
  12. data/app/controllers/shipit/api/ccmenu_controller.rb +33 -0
  13. data/app/controllers/shipit/api/pull_requests_controller.rb +36 -0
  14. data/app/controllers/shipit/api/stacks_controller.rb +1 -0
  15. data/app/controllers/shipit/ccmenu_url_controller.rb +22 -0
  16. data/app/controllers/shipit/pull_requests_controller.rb +30 -0
  17. data/app/controllers/shipit/stacks_controller.rb +7 -2
  18. data/app/controllers/shipit/webhooks_controller.rb +1 -2
  19. data/app/helpers/shipit/github_url_helper.rb +8 -2
  20. data/app/helpers/shipit/shipit_helper.rb +9 -0
  21. data/app/helpers/shipit/stacks_helper.rb +22 -7
  22. data/app/jobs/shipit/background_job/unique.rb +19 -1
  23. data/app/jobs/shipit/cache_deploy_spec_job.rb +1 -1
  24. data/app/jobs/shipit/merge_pull_requests_job.rb +26 -0
  25. data/app/jobs/shipit/perform_task_job.rb +1 -1
  26. data/app/jobs/shipit/refresh_pull_request_job.rb +8 -0
  27. data/app/models/concerns/shipit/deferred_touch.rb +6 -1
  28. data/app/models/shipit/anonymous_user.rb +4 -0
  29. data/app/models/shipit/application_record.rb +5 -0
  30. data/app/models/shipit/commit.rb +51 -49
  31. data/app/models/shipit/commit_message.rb +32 -0
  32. data/app/models/shipit/deploy.rb +5 -0
  33. data/app/models/shipit/deploy_spec.rb +26 -1
  34. data/app/models/shipit/deploy_spec/file_system.rb +6 -1
  35. data/app/models/shipit/deploy_spec/kubernetes_discovery.rb +10 -13
  36. data/app/models/shipit/deploy_spec/npm_discovery.rb +2 -1
  37. data/app/models/shipit/duration.rb +3 -1
  38. data/app/models/shipit/hook.rb +1 -0
  39. data/app/models/shipit/pull_request.rb +252 -0
  40. data/app/models/shipit/stack.rb +33 -17
  41. data/app/models/shipit/status.rb +1 -16
  42. data/app/models/shipit/status/common.rb +45 -0
  43. data/app/models/shipit/status/group.rb +82 -0
  44. data/app/models/shipit/status/missing.rb +30 -0
  45. data/app/models/shipit/status/unknown.rb +33 -0
  46. data/app/models/shipit/unlimited_api_client.rb +10 -0
  47. data/app/serializers/shipit/commit_serializer.rb +1 -1
  48. data/app/serializers/shipit/pull_request_serializer.rb +20 -0
  49. data/app/serializers/shipit/stack_serializer.rb +6 -2
  50. data/app/views/layouts/shipit.html.erb +41 -39
  51. data/app/views/shipit/ccmenu/project.xml.builder +13 -0
  52. data/app/views/shipit/commits/_commit.html.erb +1 -1
  53. data/app/views/shipit/deploys/_deploy.html.erb +1 -1
  54. data/app/views/shipit/pull_requests/_pull_request.html.erb +29 -0
  55. data/app/views/shipit/pull_requests/index.html.erb +20 -0
  56. data/app/views/shipit/shared/_author.html.erb +7 -0
  57. data/app/views/shipit/stacks/_header.html.erb +5 -0
  58. data/app/views/shipit/stacks/settings.html.erb +13 -0
  59. data/app/views/shipit/stacks/show.html.erb +3 -2
  60. data/app/views/shipit/statuses/_group.html.erb +1 -1
  61. data/app/views/shipit/tasks/_task.html.erb +1 -1
  62. data/config/initializers/inflections.rb +3 -0
  63. data/config/locales/en.yml +1 -3
  64. data/config/routes.rb +8 -0
  65. data/db/migrate/20170130113633_create_shipit_pull_requests.rb +25 -0
  66. data/db/migrate/20170208143657_add_pull_request_number_and_title_to_commits.rb +7 -0
  67. data/db/migrate/20170208154609_backfill_merge_commits.rb +13 -0
  68. data/db/migrate/20170209160355_add_branch_to_pull_requests.rb +5 -0
  69. data/db/migrate/20170215123538_add_merge_queue_enabled_to_stacks.rb +5 -0
  70. data/db/migrate/20170220152410_improve_users_indexing.rb +6 -0
  71. data/db/migrate/20170221102128_improve_tasks_indexing.rb +8 -0
  72. data/db/migrate/20170221130336_add_last_revalidated_at_on_pull_requests.rb +10 -0
  73. data/lib/shipit.rb +2 -0
  74. data/lib/shipit/version.rb +1 -1
  75. data/lib/tasks/cron.rake +1 -0
  76. data/test/controllers/api/ccmenu_controller_test.rb +57 -0
  77. data/test/controllers/api/commits_controller_test.rb +1 -1
  78. data/test/controllers/api/pull_requests_controller_test.rb +59 -0
  79. data/test/controllers/ccmenu_controller_test.rb +33 -0
  80. data/test/controllers/pull_requests_controller_test.rb +31 -0
  81. data/test/controllers/webhooks_controller_test.rb +3 -4
  82. data/test/dummy/config/environments/development.rb +3 -1
  83. data/test/dummy/data/stacks/shopify/junk/production/git/README.md +8 -0
  84. data/test/dummy/data/stacks/shopify/junk/production/git/circle.yml +4 -0
  85. data/test/dummy/data/stacks/shopify/junk/production/git/shipit.yml +4 -0
  86. data/test/dummy/db/development.sqlite3 +0 -0
  87. data/test/dummy/db/schema.rb +45 -11
  88. data/test/dummy/db/seeds.rb +33 -10
  89. data/test/dummy/db/test.sqlite3 +0 -0
  90. data/test/fixtures/shipit/commits.yml +14 -0
  91. data/test/fixtures/shipit/pull_requests.yml +56 -0
  92. data/test/fixtures/shipit/stacks.yml +5 -1
  93. data/test/fixtures/shipit/statuses.yml +8 -0
  94. data/test/helpers/json_helper.rb +16 -14
  95. data/test/jobs/merge_pull_requests_job_test.rb +59 -0
  96. data/test/models/commits_test.rb +104 -49
  97. data/test/{unit → models}/deploy_spec_test.rb +138 -12
  98. data/test/models/deploys_test.rb +10 -4
  99. data/test/models/pull_request_test.rb +197 -0
  100. data/test/models/stacks_test.rb +46 -53
  101. data/test/models/status/group_test.rb +44 -0
  102. data/test/models/status/missing_test.rb +23 -0
  103. data/test/models/status_test.rb +3 -6
  104. data/test/unit/csv_serializer_test.rb +10 -2
  105. metadata +57 -12
  106. data/app/models/shipit/missing_status.rb +0 -21
  107. data/app/models/shipit/status_group.rb +0 -35
  108. data/app/models/shipit/unknown_status.rb +0 -48
  109. data/app/views/shipit/commits/_commit_author.html.erb +0 -7
  110. data/test/models/missing_status_test.rb +0 -23
  111. data/test/models/status_group_test.rb +0 -26
@@ -0,0 +1,20 @@
1
+ <% subscribe events_path(channels: ["stack.#{@stack.id}"]), '.pr-list', '.header' %>
2
+
3
+ <%= render partial: 'shipit/stacks/header', locals: { stack: @stack } %>
4
+
5
+ <div class="wrapper">
6
+ <section>
7
+ <header class="section-header">
8
+ <%= form_tag stack_pull_requests_path(@stack) do %>
9
+ <div class="field-wrapper inline">
10
+ <%= text_field_tag :number_or_url, '', placeholder: 'PR number or URL' %>
11
+ <%= submit_tag 'Request merge', class: 'btn' %>
12
+ </div>
13
+ <% end %>
14
+ </header>
15
+
16
+ <ul class="pr-list">
17
+ <%= render @pull_requests %>
18
+ </ul>
19
+ </section>
20
+ </div>
@@ -0,0 +1,7 @@
1
+ <a href="<%= github_user_url(author.login) %>" class="commit-author">
2
+ <%= github_avatar(author, size: 80, class: 'commit-author__avatar') %>
3
+ <div class="commit-author__name">
4
+ <span class="commit-author__name__real-name"><%= author.name %></span>
5
+ <span class="commit-author__name__username"><%= author.login %></span>
6
+ </div>
7
+ </a>
@@ -22,6 +22,11 @@
22
22
  <li class="nav__list__item">
23
23
  <%= link_to 'Timeline', index_stack_tasks_path(stack) %>
24
24
  </li>
25
+ <% if stack.merge_queue_enabled? %>
26
+ <li class="nav__list__item">
27
+ <%= link_to "Pull Requests (#{stack.pull_requests.queued.count})", stack_pull_requests_path(stack) %>
28
+ </li>
29
+ <% end %>
25
30
  </ul>
26
31
  <ul class="nav__list nav__list--secondary">
27
32
  <% if stack.links.present? %>
@@ -23,6 +23,11 @@
23
23
  <%= f.label :continuous_deployment, 'Enable continuous deployment' %>
24
24
  </div>
25
25
 
26
+ <div class="field-wrapper">
27
+ <%= f.check_box :merge_queue_enabled %>
28
+ <%= f.label :merge_queue_enabled, 'Enable merge queue' %>
29
+ </div>
30
+
26
31
  <div class="field-wrapper">
27
32
  <%= f.check_box :ignore_ci %>
28
33
  <%= f.label :ignore_ci, "Don't require CI to deploy" %>
@@ -66,6 +71,14 @@
66
71
  </table>
67
72
  </div>
68
73
 
74
+ <div class="setting-section setting-ccmenu">
75
+ <h5>Miscellaneous</h5>
76
+ <div class="field-wrapper">
77
+ <label>CCMenu URL</label>
78
+ <input id="ccmenu-url" class="hidden" type="text" disabled />
79
+ </div>
80
+ <%= button_to "Fetch URL", "", class: 'btn', data: {remote: ccmenu_url_url(stack_id: @stack.to_param)} %>
81
+ </div>
69
82
 
70
83
  <div class="setting-section">
71
84
  <h5>Delete this stack</h5>
@@ -1,3 +1,5 @@
1
+ <% subscribe events_path(channels: ["stack.#{@stack.id}"]), '#layout-content' %>
2
+
1
3
  <%= render partial: 'shipit/stacks/header', locals: { stack: @stack } %>
2
4
 
3
5
  <% if !@stack.ignore_ci && !@stack.ci_enabled? %>
@@ -63,8 +65,7 @@
63
65
  </div>
64
66
  <% end %>
65
67
 
66
- <div class="wrapper" data-event-stream="<%= events_path(channels: ["stack.#{@stack.id}"]) %>">
67
-
68
+ <div class="wrapper">
68
69
  <section>
69
70
  <header class="section-header">
70
71
  <h2>Undeployed Commits</h2>
@@ -7,7 +7,7 @@
7
7
  <strong class="status-item__service"><%= group.description %></strong>
8
8
  </div>
9
9
  <% group.statuses.each do |status| %>
10
- <div class="status-item status-item--<%= status.state %> <%= :ignored if status.ignored? %>">
10
+ <div class="status-item status-item--<%= status.state %> <%= :ignored if status.allowed_to_fail? %>">
11
11
  <i class="status-item__icon"></i>
12
12
  <a href="<%= status.target_url %>" target="_blank">
13
13
  <strong class="status-item__service"><%= status.context %></strong>
@@ -1,7 +1,7 @@
1
1
  <%- read_only ||= false -%>
2
2
 
3
3
  <li class="task" id="task-<%= task.id %>" data-status="<%= task.status %>">
4
- <%= render 'shipit/commits/commit_author', commit: task %>
4
+ <%= render 'shipit/shared/author', author: task.author %>
5
5
  <a href="<%= stack_task_path(@stack, task) %>" class="status status--<%= task.status %>" data-tooltip="<%= task.status.capitalize %>">
6
6
  <i class="status__icon"></i>
7
7
  <span class="visually-hidden"><%= task.status %></span>
@@ -0,0 +1,3 @@
1
+ ActiveSupport::Inflector.inflections(:en) do |inflect|
2
+ inflect.acronym 'CCMenu'
3
+ end
@@ -43,9 +43,7 @@ en:
43
43
  rollback: Impossible to detect how to rollback this application. Please define `rollback.override` in your shipit.yml
44
44
  fetch: Impossible to detect how to fetch the deployed revision for this application. Please define `fetch` in your shipit.yml
45
45
  missing_status:
46
- description:
47
- one: "%{missing_statuses} is required for deploy but was not sent"
48
- other: "%{missing_statuses} are required for deploy but were not sent"
46
+ description: "%{context} is required for deploy but was not sent yet."
49
47
  deploys:
50
48
  description: "deploy of %{sha}"
51
49
  rollbacks:
@@ -30,12 +30,14 @@ Shipit::Engine.routes.draw do
30
30
  end
31
31
 
32
32
  scope '/stacks/*stack_id', stack_id: stack_id_format, as: :stack do
33
+ get '/ccmenu' => 'ccmenu#show', as: :ccmenu
33
34
  resource :lock, only: %i(create update destroy)
34
35
  resources :tasks, only: %i(index show) do
35
36
  resource :output, only: :show
36
37
  end
37
38
  resources :deploys, only: %i(create)
38
39
  resources :commits, only: %i(index)
40
+ resources :pull_requests, only: %i(index show update destroy)
39
41
  post '/task/:task_name' => 'tasks#trigger', as: :trigger_task
40
42
  resources :hooks, only: %i(index create show update destroy)
41
43
  end
@@ -43,6 +45,10 @@ Shipit::Engine.routes.draw do
43
45
  resources :hooks, only: %i(index create show update destroy)
44
46
  end
45
47
 
48
+ scope '/ccmenu/*stack_id', stack_id: stack_id_format, as: :ccmenu_url do
49
+ get '/' => 'ccmenu_url#fetch'
50
+ end
51
+
46
52
  # Humans
47
53
  scope '/github/auth/github', as: :github_authentication, controller: :github_authentication do
48
54
  get '/', action: :request
@@ -87,6 +93,8 @@ Shipit::Engine.routes.draw do
87
93
  get :revert
88
94
  end
89
95
  end
96
+
97
+ resources :pull_requests, only: %i(index destroy create)
90
98
  end
91
99
  get '/stacks/:id' => 'stacks#lookup'
92
100
  end
@@ -0,0 +1,25 @@
1
+ class CreateShipitPullRequests < ActiveRecord::Migration[5.0]
2
+ def change
3
+ create_table :pull_requests do |t|
4
+ t.references :stack, foreign_key: true, null: false
5
+ t.integer :number, null: false
6
+ t.string :title, limit: 256
7
+ t.integer :github_id, limit: 8
8
+ t.string :api_url, limit: 1024
9
+ t.string :state
10
+ t.references :head, foreign_key: {to_table: :commits}
11
+ t.boolean :mergeable, null: true
12
+ t.integer :additions, null: false, default: 0
13
+ t.integer :deletions, null: false, default: 0
14
+ t.string :merge_status, null: false, limit: 30
15
+ t.string :rejection_reason, null: true
16
+ t.datetime :merge_requested_at, null: false
17
+ t.references :merge_requested_by, foreign_key: {to_table: :users}
18
+ t.timestamps
19
+
20
+ t.index [:stack_id, :number], unique: true
21
+ t.index [:stack_id, :github_id], unique: true
22
+ t.index [:stack_id, :merge_status]
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,7 @@
1
+ class AddPullRequestNumberAndTitleToCommits < ActiveRecord::Migration[5.0]
2
+ def change
3
+ add_column :commits, :pull_request_number, :integer, null: true
4
+ add_column :commits, :pull_request_title, :string, limit: 1024, null: true
5
+ add_column :commits, :pull_request_id, :integer, null: true, index: true
6
+ end
7
+ end
@@ -0,0 +1,13 @@
1
+ class BackfillMergeCommits < ActiveRecord::Migration[5.0]
2
+ def change
3
+ ActiveRecord::Base.no_touching do
4
+ Shipit::Commit.find_in_batches do |commits|
5
+ commits.each do |commit|
6
+ commit.identify_pull_request
7
+ commit.save!
8
+ end
9
+ print '.'
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,5 @@
1
+ class AddBranchToPullRequests < ActiveRecord::Migration[5.0]
2
+ def change
3
+ add_column :pull_requests, :branch, :string, null: true
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class AddMergeQueueEnabledToStacks < ActiveRecord::Migration[5.0]
2
+ def change
3
+ add_column :stacks, :merge_queue_enabled, :boolean, default: false, null: false
4
+ end
5
+ end
@@ -0,0 +1,6 @@
1
+ class ImproveUsersIndexing < ActiveRecord::Migration[5.0]
2
+ def change
3
+ add_index :users, :updated_at
4
+ add_index :users, :github_id
5
+ end
6
+ end
@@ -0,0 +1,8 @@
1
+ class ImproveTasksIndexing < ActiveRecord::Migration[5.0]
2
+ def change
3
+ # index_active_tasks should superseed this, but for some reason
4
+ # MySQL tend to chose the wrong index. This one while wasting a bit of memory
5
+ # makes it do a better choice.
6
+ add_index :tasks, %i(stack_id allow_concurrency)
7
+ end
8
+ end
@@ -0,0 +1,10 @@
1
+ class AddLastRevalidatedAtOnPullRequests < ActiveRecord::Migration[5.0]
2
+ def up
3
+ add_column :pull_requests, :revalidated_at, :datetime
4
+ Shipit::PullRequest.update_all('revalidated_at = merge_requested_at')
5
+ end
6
+
7
+ def down
8
+ remove_column :pull_requests, :revalidated_at
9
+ end
10
+ end
@@ -56,6 +56,8 @@ module Shipit
56
56
 
57
57
  delegate :table_name_prefix, to: :secrets
58
58
 
59
+ attr_accessor :disable_api_authentication
60
+
59
61
  def app_name
60
62
  @app_name ||= secrets.app_name || Rails.application.class.name.split(':').first || 'Shipit'
61
63
  end
@@ -1,3 +1,3 @@
1
1
  module Shipit
2
- VERSION = '0.15.0'.freeze
2
+ VERSION = '0.16.0'.freeze
3
3
  end
@@ -4,6 +4,7 @@ namespace :cron do
4
4
  Shipit::Stack.refresh_deployed_revisions
5
5
  Shipit::Stack.schedule_continuous_delivery
6
6
  Shipit::GithubStatus.refresh_status
7
+ Shipit::PullRequest.schedule_merges
7
8
  end
8
9
 
9
10
  task hourly: [:rollup, :purge_deliveries, :refresh_users]
@@ -0,0 +1,57 @@
1
+ require 'test_helper'
2
+
3
+ module Shipit
4
+ module Api
5
+ class CCMenuControllerTest < ActionController::TestCase
6
+ setup do
7
+ authenticate!
8
+ @stack = shipit_stacks(:shipit)
9
+ end
10
+
11
+ test "a request with insufficient permissions will render a 403" do
12
+ @client.update!(permissions: [])
13
+ get :show, params: {stack_id: @stack.to_param}
14
+ assert_response :forbidden
15
+ assert_json 'message', 'This operation requires the `read:stack` permission'
16
+ end
17
+
18
+ test "#show renders the xml" do
19
+ get :show, params: {stack_id: @stack.to_param}
20
+ assert_response :ok
21
+ assert_payload 'name', @stack.to_param
22
+ end
23
+
24
+ test "can authenticate with query string token" do
25
+ request.headers['Authorization'] = 'bleh'
26
+ get :show, params: {stack_id: @stack.to_param, token: @client.authentication_token}
27
+ assert_response :ok
28
+ assert_payload 'name', @stack.to_param
29
+ end
30
+
31
+ test "xml contains required attributes" do
32
+ get :show, params: {stack_id: @stack.to_param}
33
+ project = get_project_from_xml(response.body)
34
+ %w(name activity lastBuildStatus lastBuildLabel lastBuildTime webUrl).each do |attribute|
35
+ assert_includes project, attribute, "Response missing required attribute: #{attribute}"
36
+ end
37
+ end
38
+
39
+ test "locked stacks show as failed" do
40
+ @stack.lock('test', @user)
41
+ get :show, params: {stack_id: @stack.to_param}
42
+ assert_payload 'lastBuildStatus', 'Failure'
43
+ end
44
+
45
+ private
46
+
47
+ def get_project_from_xml(xml)
48
+ Hash.from_xml(xml)['Projects']['Project']
49
+ end
50
+
51
+ def assert_payload(k, v)
52
+ @project ||= get_project_from_xml(response.body)
53
+ assert_equal v, @project[k]
54
+ end
55
+ end
56
+ end
57
+ end
@@ -9,7 +9,7 @@ module Shipit
9
9
  end
10
10
 
11
11
  test "#index returns a list of commits" do
12
- commit = @stack.commits.last
12
+ commit = @stack.commits.reachable.last
13
13
 
14
14
  get :index, params: {stack_id: @stack.to_param}
15
15
  assert_response :ok
@@ -0,0 +1,59 @@
1
+ require 'test_helper'
2
+
3
+ module Shipit
4
+ module Api
5
+ class PullRequestsControllerTest < ActionController::TestCase
6
+ setup do
7
+ @stack = shipit_stacks(:shipit)
8
+ @pull_request = shipit_pull_requests(:shipit_pending)
9
+ authenticate!
10
+ end
11
+
12
+ test "#index returns a list of pull requests" do
13
+ pull_request = @stack.pull_requests.last
14
+
15
+ get :index, params: {stack_id: @stack.to_param}
16
+ assert_response :ok
17
+ assert_json '0.id', pull_request.id
18
+ end
19
+
20
+ test "#show returns a single pull requests" do
21
+ get :show, params: {stack_id: @stack.to_param, id: @pull_request.number.to_s}
22
+ assert_response :ok
23
+ assert_json 'id', @pull_request.id
24
+ end
25
+
26
+ test "#update responds with Accepted if the pull request was queued" do
27
+ assert_enqueued_with(job: RefreshPullRequestJob) do
28
+ put :update, params: {stack_id: @stack.to_param, id: '64'}
29
+ end
30
+ assert_response :accepted
31
+ end
32
+
33
+ test "#update responds with Accepted if the pull request was already queued" do
34
+ assert_enqueued_with(job: RefreshPullRequestJob) do
35
+ put :update, params: {stack_id: @stack.to_param, id: '65'}
36
+ end
37
+ assert_response :accepted
38
+ end
39
+
40
+ test "#update responds with method not allowed if the pull request was already merged" do
41
+ @pull_request.complete!
42
+ put :update, params: {stack_id: @stack.to_param, id: @pull_request.number.to_s}
43
+ assert_response :method_not_allowed
44
+ assert_json 'message', 'This pull request was already merged.'
45
+ end
46
+
47
+ test "#destroy cancels the merge if the pull request was waiting" do
48
+ delete :destroy, params: {stack_id: @stack.to_param, id: @pull_request.number.to_s}
49
+ assert_response :no_content
50
+ assert_predicate @pull_request.reload, :canceled?
51
+ end
52
+
53
+ test "#destroy silently fail if the pull request was unknown" do
54
+ delete :destroy, params: {stack_id: @stack.to_param, id: '83453489'}
55
+ assert_response :no_content
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,33 @@
1
+ require 'uri'
2
+ require 'test_helper'
3
+
4
+ module Shipit
5
+ class CCMenuUrlControllerTest < ActionController::TestCase
6
+ setup do
7
+ @stack = shipit_stacks(:shipit)
8
+ @user = shipit_users(:walrus)
9
+ session[:user_id] = @user.id
10
+ end
11
+
12
+ test ":fetch returns ok with json" do
13
+ get :fetch, params: {stack_id: @stack.to_param}
14
+ assert_response :ok
15
+ data = JSON.parse(response.body)
16
+ assert_includes data, 'ccmenu_url'
17
+ end
18
+
19
+ test ":fetch creates a read only api client" do
20
+ assert_difference 'ApiClient.count' do
21
+ get :fetch, params: {stack_id: @stack.to_param}
22
+ end
23
+ end
24
+
25
+ test ":fetch url includes api token on query string" do
26
+ get :fetch, params: {stack_id: @stack.to_param}
27
+ data = JSON.parse(response.body)
28
+ client = ApiClient.last
29
+ query = Rack::Utils.parse_nested_query(URI(data['ccmenu_url']).query)
30
+ assert_equal client.authentication_token, query['token']
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,31 @@
1
+ require 'test_helper'
2
+
3
+ module Shipit
4
+ class PullRequestsControllerTest < ActionController::TestCase
5
+ setup do
6
+ @stack = shipit_stacks(:shipit)
7
+ @pr = shipit_pull_requests(:shipit_pending)
8
+ session[:user_id] = shipit_users(:walrus).id
9
+ end
10
+
11
+ test "#index shows pending pull requests" do
12
+ get :index, params: {stack_id: @stack.to_param}
13
+ assert_response :success
14
+ assert_select '.pr-list .pr', @stack.pull_requests.pending.count
15
+ end
16
+
17
+ test "#add can enqueue a pull request" do
18
+ assert_difference -> { PullRequest.count }, +1 do
19
+ post :create, params: {stack_id: @stack.to_param, number_or_url: '#5'}
20
+ end
21
+ assert_redirected_to stack_pull_requests_path(@stack)
22
+ end
23
+
24
+ test "#destroy can cancel a pending pull request" do
25
+ assert_predicate @pr, :pending?
26
+ delete :destroy, params: {stack_id: @stack.to_param, id: @pr.id}
27
+ assert_redirected_to stack_pull_requests_path(@stack)
28
+ assert_predicate @pr.reload, :canceled?
29
+ end
30
+ end
31
+ end