shipit-engine 0.6.4 → 0.7.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 (35) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +4 -2
  3. data/app/assets/javascripts/shipit/checklist.js.coffee +2 -2
  4. data/app/controllers/shipit/api/hooks_controller.rb +2 -2
  5. data/app/controllers/shipit/shipit_controller.rb +4 -3
  6. data/app/models/shipit/hook.rb +3 -2
  7. data/app/models/shipit/stack.rb +18 -2
  8. data/app/models/shipit/user.rb +2 -0
  9. data/app/serializers/shipit/hook_serializer.rb +9 -1
  10. data/app/serializers/shipit/stack_serializer.rb +1 -1
  11. data/app/views/shipit/deploys/_checklist.html.erb +1 -1
  12. data/app/views/shipit/deploys/_concurrent_deploy_warning.html.erb +4 -0
  13. data/app/views/shipit/deploys/new.html.erb +3 -5
  14. data/app/views/shipit/deploys/rollback.html.erb +3 -5
  15. data/config/routes.rb +29 -29
  16. data/db/migrate/20160122165559_rename_hooks_url_in_delivery_url.rb +5 -0
  17. data/lib/shipit.rb +3 -2
  18. data/lib/shipit/version.rb +1 -1
  19. data/test/controllers/api/hooks_controller_test.rb +19 -11
  20. data/test/controllers/stacks_controller_test.rb +7 -3
  21. data/test/dummy/config/secrets.example.yml +6 -2
  22. data/test/dummy/db/development.sqlite3 +0 -0
  23. data/test/dummy/db/schema.rb +2 -4
  24. data/test/dummy/db/test.sqlite3 +0 -0
  25. data/test/fixtures/shipit/hooks.yml +5 -5
  26. data/test/helpers/hooks_helper.rb +36 -0
  27. data/test/helpers/payloads_helper.rb +0 -1
  28. data/test/jobs/perform_task_job_test.rb +0 -1
  29. data/test/models/commits_test.rb +27 -16
  30. data/test/models/deploys_test.rb +12 -12
  31. data/test/models/hook_test.rb +5 -5
  32. data/test/models/stacks_test.rb +15 -7
  33. data/test/test_helper.rb +9 -5
  34. data/test/unit/shipit_test.rb +16 -0
  35. metadata +5 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7e59f9e4da5a153b86f3a4e001457f0ca9fa43f9
4
- data.tar.gz: fb56ea8afef030852bb331ce12a8fb5db9a40234
3
+ metadata.gz: 13126d19eca4966f56856152cf632751bf1ba9d1
4
+ data.tar.gz: 665a8bce4eb15e193e55b0da971a5840b7888bf6
5
5
  SHA512:
6
- metadata.gz: 505e87e04f14fbfb8403dfd95a868a536d6666e8fd32fc88894cd51d3b720a7a37cff6de7bb36290438d6ecf8b7795abc0317b8594d070b8adf837cae50b2259
7
- data.tar.gz: 331f978493b326520897b4ebeb29eb23ce75e8224586dfc7a48dd643e56f8405ee825ca956d0f9a1796cf8f14e2ffac40c15b80501f97462ee784fc3d36d2d1e
6
+ metadata.gz: 87cf3290c48593691fec2c278607cc1783206af426ca3dbefcab269b639614d98e5e8632cd1bc4fa27842f70615886f9b7c3914191d99dfc8168d43ab61ffcae
7
+ data.tar.gz: 12077a22444887bb58eb55faed2b395e257d97f2a762fc64164ef216b61921c6606d8261de6f202192324b17e461e4b3c9f008d4278503c7631a41513a309ce2
data/README.md CHANGED
@@ -316,7 +316,7 @@ development:
316
316
 
317
317
  The value for `id` is your application's *Client ID*, and the value for `secret` is your application's *Client Secret* — both of these should appear on your application's GitHub page.
318
318
 
319
- The `team` is optional, and required only if you want to specify a team that has access to the stack in Shipit.
319
+ The `teams` key is optional, and required only if you want to specify some teams which have access to the stack in Shipit.
320
320
 
321
321
  For example:
322
322
 
@@ -325,7 +325,9 @@ development:
325
325
  github_oauth:
