shipit-engine 0.6.4 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +4 -2
- data/app/assets/javascripts/shipit/checklist.js.coffee +2 -2
- data/app/controllers/shipit/api/hooks_controller.rb +2 -2
- data/app/controllers/shipit/shipit_controller.rb +4 -3
- data/app/models/shipit/hook.rb +3 -2
- data/app/models/shipit/stack.rb +18 -2
- data/app/models/shipit/user.rb +2 -0
- data/app/serializers/shipit/hook_serializer.rb +9 -1
- data/app/serializers/shipit/stack_serializer.rb +1 -1
- data/app/views/shipit/deploys/_checklist.html.erb +1 -1
- data/app/views/shipit/deploys/_concurrent_deploy_warning.html.erb +4 -0
- data/app/views/shipit/deploys/new.html.erb +3 -5
- data/app/views/shipit/deploys/rollback.html.erb +3 -5
- data/config/routes.rb +29 -29
- data/db/migrate/20160122165559_rename_hooks_url_in_delivery_url.rb +5 -0
- data/lib/shipit.rb +3 -2
- data/lib/shipit/version.rb +1 -1
- data/test/controllers/api/hooks_controller_test.rb +19 -11
- data/test/controllers/stacks_controller_test.rb +7 -3
- data/test/dummy/config/secrets.example.yml +6 -2
- data/test/dummy/db/development.sqlite3 +0 -0
- data/test/dummy/db/schema.rb +2 -4
- data/test/dummy/db/test.sqlite3 +0 -0
- data/test/fixtures/shipit/hooks.yml +5 -5
- data/test/helpers/hooks_helper.rb +36 -0
- data/test/helpers/payloads_helper.rb +0 -1
- data/test/jobs/perform_task_job_test.rb +0 -1
- data/test/models/commits_test.rb +27 -16
- data/test/models/deploys_test.rb +12 -12
- data/test/models/hook_test.rb +5 -5
- data/test/models/stacks_test.rb +15 -7
- data/test/test_helper.rb +9 -5
- data/test/unit/shipit_test.rb +16 -0
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 13126d19eca4966f56856152cf632751bf1ba9d1
|
4
|
+
data.tar.gz: 665a8bce4eb15e193e55b0da971a5840b7888bf6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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 `
|
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
|
-
|
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
|
4
|
+
$('.trigger-deploy').toggleClass('disabled btn--disabled', !!$(':checkbox.required:not(:checked)').length)
|
5
5
|
|
6
|
-
$document.on('change', ':checkbox
|
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 :
|
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 :
|
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
|
-
|
36
|
-
|
37
|
-
|
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)
|
data/app/models/shipit/hook.rb
CHANGED
@@ -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 :
|
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:
|
71
|
+
url: delivery_url,
|
71
72
|
content_type: CONTENT_TYPES[content_type],
|
72
73
|
payload: serialize_payload(payload),
|
73
74
|
).schedule!
|
data/app/models/shipit/stack.rb
CHANGED
@@ -27,7 +27,10 @@ module Shipit
|
|
27
27
|
|
28
28
|
before_validation :update_defaults
|
29
29
|
before_destroy :clear_local_files
|
30
|
-
after_commit :
|
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
|
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
|
data/app/models/shipit/user.rb
CHANGED
@@ -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
|
data/lib/shipit.rb
CHANGED
@@ -103,8 +103,9 @@ module Shipit
|
|
103
103
|
secrets.host.presence
|
104
104
|
end
|
105
105
|
|
106
|
-
def
|
107
|
-
|
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
|
data/lib/shipit/version.rb
CHANGED
@@ -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.
|
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.
|
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 '
|
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,
|
51
|
+
post :create, delivery_url: 'https://example.com/hook', events: %w(deploy rollback)
|
48
52
|
end
|
49
|
-
|
50
|
-
assert_json '
|
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,
|
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,
|
67
|
+
post :create, delivery_url: '../etc/passwd', events: %w(deploy)
|
60
68
|
assert_response :unprocessable_entity
|
61
|
-
assert_json 'errors', '
|
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,
|
74
|
+
patch :update, id: hook.id, delivery_url: 'https://shipit.com/'
|
67
75
|
assert_response :ok
|
68
|
-
assert_json '
|
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.
|
58
|
-
|
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
|
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
|
-
#
|
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
|
-
#
|
28
|
+
# teams:
|
29
|
+
# -
|
30
|
+
# -
|
27
31
|
redis_url: "redis://127.0.0.1:6379/7"
|
Binary file
|
data/test/dummy/db/schema.rb
CHANGED
@@ -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:
|
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 "
|
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
|
|
data/test/dummy/db/test.sqlite3
CHANGED
Binary file
|
@@ -1,28 +1,28 @@
|
|
1
1
|
shipit_deploys:
|
2
2
|
stack: shipit
|
3
3
|
events: 'deploy,rollback'
|
4
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
data/test/models/commits_test.rb
CHANGED
@@ -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
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
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
|
-
|
328
|
-
|
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
|
-
|
335
|
-
|
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
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
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
|
data/test/models/deploys_test.rb
CHANGED
@@ -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.
|
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.
|
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.
|
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
|
data/test/models/hook_test.rb
CHANGED
@@ -8,15 +8,15 @@ module Shipit
|
|
8
8
|
end
|
9
9
|
|
10
10
|
test "#url must be valid" do
|
11
|
-
@hook.
|
11
|
+
@hook.delivery_url = 'file:/ad"fa/adfa'
|
12
12
|
refute @hook.valid?
|
13
|
-
assert_equal ['
|
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.
|
17
|
+
@hook.delivery_url = 'file:///etc/passwd'
|
18
18
|
refute @hook.valid?
|
19
|
-
assert_equal ['
|
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.
|
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
|
data/test/models/stacks_test.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
353
|
-
|
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(
|
10
|
-
ActiveRecord::Migrator.migrations_paths = [
|
11
|
-
|
12
|
-
|
13
|
-
|
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
|
data/test/unit/shipit_test.rb
CHANGED
@@ -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.
|
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-
|
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
|