326
326
  id: (your application's Client ID)
327
327
  secret: (your application's Client Secret)
328
- team: Shipit/team
328
+ teams:
329
+ - Shipit/team
330
+ - Shipit/another_team
329
331
  ```
330
332
  <br>
331
333
 
@@ -1,9 +1,9 @@
1
1
  $document = $(document)
2
2
 
3
3
  toggleDeployButton = ->
4
- $('.trigger-deploy').toggleClass('disabled btn--disabled', !!$(':checkbox[name=checklist]:not(:checked)').length)
4
+ $('.trigger-deploy').toggleClass('disabled btn--disabled', !!$(':checkbox.required:not(:checked)').length)
5
5
 
6
- $document.on('change', ':checkbox[name=checklist]', toggleDeployButton)
6
+ $document.on('change', ':checkbox.required', toggleDeployButton)
7
7
 
8
8
  jQuery ($) ->
9
9
  toggleDeployButton()
@@ -13,7 +13,7 @@ module Shipit
13
13
  end
14
14
 
15
15
  params do
16
- requires :url, String
16
+ requires :delivery_url, String
17
17
  requires :events, Array[String]
18
18
  accepts :content_type, String
19
19
  end
@@ -22,7 +22,7 @@ module Shipit
22
22
  end
23
23
 
24
24
  params do
25
- accepts :url, String
25
+ accepts :delivery_url, String
26
26
  accepts :events, Array[String]
27
27
  accepts :content_type, String
28
28
  end
@@ -32,9 +32,10 @@ module Shipit
32
32
 
33
33
  def force_github_authentication
34
34
  if current_user.logged_in?
35
- team = Shipit.github_team
36
- if team && !current_user.in?(team.members)
37
- render text: "You must be a member of #{team.handle} to access this application.", status: :forbidden
35
+ teams = Shipit.github_teams
36
+ unless teams.empty? || current_user.teams.where(id: teams).exists?
37
+ team_list = teams.map(&:handle).to_sentence(two_words_connector: ' or ', last_word_connector: ', or ')
38
+ render text: "You must be a member of #{team_list} to access this application.", status: :forbidden
38
39
  end
39
40
  else
40
41
  redirect_to Shipit::Engine.routes.url_helpers.github_authentication_path(origin: request.original_url)
@@ -8,6 +8,7 @@ module Shipit
8
8
  }.freeze
9
9
 
10
10
  EVENTS = %w(
11
+ stack
11
12
  task
12
13
  deploy
13
14
  rollback
@@ -19,7 +20,7 @@ module Shipit
19
20
  belongs_to :stack, required: false
20
21
  has_many :deliveries
21
22
 
22
- validates :url, presence: true, url: {no_local: true, allow_blank: true}
23
+ validates :delivery_url, presence: true, url: {no_local: true, allow_blank: true}
23
24
  validates :content_type, presence: true, inclusion: {in: CONTENT_TYPES.keys}
24
25
  validates :events, presence: true, subset: {of: EVENTS}
25
26
 
@@ -67,7 +68,7 @@ module Shipit
67
68
  def deliver!(event, payload)
68
69
  deliveries.create!(
69
70
  event: event,
70
- url: url,
71
+ url: delivery_url,
71
72
  content_type: CONTENT_TYPES[content_type],
72
73
  payload: serialize_payload(payload),
73
74
  ).schedule!
@@ -27,7 +27,10 @@ module Shipit
27
27
 
28
28
  before_validation :update_defaults
29
29
  before_destroy :clear_local_files
30
- after_commit :emit_hooks
30
+ after_commit :emit_lock_hooks
31
+ after_commit :emit_added_hooks, on: :create
32
+ after_commit :emit_updated_hooks, on: :update
33
+ after_commit :emit_removed_hooks, on: :destroy
31
34
  after_commit :broadcast_update, on: :update
32
35
  after_commit :setup_hooks, :sync_github, on: :create
33
36
  after_touch :clear_cache
@@ -296,11 +299,24 @@ module Shipit
296
299
  self.branch = 'master' if branch.blank?
297
300
  end
298
301
 
299
- def emit_hooks
302
+ def emit_lock_hooks
300
303
  return unless previous_changes.include?('lock_reason')
301
304
  Hook.emit(:lock, self, locked: locked?, stack: self)
302
305
  end
303
306
 
307
+ def emit_added_hooks
308
+ Hook.emit(:stack, self, action: :added, stack: self)
309
+ end
310
+
311
+ def emit_updated_hooks
312
+ changed = !(previous_changes.keys - %w(updated_at)).empty?
313
+ Hook.emit(:stack, self, action: :updated, stack: self) if changed
314
+ end
315
+
316
+ def emit_removed_hooks
317
+ Hook.emit(:stack, self, action: :removed, stack: self)
318
+ end
319
+
304
320
  def ci_enabled_cache_key
305
321
  "stacks:#{id}:ci_enabled"
306
322
  end
@@ -2,6 +2,8 @@ module Shipit
2
2
  class User < ActiveRecord::Base
3
3
  DEFAULT_AVATAR = URI.parse('https://avatars.githubusercontent.com/u/583231?')
4
4
 
5
+ has_many :teams, through: :memberships
6
+ has_many :memberships
5
7
  has_many :authored_commits, class_name: :Commit, foreign_key: :author_id, inverse_of: :author
6
8
  has_many :commits, foreign_key: :committer_id, inverse_of: :committer
7
9
  has_many :tasks
@@ -3,7 +3,15 @@ module Shipit
3
3
  include ConditionalAttributes
4
4
 
5
5
  has_one :stack
6
- attributes :id, :url, :content_type, :events, :insecure_ssl, :created_at, :updated_at
6
+ attributes :id, :url, :delivery_url, :content_type, :events, :insecure_ssl, :created_at, :updated_at
7
+
8
+ def url
9
+ if object.scoped?
10
+ api_stack_hook_url(object.stack, object)
11
+ else
12
+ api_hook_url(object)
13
+ end
14
+ end
7
15
 
8
16
  def include_stack?
9
17
  object.scoped?
@@ -3,7 +3,7 @@ module Shipit
3
3
  include ConditionalAttributes
4
4
 
5
5
  has_one :lock_author
6
- attributes :id, :repo_owner, :repo_name, :environment, :html_url, :url, :tasks_url, :deploy_spec,
6
+ attributes :id, :repo_owner, :repo_name, :environment, :html_url, :url, :tasks_url, :deploy_url, :deploy_spec,
7
7
  :undeployed_commits_count, :is_locked, :lock_reason, :continuous_deployment, :created_at, :updated_at
8
8
 
9
9
  def url
@@ -6,7 +6,7 @@
6
6
  <ul class="deploy-checklist">
7
7
  <%- checklist.each_with_index do |check, index| -%>
8
8
  <li class="deploy-checklist__item">
9
- <%= check_box_tag :checklist, nil, false, class: 'deploy-checklist__item__checkbox', id: "checkbox_#{index}" %>
9
+ <%= check_box_tag :checklist, nil, false, class: 'deploy-checklist__item__checkbox required', id: "checkbox_#{index}" %>
10
10
  <label class="deploy-checklist__item__label" for="checkbox_<%= index %>">
11
11
  <%= sanitize(check, tags: %w(a strong), attributes: %w(href target)) %>
12
12
  </label>
@@ -2,5 +2,9 @@
2
2
  <h2><%= render_github_user(@stack.active_deploy.author) %> is already deploying!</h2>
3
3
  <ul>
4
4
  <li>Are you sure you want to deploy concurrently?</li>
5
+ <li>
6
+ <%= check_box_tag :force, true, false, class: 'required' %>
7
+ Yes I know what I'm doing.
8
+ </li>
5
9
  </ul>
6
10
  </section>
@@ -1,8 +1,6 @@
1
1
  <%= render partial: 'shipit/stacks/header', locals: { stack: @stack } %>
2
2
 
3
3
  <div class="wrapper">
4
- <%= render 'concurrent_deploy_warning' if @stack.deploying? %>
5
-
6
4
  <section>
7
5
  <header class="section-header">
8
6
  <h2>Commits included in this deploy (<%= link_to_github_deploy(@deploy) %>)</h2>
@@ -45,10 +43,10 @@
45
43
  <% end %>
46
44
  </section>
47
45
  <% end %>
46
+
47
+ <%= render 'concurrent_deploy_warning' if @stack.deploying? %>
48
+
48
49
  <section class="submit-section">
49
- <% if @stack.deploying? %>
50
- <%= hidden_field_tag :force, value: true %>
51
- <% end %>
52
50
  <%= f.hidden_field :until_commit_id %>
53
51
  <%= f.submit class: 'btn btn--primary btn--large trigger-deploy' %>
54
52
  </section>
@@ -9,8 +9,6 @@
9
9
  </ul>
10
10
  </section>
11
11
 
12
- <%= render 'concurrent_deploy_warning' if @stack.deploying? %>
13
-
14
12
  <section>
15
13
  <header class="section-header">
16
14
  <h2>Commits included in this rollback</h2>
@@ -41,10 +39,10 @@
41
39
  <% end %>
42
40
  </section>
43
41
  <% end %>
42
+
43
+ <%= render 'concurrent_deploy_warning' if @stack.deploying? %>
44
+
44
45
  <section class="submit-section">
45
- <% if @stack.deploying? %>
46
- <%= hidden_field_tag :force, value: true %>
47
- <% end %>
48
46
  <%= f.hidden_field :parent_id %>
49
47
  <%= f.submit 'Rollback', :class => ['btn', 'rollback', 'trigger-rollback'], data: {confirm: "Are you really sure it's safe?"} %>
50
48
  </section>
data/config/routes.rb CHANGED
@@ -5,16 +5,9 @@ Shipit::Engine.routes.draw do
5
5
 
6
6
  mount Pubsubstub::StreamAction.new, at: "/events", as: :events
7
7
 
8
+ # Robots
8
9
  get '/status/version' => 'status#version', as: :version
9
10
 
10
- scope '/github/auth/github', as: :github_authentication, controller: :github_authentication do
11
- get '/', action: :request
12
- post :callback
13
- get :callback
14
- get :logout
15
- end
16
-
17
- # Robots
18
11
  resources :stacks, only: %i(new create index) do
19
12
  resource :webhooks, only: [] do
20
13
  post :push, :state
@@ -28,7 +21,35 @@ Shipit::Engine.routes.draw do
28
21
  end
29
22
  end
30
23
 
24
+ # API
25
+ namespace :api do
26
+ root to: 'base#index'
27
+ resources :stacks, only: :index
28
+ scope '/stacks/*id', id: stack_id_format, as: :stack do
29
+ get '/' => 'stacks#show'
30
+ end
31
+
32
+ scope '/stacks/*stack_id', stack_id: stack_id_format, as: :stack do
33
+ resource :lock, only: %i(create update destroy)
34
+ resources :tasks, only: %i(index show) do
35
+ resource :output, only: :show
36
+ end
37
+ resources :deploys, only: %i(create)
38
+ post '/task/:task_name' => 'tasks#trigger', as: :trigger_task
39
+ resources :hooks, only: %i(index create show update destroy)
40
+ end
41
+
42
+ resources :hooks, only: %i(index create show update destroy)
43
+ end
44
+
31
45
  # Humans
46
+ scope '/github/auth/github', as: :github_authentication, controller: :github_authentication do
47
+ get '/', action: :request
48
+ post :callback
49
+ get :callback
50
+ get :logout
51
+ end
52
+
32
53
  scope '/*id', id: stack_id_format, as: :stack do
33
54
  get '/' => 'stacks#show'
34
55
  patch '/' => 'stacks#update'
@@ -64,25 +85,4 @@ Shipit::Engine.routes.draw do
64
85
  end
65
86
  end
66
87
  end
67
-
68
- # API
69
- namespace :api do
70
- root to: 'base#index'
71
- resources :stacks, only: :index
72
- scope '/stacks/*id', id: stack_id_format, as: :stack do
73
- get '/' => 'stacks#show'
74
- end
75
-
76
- scope '/stacks/*stack_id', stack_id: stack_id_format, as: :stack do
77
- resource :lock, only: %i(create update destroy)
78
- resources :tasks, only: %i(index show) do
79
- resource :output, only: :show
80
- end
81
- resources :deploys, only: %i(create)
82
- post '/task/:task_name' => 'tasks#trigger', as: :trigger_task
83
- resources :hooks, only: %i(index create show update destroy)
84
- end
85
-
86
- resources :hooks, only: %i(index create show update destroy)
87
- end
88
88
  end
@@ -0,0 +1,5 @@
1
+ class RenameHooksUrlInDeliveryUrl < ActiveRecord::Migration
2
+ def change
3
+ rename_column :hooks, :url, :delivery_url
4
+ end
5
+ end
data/lib/shipit.rb CHANGED
@@ -103,8 +103,9 @@ module Shipit
103
103
  secrets.host.presence
104
104
  end
105
105
 
106
- def github_team
107
- @github_team ||= github_oauth_credentials['team'] && Team.find_or_create_by_handle(github_oauth_credentials['team'])
106
+ def github_teams
107
+ teams = (Array(github_oauth_credentials['team']) + Array(github_oauth_credentials['teams'])).sort.uniq
108
+ @github_teams ||= teams.map { |t| Team.find_or_create_by_handle(t) }
108
109
  end
109
110
 
110
111
  def github_oauth_id
@@ -1,3 +1,3 @@
1
1
  module Shipit
2
- VERSION = '0.6.4'
2
+ VERSION = '0.7.0'
3
3
  end
@@ -8,13 +8,17 @@ module Shipit
8
8
  @stack = shipit_stacks(:shipit)
9
9
  end
10
10
 
11
+ test "the route has priority over stacks one" do
12
+ assert_recognizes({controller: 'shipit/api/hooks', action: 'show', id: '42'}, '/api/hooks/42')
13
+ end
14
+
11
15
  test "#index without a stack_id returns the list of global hooks" do
12
16
  hook = Hook.global.first
13
17
 
14
18
  get :index
15
19
  assert_response :ok
16
20
  assert_json '0.id', hook.id
17
- assert_json '0.url', hook.url
21
+ assert_json '0.delivery_url', hook.delivery_url
18
22
  assert_json '0.content_type', hook.content_type
19
23
  assert_no_json '0.stack'
20
24
  end
@@ -25,7 +29,7 @@ module Shipit
25
29
  get :index, stack_id: @stack.to_param
26
30
  assert_response :ok
27
31
  assert_json '0.id', hook.id
28
- assert_json '0.url', hook.url
32
+ assert_json '0.delivery_url', hook.delivery_url
29
33
  assert_json '0.content_type', hook.content_type
30
34
  assert_json '0.stack.id', @stack.id
31
35
  end
@@ -37,35 +41,39 @@ module Shipit
37
41
  assert_response :ok
38
42
 
39
43
  assert_json 'id', hook.id
40
- assert_json 'url', hook.url
44
+ assert_json 'delivery_url', hook.delivery_url
41
45
  assert_json 'content_type', hook.content_type
42
46
  assert_json 'stack.id', @stack.id
43
47
  end
44
48
 
45
49
  test "#create adds a new hook" do
46
50
  assert_difference -> { Hook.count }, 1 do
47
- post :create, url: 'https://example.com/hook', events: %w(deploy rollback)
51
+ post :create, delivery_url: 'https://example.com/hook', events: %w(deploy rollback)
48
52
  end
49
- assert_json 'url', 'https://example.com/hook'
50
- assert_json 'id', Hook.last.id
53
+ hook = Hook.last
54
+ assert_json 'delivery_url', 'https://example.com/hook'
55
+ assert_json 'url', "http://shipit.com/api/hooks/#{hook.id}"
56
+ assert_json 'id', hook.id
51
57
  end
52
58
 
53
59
  test "#create do not allow to set protected attributes" do
54
- post :create, url: 'https://example.com/hook', events: %w(deploy rollback), created_at: 2.months.ago.to_s(:db)
60
+ post :create, delivery_url: 'https://example.com/hook',
61
+ events: %w(deploy rollback),
62
+ created_at: 2.months.ago.to_s(:db)
55
63
  Hook.last.created_at > 2.seconds.ago
56
64
  end
57
65
 
58
66
  test "#create returns validation errors" do
59
- post :create, url: '../etc/passwd', events: %w(deploy)
67
+ post :create, delivery_url: '../etc/passwd', events: %w(deploy)
60
68
  assert_response :unprocessable_entity
61
- assert_json 'errors', 'url' => ['is not a valid URL']
69
+ assert_json 'errors', 'delivery_url' => ['is not a valid URL']
62
70
  end
63
71
 
64
72
  test "#update changes an existing hook" do
65
73
  hook = Hook.global.first
66
- patch :update, id: hook.id, url: 'https://shipit.com/'
74
+ patch :update, id: hook.id, delivery_url: 'https://shipit.com/'
67
75
  assert_response :ok
68
- assert_json 'url', 'https://shipit.com/'
76
+ assert_json 'delivery_url', 'https://shipit.com/'
69
77
  end
70
78
 
71
79
  test "#destroy removes an existing hook" do
@@ -54,11 +54,15 @@ module Shipit
54
54
  assert_redirected_to '/github/auth/github?origin=http%3A%2F%2Ftest.host%2F'
55
55
  end
56
56
 
57
- test "current_user must be a member of Shipit.github_team" do
58
- Shipit.stubs(:github_team).returns(shipit_teams(:cyclimse_cooks))
57
+ test "current_user must be a member of at least a Shipit.github_teams" do
58
+ session[:user_id] = shipit_users(:bob).id
59
+ Shipit.stubs(:github_teams).returns([shipit_teams(:cyclimse_cooks), shipit_teams(:shopify_developers)])
59
60
  get :index
60
61
  assert_response :forbidden
61
- assert_equal 'You must be a member of cyclimse/cooks to access this application.', response.body
62
+ assert_equal(
63
+ 'You must be a member of cyclimse/cooks or shopify/developers to access this application.',
64
+ response.body,
65
+ )
62
66
  end
63
67
 
64
68
  test "#show is success" do
@@ -3,7 +3,9 @@ development:
3
3
  github_oauth:
4
4
  # id:
5
5
  # secret:
6
- # team:
6
+ # teams:
7
+ # -
8
+ # -
7
9
  github_api:
8
10
  # access_token:
9
11
  # login:
@@ -23,5 +25,7 @@ test:
23
25
  github_oauth:
24
26
  id: 1d
25
27
  secret: s3cr37
26
- # team:
28
+ # teams:
29
+ # -
30
+ # -
27
31
  redis_url: "redis://127.0.0.1:6379/7"
Binary file
@@ -11,7 +11,7 @@
11
11
  #
12
12
  # It's strongly recommended that you check this file into your version control system.
13
13
 
14
- ActiveRecord::Schema.define(version: 20160104151833) do
14
+ ActiveRecord::Schema.define(version: 20160122165559) do
15
15
 
16
16
  create_table "api_clients", force: :cascade do |t|
17
17
  t.text "permissions", limit: 65535
@@ -76,7 +76,7 @@ ActiveRecord::Schema.define(version: 20160104151833) do
76
76
 
77
77
  create_table "hooks", force: :cascade do |t|
78
78
  t.integer "stack_id", limit: 4
79
- t.string "url", limit: 4096, null: false
79
+ t.string "delivery_url", limit: 4096, null: false
80
80
  t.string "content_type", limit: 4, default: "json", null: false
81
81
  t.string "secret", limit: 255
82
82
  t.string "events", limit: 255, default: "", null: false
@@ -161,8 +161,6 @@ ActiveRecord::Schema.define(version: 20160104151833) do
161
161
  add_index "tasks", ["rolled_up", "created_at", "status"], name: "index_tasks_on_rolled_up_and_created_at_and_status"
162
162
  add_index "tasks", ["since_commit_id"], name: "index_tasks_on_since_commit_id"
163
163
  add_index "tasks", ["stack_id"], name: "index_tasks_on_stack_id"
164
- add_index "tasks", ["type", "stack_id", "parent_id"], name: "index_tasks_by_stack_and_parent"
165
- add_index "tasks", ["type", "stack_id", "status"], name: "index_tasks_by_stack_and_status"
166
164
  add_index "tasks", ["until_commit_id"], name: "index_tasks_on_until_commit_id"
167
165
  add_index "tasks", ["user_id"], name: "index_tasks_on_user_id"
168
166
 
Binary file
@@ -1,28 +1,28 @@
1
1
  shipit_deploys:
2
2
  stack: shipit
3
3
  events: 'deploy,rollback'
4
- url: https://example.com/events/deploy
4
+ delivery_url: https://example.com/events/deploy
5
5
  content_type: json
6
6
 
7
7
  all_deploys:
8
8
  events: 'deploy,rollback'
9
- url: https://example.com/events/deploy
9
+ delivery_url: https://example.com/events/deploy
10
10
  content_type: form
11
11
 
12
12
  shipit_tasks:
13
13
  stack: shipit
14
14
  events: 'task'
15
- url: https://example.com/events/deploy
15
+ delivery_url: https://example.com/events/deploy
16
16
  content_type: json
17
17
 
18
18
  shipit_commit_status:
19
19
  stack: shipit
20
20
  events: 'commit_status'
21
- url: https://example.com/events/commit_status
21
+ delivery_url: https://example.com/events/commit_status
22
22
  content_type: json
23
23
 
24
24
  cyclimse_deploy_status:
25
25
  stack: cyclimse
26
26
  events: 'deploy_status'
27
- url: https://example.com/events/deploy_status
27
+ delivery_url: https://example.com/events/deploy_status
28
28
  content_type: json
@@ -0,0 +1,36 @@
1
+ module HooksHelper
2
+ def expect_hook(event, stack = nil, payload = nil)
3
+ spy_on_hook
4
+ yield
5
+ assert_received_with(Shipit::Hook, :emit) do |call|
6
+ if call.args.first == event && (stack.nil? || call.args.second == stack)
7
+ if payload.respond_to?(:call)
8
+ payload.call(call.args.third)
9
+ elsif payload
10
+ payload == call.args.third
11
+ else
12
+ true
13
+ end
14
+ end
15
+ end
16
+ end
17
+
18
+ def expect_no_hook(*args)
19
+ spy_on_hook
20
+ yield
21
+ spy = Spy::Subroutine.get(Shipit::Hook, :emit)
22
+ called = spy.calls.find do |call|
23
+ args.map.with_index.all? { |value, index| value == call.args[index] }
24
+ end
25
+ matcher = args.map(&:inspect).join(', ')
26
+ got = called && called.args.map(&:inspect).join(', ')
27
+ refute called, "Expected no hook matching: (#{matcher})\n got: (#{got})"
28
+ end
29
+
30
+ private
31
+
32
+ def spy_on_hook
33
+ Spy.on(Shipit::Hook, :emit).and_call_through
34
+ rescue Spy::AlreadyHookedError
35
+ end
36
+ end
@@ -4,4 +4,3 @@ module PayloadsHelper
4
4
  JSON.parse(file.read)
5
5
  end
6
6
  end
7
-
@@ -29,7 +29,6 @@ module Shipit
29
29
  DeployCommands.any_instance.expects(:perform).returns([])
30
30
  @job.stubs(:capture)
31
31
 
32
- Hook.expects(:emit).twice
33
32
  assert_enqueued_with(job: FetchDeployedRevisionJob, args: [@deploy.stack]) do
34
33
  @job.perform(@deploy)
35
34
  end
@@ -309,14 +309,14 @@ module Shipit
309
309
  assert_equal initial_state, commit.state
310
310
 
311
311
  expected_status_attributes = {state: new_state, description: initial_state, context: 'ci/travis'}
312
- if should_fire
313
- expect_hook_emit(commit, :deployable_status, expected_status_attributes)
314
- else
315
- Hook.expects(:emit).never
312
+ add_status = -> { commit.add_status(expected_status_attributes.merge(created_at: 1.day.ago.to_s(:db))) }
313
+ expect_hook_emit(commit, :commit_status, expected_status_attributes) do
314
+ if should_fire
315
+ expect_hook_emit(commit, :deployable_status, expected_status_attributes, &add_status)
316
+ else
317
+ expect_no_hook(:deployable_status, &add_status)
318
+ end
316
319
  end
317
- expect_hook_emit(commit, :commit_status, expected_status_attributes)
318
-
319
- commit.add_status(expected_status_attributes.merge(created_at: 1.day.ago.to_s(:db)))
320
320
  end
321
321
  end
322
322
  end
@@ -324,15 +324,24 @@ module Shipit
324
324
  test "#add_status does not fire webhooks for invisible statuses" do
325
325
  commit = shipit_commits(:second)
326
326
  assert commit.stack.hooks.where(events: ['commit_status']).size >= 1
327
- Hook.expects(:emit).never
328
- commit.add_status(state: 'failure', description: 'Sad', context: 'ci/hidden', created_at: 1.day.ago.to_s(:db))
327
+
328
+ expect_no_hook(:deployable_status) do
329
+ commit.add_status(state: 'failure', description: 'Sad', context: 'ci/hidden', created_at: 1.day.ago.to_s(:db))
330
+ end
329
331
  end
330
332
 
331
333
  test "#add_status does not fire webhooks for non-meaningful statuses" do
332
334
  commit = shipit_commits(:second)
333
335
  assert commit.stack.hooks.where(events: ['commit_status']).size >= 1
334
- Hook.expects(:emit).never
335
- commit.add_status(state: 'failure', description: 'Sad', context: 'ci/ok_to_fail', created_at: 1.day.ago.to_s(:db))
336
+
337
+ expect_no_hook(:deployable_status) do
338
+ commit.add_status(
339
+ state: 'failure',
340
+ description: 'Sad',
341
+ context: 'ci/ok_to_fail',
342
+ created_at: 1.day.ago.to_s(:db),
343
+ )
344
+ end
336
345
  end
337
346
 
338
347
  test "#visible_statuses forward the last_statuses to the stack" do
@@ -397,11 +406,13 @@ module Shipit
397
406
  end
398
407
  end
399
408
 
400
- def expect_hook_emit(commit, event, status_attributes)
401
- matchers = status_attributes.to_a.map { |pair| responds_with(pair.first, pair.second) }
402
- Hook.expects(:emit).with(event, commit.stack, has_entries(commit: commit, stack: commit.stack,
403
- event => all_of(*matchers),
404
- status: status_attributes[:state]))
409
+ def expect_hook_emit(commit, event, status_attributes, &block)
410
+ matches = lambda do |payload|
411
+ assert_equal commit, payload[:commit]
412
+ assert_equal commit.stack, payload[:stack]
413
+ assert_equal status_attributes[:state], payload[:status]
414
+ end
415
+ expect_hook(event, commit.stack, matches, &block)
405
416
  end
406
417
  end
407
418
  end
@@ -96,37 +96,41 @@ module Shipit
96
96
  test "transitioning to success causes an event to be broadcasted" do
97
97
  deploy = shipit_deploys(:shipit_pending)
98
98
 
99
- expect_hook(:deploy, deploy.stack, status: 'success', deploy: deploy, stack: deploy.stack)
100
99
  expect_event(deploy)
101
100
  deploy.status = 'running'
102
- deploy.complete!
101
+ expect_hook(:deploy, deploy.stack, status: 'success', deploy: deploy, stack: deploy.stack) do
102
+ deploy.complete!
103
+ end
103
104
  end
104
105
 
105
106
  test "transitioning to failed causes an event to be broadcasted" do
106
107
  deploy = shipit_deploys(:shipit_pending)
107
108
 
108
- expect_hook(:deploy, deploy.stack, status: 'failed', deploy: deploy, stack: deploy.stack)
109
109
  expect_event(deploy)
110
110
  deploy.status = 'running'
111
- deploy.failure!
111
+ expect_hook(:deploy, deploy.stack, status: 'failed', deploy: deploy, stack: deploy.stack) do
112
+ deploy.failure!
113
+ end
112
114
  end
113
115
 
114
116
  test "transitioning to error causes an event to be broadcasted" do
115
117
  deploy = shipit_deploys(:shipit_pending)
116
118
 
117
- expect_hook(:deploy, deploy.stack, status: 'error', deploy: deploy, stack: deploy.stack)
118
119
  expect_event(deploy)
119
120
  deploy.status = 'running'
120
- deploy.error!
121
+ expect_hook(:deploy, deploy.stack, status: 'error', deploy: deploy, stack: deploy.stack) do
122
+ deploy.error!
123
+ end
121
124
  end
122
125
 
123
126
  test "transitioning to running causes an event to be broadcasted" do
124
127
  deploy = shipit_deploys(:shipit_pending)
125
128
 
126
- expect_hook(:deploy, deploy.stack, status: 'running', deploy: deploy, stack: deploy.stack)
127
129
  expect_event(deploy)
128
130
  deploy.status = 'pending'
129
- deploy.run!
131
+ expect_hook(:deploy, deploy.stack, status: 'running', deploy: deploy, stack: deploy.stack) do
132
+ deploy.run!
133
+ end
130
134
  end
131
135
 
132
136
  test "creating a deploy causes an event to be broadcasted" do
@@ -386,9 +390,5 @@ module Shipit
386
390
  channel == "stack.#{deploy.stack.id}" && data['url'] == "/#{deploy.stack.to_param}"
387
391
  end
388
392
  end
389
-
390
- def expect_hook(event, stack, payload)
391
- Hook.expects(:emit).with(event, stack, payload)
392
- end
393
393
  end
394
394
  end
@@ -8,15 +8,15 @@ module Shipit
8
8
  end
9
9
 
10
10
  test "#url must be valid" do
11
- @hook.url = 'file:/ad"fa/adfa'
11
+ @hook.delivery_url = 'file:/ad"fa/adfa'
12
12
  refute @hook.valid?
13
- assert_equal ['Url is not a valid URL'], @hook.errors.full_messages
13
+ assert_equal ['Delivery url is not a valid URL'], @hook.errors.full_messages
14
14
  end
15
15
 
16
16
  test "#url must not be localhost" do
17
- @hook.url = 'file:///etc/passwd'
17
+ @hook.delivery_url = 'file:///etc/passwd'
18
18
  refute @hook.valid?
19
- assert_equal ['Url is not a valid URL'], @hook.errors.full_messages
19
+ assert_equal ['Delivery url is not a valid URL'], @hook.errors.full_messages
20
20
  end
21
21
 
22
22
  test "#events is accessible as an array" do
@@ -42,7 +42,7 @@ module Shipit
42
42
 
43
43
  delivery = Delivery.last
44
44
 
45
- assert_equal @hook.url, delivery.url
45
+ assert_equal @hook.delivery_url, delivery.url
46
46
  assert_equal 'application/x-www-form-urlencoded', delivery.content_type
47
47
  assert_equal 'foo=42', delivery.payload
48
48
  assert_equal 'scheduled', delivery.status
@@ -284,14 +284,16 @@ module Shipit
284
284
  end
285
285
 
286
286
  test "locking the stack triggers a webhook" do
287
- expect_hook(:lock, @stack, locked: true, stack: @stack)
288
- @stack.update(lock_reason: "Just for fun", lock_author: shipit_users(:walrus))
287
+ expect_hook(:lock, @stack, locked: true, stack: @stack) do
288
+ @stack.update(lock_reason: "Just for fun", lock_author: shipit_users(:walrus))
289
+ end
289
290
  end
290
291
 
291
292
  test "unlocking the stack triggers a webhook" do
292
293
  @stack.update(lock_reason: "Just for fun", lock_author: shipit_users(:walrus))
293
- expect_hook(:lock, @stack, locked: false, stack: @stack)
294
- @stack.update(lock_reason: nil)
294
+ expect_hook(:lock, @stack, locked: false, stack: @stack) do
295
+ @stack.update(lock_reason: nil)
296
+ end
295
297
  end
296
298
 
297
299
  test "the git cache lock prevent concurrent access to the git cache" do
@@ -347,10 +349,16 @@ module Shipit
347
349
  assert_equal [commit1, commit2], stack.filter_meaningful_statuses([soft_fail, commit1, commit2])
348
350
  end
349
351
 
350
- private
352
+ test "updating the stack emit a hook" do
353
+ expect_hook(:stack, @stack, action: :updated, stack: @stack) do
354
+ @stack.update(repo_name: 'foo')
355
+ end
356
+ end
351
357
 
352
- def expect_hook(event, stack, payload)
353
- Hook.expects(:emit).with(event, stack, payload)
358
+ test "updating the stack doesn't emit a hook if only `updated_at` is changed" do
359
+ expect_no_hook(:stack) do
360
+ @stack.update(updated_at: Time.zone.now)
361
+ end
354
362
  end
355
363
  end
356
364
  end
data/test/test_helper.rb CHANGED
@@ -6,11 +6,14 @@ SimpleCov.start 'rails'
6
6
  require 'fakeweb'
7
7
  FakeWeb.allow_net_connect = false
8
8
 
9
- require File.expand_path("../../test/dummy/config/environment.rb", __FILE__)
10
- ActiveRecord::Migrator.migrations_paths = [File.expand_path("../../test/dummy/db/migrate", __FILE__)]
11
- ActiveRecord::Migrator.migrations_paths << File.expand_path('../../db/migrate', __FILE__)
12
- require "rails/test_help"
13
- require "mocha/mini_test"
9
+ require File.expand_path('../../test/dummy/config/environment.rb', __FILE__)
10
+ ActiveRecord::Migrator.migrations_paths = [
11
+ File.expand_path('../../test/dummy/db/migrate', __FILE__),
12
+ File.expand_path('../../db/migrate', __FILE__),
13
+ ]
14
+ require 'rails/test_help'
15
+ require 'mocha/mini_test'
16
+ require 'spy/integration'
14
17
 
15
18
  # Load fixtures from the engine
16
19
  if ActiveSupport::TestCase.respond_to?(:fixture_path=)
@@ -34,6 +37,7 @@ class ActiveSupport::TestCase
34
37
  include JSONHelper
35
38
  include LinksHelper
36
39
  include ApiHelper
40
+ include HooksHelper
37
41
  include ActiveJob::TestHelper
38
42
 
39
43
  setup do
@@ -44,5 +44,21 @@ module Shipit
44
44
  refute Shipit.github_enterprise?
45
45
  assert_equal({}, Shipit.github_oauth_options)
46
46
  end
47
+
48
+ test ".github_teams returns an empty array if there's no team" do
49
+ assert_equal([], Shipit.github_teams)
50
+ end
51
+
52
+ test ".github_teams returns the team key as an array" do
53
+ Rails.application.secrets.stubs(:github_oauth).returns('team' => 'shopify/developers')
54
+ assert_equal(['shopify/developers'], Shipit.github_teams.map(&:handle))
55
+ end
56
+
57
+ test ".github_teams merges the teams and team keys in a single array" do
58
+ Rails.application.secrets.stubs(:github_oauth).returns(
59
+ 'team' => 'shopify/developers',
60
+ 'teams' => ['shopify/developers', 'cyclimse/cooks'])
61
+ assert_equal(['cyclimse/cooks', 'shopify/developers'], Shipit.github_teams.map(&:handle))
62
+ end
47
63
  end
48
64
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: shipit-engine
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.4
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jean Boussier
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-01-20 00:00:00.000000000 Z
11
+ date: 2016-02-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -531,6 +531,7 @@ files:
531
531
  - db/migrate/20151113151323_improve_indexes_on_tasks.rb
532
532
  - db/migrate/20160104151742_increase_tasks_type_size_back.rb
533
533
  - db/migrate/20160104151833_convert_sti_columns.rb
534
+ - db/migrate/20160122165559_rename_hooks_url_in_delivery_url.rb
534
535
  - db/schema.rb
535
536
  - lib/shipit-engine.rb
536
537
  - lib/shipit.rb
@@ -632,6 +633,7 @@ files:
632
633
  - test/fixtures/shipit/users.yml
633
634
  - test/helpers/api_helper.rb
634
635
  - test/helpers/fixture_aliases_helper.rb
636
+ - test/helpers/hooks_helper.rb
635
637
  - test/helpers/json_helper.rb
636
638
  - test/helpers/links_helper.rb
637
639
  - test/helpers/payloads_helper.rb
@@ -772,6 +774,7 @@ test_files:
772
774
  - test/fixtures/shipit/users.yml
773
775
  - test/helpers/api_helper.rb
774
776
  - test/helpers/fixture_aliases_helper.rb
777
+ - test/helpers/hooks_helper.rb
775
778
  - test/helpers/json_helper.rb
776
779
  - test/helpers/links_helper.rb
777
780
  - test/helpers/payloads_helper.rb