Commit 3c6daec4b1194f5a2c43fcc5b7e370cd5c8add1e
Exists in
master
and in
4 other branches
Merge branch 'sys_hooks' of dev.gitlabhq.com:gitlabhq
Showing
33 changed files
with
425 additions
and
133 deletions
Show diff stats
Gemfile
@@ -71,7 +71,6 @@ group :development, :test do | @@ -71,7 +71,6 @@ group :development, :test do | ||
71 | gem "awesome_print" | 71 | gem "awesome_print" |
72 | gem "database_cleaner" | 72 | gem "database_cleaner" |
73 | gem "launchy" | 73 | gem "launchy" |
74 | - gem "webmock" | ||
75 | end | 74 | end |
76 | 75 | ||
77 | group :test do | 76 | group :test do |
@@ -82,4 +81,5 @@ group :test do | @@ -82,4 +81,5 @@ group :test do | ||
82 | gem "shoulda-matchers" | 81 | gem "shoulda-matchers" |
83 | gem 'email_spec' | 82 | gem 'email_spec' |
84 | gem 'resque_spec' | 83 | gem 'resque_spec' |
84 | + gem "webmock" | ||
85 | end | 85 | end |
@@ -0,0 +1,44 @@ | @@ -0,0 +1,44 @@ | ||
1 | +class Admin::HooksController < ApplicationController | ||
2 | + layout "admin" | ||
3 | + before_filter :authenticate_user! | ||
4 | + before_filter :authenticate_admin! | ||
5 | + | ||
6 | + def index | ||
7 | + @hooks = SystemHook.all | ||
8 | + @hook = SystemHook.new | ||
9 | + end | ||
10 | + | ||
11 | + def create | ||
12 | + @hook = SystemHook.new(params[:hook]) | ||
13 | + | ||
14 | + if @hook.save | ||
15 | + redirect_to admin_hooks_path, notice: 'Hook was successfully created.' | ||
16 | + else | ||
17 | + @hooks = SystemHook.all | ||
18 | + render :index | ||
19 | + end | ||
20 | + end | ||
21 | + | ||
22 | + def destroy | ||
23 | + @hook = SystemHook.find(params[:id]) | ||
24 | + @hook.destroy | ||
25 | + | ||
26 | + redirect_to admin_hooks_path | ||
27 | + end | ||
28 | + | ||
29 | + | ||
30 | + def test | ||
31 | + @hook = SystemHook.find(params[:hook_id]) | ||
32 | + data = { | ||
33 | + event_name: "project_create", | ||
34 | + name: "Ruby", | ||
35 | + path: "ruby", | ||
36 | + project_id: 1, | ||
37 | + owner_name: "Someone", | ||
38 | + owner_email: "example@gitlabhq.com" | ||
39 | + } | ||
40 | + @hook.execute(data) | ||
41 | + | ||
42 | + redirect_to :back | ||
43 | + end | ||
44 | +end |
app/controllers/admin/mailer_controller.rb
@@ -1,45 +0,0 @@ | @@ -1,45 +0,0 @@ | ||
1 | -class Admin::MailerController < ApplicationController | ||
2 | - layout "admin" | ||
3 | - before_filter :authenticate_user! | ||
4 | - before_filter :authenticate_admin! | ||
5 | - | ||
6 | - def preview | ||
7 | - | ||
8 | - end | ||
9 | - | ||
10 | - def preview_note | ||
11 | - @note = Note.first | ||
12 | - @user = @note.author | ||
13 | - @project = @note.project | ||
14 | - case params[:type] | ||
15 | - when "Commit" then | ||
16 | - @commit = @project.commit | ||
17 | - render :file => 'notify/note_commit_email', :layout => 'notify' | ||
18 | - when "Issue" then | ||
19 | - @issue = Issue.first | ||
20 | - render :file => 'notify/note_issue_email', :layout => 'notify' | ||
21 | - else | ||
22 | - render :file => 'notify/note_wall_email', :layout => 'notify' | ||
23 | - end | ||
24 | - rescue | ||
25 | - render :text => "Preview not available" | ||
26 | - end | ||
27 | - | ||
28 | - def preview_user_new | ||
29 | - @user = User.first | ||
30 | - @password = "DHasJKDHAS!" | ||
31 | - | ||
32 | - render :file => 'notify/new_user_email', :layout => 'notify' | ||
33 | - rescue | ||
34 | - render :text => "Preview not available" | ||
35 | - end | ||
36 | - | ||
37 | - def preview_issue_new | ||
38 | - @issue = Issue.first | ||
39 | - @user = @issue.assignee | ||
40 | - @project = @issue.project | ||
41 | - render :file => 'notify/new_issue_email', :layout => 'notify' | ||
42 | - rescue | ||
43 | - render :text => "Preview not available" | ||
44 | - end | ||
45 | -end |
app/controllers/hooks_controller.rb
@@ -11,24 +11,24 @@ class HooksController < ApplicationController | @@ -11,24 +11,24 @@ class HooksController < ApplicationController | ||
11 | respond_to :html | 11 | respond_to :html |
12 | 12 | ||
13 | def index | 13 | def index |
14 | - @hooks = @project.web_hooks.all | ||
15 | - @hook = WebHook.new | 14 | + @hooks = @project.hooks.all |
15 | + @hook = ProjectHook.new | ||
16 | end | 16 | end |
17 | 17 | ||
18 | def create | 18 | def create |
19 | - @hook = @project.web_hooks.new(params[:hook]) | 19 | + @hook = @project.hooks.new(params[:hook]) |
20 | @hook.save | 20 | @hook.save |
21 | 21 | ||
22 | if @hook.valid? | 22 | if @hook.valid? |
23 | redirect_to project_hooks_path(@project) | 23 | redirect_to project_hooks_path(@project) |
24 | else | 24 | else |
25 | - @hooks = @project.web_hooks.all | 25 | + @hooks = @project.hooks.all |
26 | render :index | 26 | render :index |
27 | end | 27 | end |
28 | end | 28 | end |
29 | 29 | ||
30 | def test | 30 | def test |
31 | - @hook = @project.web_hooks.find(params[:id]) | 31 | + @hook = @project.hooks.find(params[:id]) |
32 | commits = @project.commits(@project.default_branch, nil, 3) | 32 | commits = @project.commits(@project.default_branch, nil, 3) |
33 | data = @project.post_receive_data(commits.last.id, commits.first.id, "refs/heads/#{@project.default_branch}", current_user) | 33 | data = @project.post_receive_data(commits.last.id, commits.first.id, "refs/heads/#{@project.default_branch}", current_user) |
34 | @hook.execute(data) | 34 | @hook.execute(data) |
@@ -37,7 +37,7 @@ class HooksController < ApplicationController | @@ -37,7 +37,7 @@ class HooksController < ApplicationController | ||
37 | end | 37 | end |
38 | 38 | ||
39 | def destroy | 39 | def destroy |
40 | - @hook = @project.web_hooks.find(params[:id]) | 40 | + @hook = @project.hooks.find(params[:id]) |
41 | @hook.destroy | 41 | @hook.destroy |
42 | 42 | ||
43 | redirect_to project_hooks_path(@project) | 43 | redirect_to project_hooks_path(@project) |
app/models/project.rb
@@ -19,7 +19,7 @@ class Project < ActiveRecord::Base | @@ -19,7 +19,7 @@ class Project < ActiveRecord::Base | ||
19 | has_many :notes, :dependent => :destroy | 19 | has_many :notes, :dependent => :destroy |
20 | has_many :snippets, :dependent => :destroy | 20 | has_many :snippets, :dependent => :destroy |
21 | has_many :deploy_keys, :dependent => :destroy, :foreign_key => "project_id", :class_name => "Key" | 21 | has_many :deploy_keys, :dependent => :destroy, :foreign_key => "project_id", :class_name => "Key" |
22 | - has_many :web_hooks, :dependent => :destroy | 22 | + has_many :hooks, :dependent => :destroy, :class_name => "ProjectHook" |
23 | has_many :wikis, :dependent => :destroy | 23 | has_many :wikis, :dependent => :destroy |
24 | has_many :protected_branches, :dependent => :destroy | 24 | has_many :protected_branches, :dependent => :destroy |
25 | 25 | ||
@@ -120,7 +120,7 @@ class Project < ActiveRecord::Base | @@ -120,7 +120,7 @@ class Project < ActiveRecord::Base | ||
120 | errors.add(:path, " like 'gitolite-admin' is not allowed") | 120 | errors.add(:path, " like 'gitolite-admin' is not allowed") |
121 | end | 121 | end |
122 | end | 122 | end |
123 | - | 123 | + |
124 | def self.access_options | 124 | def self.access_options |
125 | UsersProject.access_roles | 125 | UsersProject.access_roles |
126 | end | 126 | end |
app/models/user.rb
app/models/users_project.rb
@@ -68,7 +68,7 @@ class UsersProject < ActiveRecord::Base | @@ -68,7 +68,7 @@ class UsersProject < ActiveRecord::Base | ||
68 | end | 68 | end |
69 | 69 | ||
70 | def repo_access_human | 70 | def repo_access_human |
71 | - "" | 71 | + self.class.access_roles.invert[self.project_access] |
72 | end | 72 | end |
73 | end | 73 | end |
74 | # == Schema Information | 74 | # == Schema Information |
app/models/web_hook.rb
@@ -4,8 +4,6 @@ class WebHook < ActiveRecord::Base | @@ -4,8 +4,6 @@ class WebHook < ActiveRecord::Base | ||
4 | # HTTParty timeout | 4 | # HTTParty timeout |
5 | default_timeout 10 | 5 | default_timeout 10 |
6 | 6 | ||
7 | - belongs_to :project | ||
8 | - | ||
9 | validates :url, | 7 | validates :url, |
10 | presence: true, | 8 | presence: true, |
11 | format: { | 9 | format: { |
@@ -14,9 +12,8 @@ class WebHook < ActiveRecord::Base | @@ -14,9 +12,8 @@ class WebHook < ActiveRecord::Base | ||
14 | 12 | ||
15 | def execute(data) | 13 | def execute(data) |
16 | WebHook.post(url, body: data.to_json, headers: { "Content-Type" => "application/json" }) | 14 | WebHook.post(url, body: data.to_json, headers: { "Content-Type" => "application/json" }) |
17 | - rescue | ||
18 | - # There was a problem calling this web hook, let's forget about it. | ||
19 | end | 15 | end |
16 | + | ||
20 | end | 17 | end |
21 | # == Schema Information | 18 | # == Schema Information |
22 | # | 19 | # |
@@ -0,0 +1,67 @@ | @@ -0,0 +1,67 @@ | ||
1 | +class SystemHookObserver < ActiveRecord::Observer | ||
2 | + observe :user, :project, :users_project | ||
3 | + | ||
4 | + def after_create(model) | ||
5 | + if model.kind_of? Project | ||
6 | + SystemHook.all_hooks_fire({ | ||
7 | + event_name: "project_create", | ||
8 | + name: model.name, | ||
9 | + path: model.path, | ||
10 | + project_id: model.id, | ||
11 | + owner_name: model.owner.name, | ||
12 | + owner_email: model.owner.email, | ||
13 | + created_at: model.created_at | ||
14 | + }) | ||
15 | + elsif model.kind_of? User | ||
16 | + SystemHook.all_hooks_fire({ | ||
17 | + event_name: "user_create", | ||
18 | + name: model.name, | ||
19 | + email: model.email, | ||
20 | + created_at: model.created_at | ||
21 | + }) | ||
22 | + | ||
23 | + elsif model.kind_of? UsersProject | ||
24 | + SystemHook.all_hooks_fire({ | ||
25 | + event_name: "user_add_to_team", | ||
26 | + project_name: model.project.name, | ||
27 | + project_path: model.project.path, | ||
28 | + project_id: model.project_id, | ||
29 | + user_name: model.user.name, | ||
30 | + user_email: model.user.email, | ||
31 | + project_access: model.repo_access_human, | ||
32 | + created_at: model.created_at | ||
33 | + }) | ||
34 | + | ||
35 | + end | ||
36 | + end | ||
37 | + | ||
38 | + def after_destroy(model) | ||
39 | + if model.kind_of? Project | ||
40 | + SystemHook.all_hooks_fire({ | ||
41 | + event_name: "project_destroy", | ||
42 | + name: model.name, | ||
43 | + path: model.path, | ||
44 | + project_id: model.id, | ||
45 | + owner_name: model.owner.name, | ||
46 | + owner_email: model.owner.email, | ||
47 | + }) | ||
48 | + elsif model.kind_of? User | ||
49 | + SystemHook.all_hooks_fire({ | ||
50 | + event_name: "user_destroy", | ||
51 | + name: model.name, | ||
52 | + email: model.email | ||
53 | + }) | ||
54 | + | ||
55 | + elsif model.kind_of? UsersProject | ||
56 | + SystemHook.all_hooks_fire({ | ||
57 | + event_name: "user_remove_from_team", | ||
58 | + project_name: model.project.name, | ||
59 | + project_path: model.project.path, | ||
60 | + project_id: model.project_id, | ||
61 | + user_name: model.user.name, | ||
62 | + user_email: model.user.email, | ||
63 | + project_access: model.repo_access_human | ||
64 | + }) | ||
65 | + end | ||
66 | + end | ||
67 | +end |
app/roles/git_push.rb
@@ -27,7 +27,7 @@ module GitPush | @@ -27,7 +27,7 @@ module GitPush | ||
27 | true | 27 | true |
28 | end | 28 | end |
29 | 29 | ||
30 | - def execute_web_hooks(oldrev, newrev, ref, user) | 30 | + def execute_hooks(oldrev, newrev, ref, user) |
31 | ref_parts = ref.split('/') | 31 | ref_parts = ref.split('/') |
32 | 32 | ||
33 | # Return if this is not a push to a branch (e.g. new commits) | 33 | # Return if this is not a push to a branch (e.g. new commits) |
@@ -35,7 +35,7 @@ module GitPush | @@ -35,7 +35,7 @@ module GitPush | ||
35 | 35 | ||
36 | data = post_receive_data(oldrev, newrev, ref, user) | 36 | data = post_receive_data(oldrev, newrev, ref, user) |
37 | 37 | ||
38 | - web_hooks.each { |web_hook| web_hook.execute(data) } | 38 | + hooks.each { |hook| hook.execute(data) } |
39 | end | 39 | end |
40 | 40 | ||
41 | def post_receive_data(oldrev, newrev, ref, user) | 41 | def post_receive_data(oldrev, newrev, ref, user) |
@@ -97,7 +97,7 @@ module GitPush | @@ -97,7 +97,7 @@ module GitPush | ||
97 | self.update_merge_requests(oldrev, newrev, ref, user) | 97 | self.update_merge_requests(oldrev, newrev, ref, user) |
98 | 98 | ||
99 | # Execute web hooks | 99 | # Execute web hooks |
100 | - self.execute_web_hooks(oldrev, newrev, ref, user) | 100 | + self.execute_hooks(oldrev, newrev, ref, user) |
101 | 101 | ||
102 | # Create satellite | 102 | # Create satellite |
103 | self.satellite.create unless self.satellite.exists? | 103 | self.satellite.create unless self.satellite.exists? |
@@ -0,0 +1,45 @@ | @@ -0,0 +1,45 @@ | ||
1 | +<% data_ex_str = <<eos | ||
2 | +{ | ||
3 | + :before => "95790bf891e76fee5e1747ab589903a6a1f80f22", | ||
4 | + :after => "da1560886d4f094c3e6c9ef40349f7d38b5d27d7", | ||
5 | + :ref => "refs/heads/master", | ||
6 | + :user_id => 4, | ||
7 | + :user_name => "John Smith", | ||
8 | + :repository => { | ||
9 | + :name => "Diaspora", | ||
10 | + :url => "localhost/diaspora", | ||
11 | + :description => "", | ||
12 | + :homepage => "localhost/diaspora", | ||
13 | + :private => true | ||
14 | + }, | ||
15 | + :commits => [ | ||
16 | + [0] { | ||
17 | + :id => "450d0de7532f8b663b9c5cce183b...", | ||
18 | + :message => "Update Catalan translation to e38cb41.", | ||
19 | + :timestamp => "2011-12-12T14:27:31+02:00", | ||
20 | + :url => "http://localhost/diaspora/commits/450d0de7532f...", | ||
21 | + :author => { | ||
22 | + :name => "Jordi Mallach", | ||
23 | + :email => "jordi@softcatala.org" | ||
24 | + } | ||
25 | + }, | ||
26 | + | ||
27 | + .... | ||
28 | + | ||
29 | + [3] { | ||
30 | + :id => "da1560886d4f094c3e6c9ef40349...", | ||
31 | + :message => "fixed readme", | ||
32 | + :timestamp => "2012-01-03T23:36:29+02:00", | ||
33 | + :url => "http://localhost/diaspora/commits/da1560886d...", | ||
34 | + :author => { | ||
35 | + :name => "gitlab dev user", | ||
36 | + :email => "gitlabdev@dv6700.(none)" | ||
37 | + } | ||
38 | + } | ||
39 | + ], | ||
40 | + total_commits_count => 3 | ||
41 | +} | ||
42 | +eos | ||
43 | +%> | ||
44 | +<% js_lexer = Pygments::Lexer[:js] %> | ||
45 | +<%= raw js_lexer.highlight(data_ex_str) %> |
@@ -0,0 +1,39 @@ | @@ -0,0 +1,39 @@ | ||
1 | +.alert.alert-info | ||
2 | + %span | ||
3 | + Post receive hooks for binding events. | ||
4 | + %br | ||
5 | + Read more about system hooks | ||
6 | + %strong #{link_to "here", help_system_hooks_path, :class => "vlink"} | ||
7 | + | ||
8 | += form_for @hook, :as => :hook, :url => admin_hooks_path do |f| | ||
9 | + -if @hook.errors.any? | ||
10 | + .alert-message.block-message.error | ||
11 | + - @hook.errors.full_messages.each do |msg| | ||
12 | + %p= msg | ||
13 | + .clearfix | ||
14 | + = f.label :url, "URL:" | ||
15 | + .input | ||
16 | + = f.text_field :url, :class => "text_field xxlarge" | ||
17 | + | ||
18 | + = f.submit "Add System Hook", :class => "btn primary" | ||
19 | +%hr | ||
20 | + | ||
21 | +-if @hooks.any? | ||
22 | + %h3 | ||
23 | + Hooks | ||
24 | + %small (#{@hooks.count}) | ||
25 | + %br | ||
26 | + %table.admin-table | ||
27 | + %tr | ||
28 | + %th URL | ||
29 | + %th Method | ||
30 | + %th | ||
31 | + - @hooks.each do |hook| | ||
32 | + %tr | ||
33 | + %td | ||
34 | + = link_to admin_hook_path(hook) do | ||
35 | + %strong= hook.url | ||
36 | + = link_to 'Test Hook', admin_hook_test_path(hook), :class => "btn small right" | ||
37 | + %td POST | ||
38 | + %td | ||
39 | + = link_to 'Remove', admin_hook_path(hook), :confirm => 'Are you sure?', :method => :delete, :class => "danger btn small right" |
app/views/admin/mailer/preview.html.haml
@@ -1,28 +0,0 @@ | @@ -1,28 +0,0 @@ | ||
1 | -%p This is page with preview for all system emails that are sent to user | ||
2 | -%p Email previews built based on existing Project/Commit/Issue base - so some preview maybe unavailable unless object appear in system | ||
3 | - | ||
4 | -#accordion | ||
5 | - %h3 | ||
6 | - %a New user | ||
7 | - %div | ||
8 | - %iframe{ :src=> admin_mailer_preview_user_new_path, :width=>"100%", :height=>"350"} | ||
9 | - %h3 | ||
10 | - %a New issue | ||
11 | - %div | ||
12 | - %iframe{ :src=> admin_mailer_preview_issue_new_path, :width=>"100%", :height=>"350"} | ||
13 | - %h3 | ||
14 | - %a Commit note | ||
15 | - %div | ||
16 | - %iframe{ :src=> admin_mailer_preview_note_path(:type => "Commit"), :width=>"100%", :height=>"350"} | ||
17 | - %h3 | ||
18 | - %a Issue note | ||
19 | - %div | ||
20 | - %iframe{ :src=> admin_mailer_preview_note_path(:type => "Issue"), :width=>"100%", :height=>"350"} | ||
21 | - %h3 | ||
22 | - %a Wall note | ||
23 | - %div | ||
24 | - %iframe{ :src=> admin_mailer_preview_note_path(:type => "Wall"), :width=>"100%", :height=>"350"} | ||
25 | - | ||
26 | -:javascript | ||
27 | - $(function() { | ||
28 | - $("#accordion").accordion(); }); |
@@ -0,0 +1,13 @@ | @@ -0,0 +1,13 @@ | ||
1 | +%h3 System hooks | ||
2 | +.back_link | ||
3 | + = link_to :back do | ||
4 | + ← back | ||
5 | +%hr | ||
6 | + | ||
7 | +%p.slead | ||
8 | + Your Gitlab instance can perform HTTP POST request on next event: create_project, delete_project, create_user, delete_user, change_team_member. | ||
9 | + %br | ||
10 | + System Hooks can be used for logging or change information in LDAP server. | ||
11 | + %br | ||
12 | +%h5 Hooks request example: | ||
13 | += render "admin/hooks/data_ex" |
app/views/layouts/admin.html.haml
@@ -15,7 +15,7 @@ | @@ -15,7 +15,7 @@ | ||
15 | %li{:class => tab_class(:admin_logs)} | 15 | %li{:class => tab_class(:admin_logs)} |
16 | = link_to "Logs", admin_logs_path | 16 | = link_to "Logs", admin_logs_path |
17 | %li{:class => tab_class(:admin_emails)} | 17 | %li{:class => tab_class(:admin_emails)} |
18 | - = link_to "Emails", admin_emails_path | 18 | + = link_to "Hooks", admin_hooks_path |
19 | %li{:class => tab_class(:admin_resque)} | 19 | %li{:class => tab_class(:admin_resque)} |
20 | = link_to "Resque", admin_resque_path | 20 | = link_to "Resque", admin_resque_path |
21 | 21 |
config/application.rb
@@ -23,7 +23,7 @@ module Gitlab | @@ -23,7 +23,7 @@ module Gitlab | ||
23 | # config.plugins = [ :exception_notification, :ssl_requirement, :all ] | 23 | # config.plugins = [ :exception_notification, :ssl_requirement, :all ] |
24 | 24 | ||
25 | # Activate observers that should always be running. | 25 | # Activate observers that should always be running. |
26 | - config.active_record.observers = :mailer_observer, :activity_observer, :project_observer, :key_observer, :issue_observer, :user_observer | 26 | + config.active_record.observers = :mailer_observer, :activity_observer, :project_observer, :key_observer, :issue_observer, :user_observer, :system_hook_observer |
27 | 27 | ||
28 | # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. | 28 | # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. |
29 | # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. | 29 | # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. |
config/routes.rb
@@ -28,6 +28,7 @@ Gitlab::Application.routes.draw do | @@ -28,6 +28,7 @@ Gitlab::Application.routes.draw do | ||
28 | get 'help/workflow' => 'help#workflow' | 28 | get 'help/workflow' => 'help#workflow' |
29 | get 'help/api' => 'help#api' | 29 | get 'help/api' => 'help#api' |
30 | get 'help/web_hooks' => 'help#web_hooks' | 30 | get 'help/web_hooks' => 'help#web_hooks' |
31 | + get 'help/system_hooks' => 'help#system_hooks' | ||
31 | 32 | ||
32 | # | 33 | # |
33 | # Admin Area | 34 | # Admin Area |
@@ -47,11 +48,13 @@ Gitlab::Application.routes.draw do | @@ -47,11 +48,13 @@ Gitlab::Application.routes.draw do | ||
47 | end | 48 | end |
48 | end | 49 | end |
49 | resources :team_members, :only => [:edit, :update, :destroy] | 50 | resources :team_members, :only => [:edit, :update, :destroy] |
50 | - get 'emails', :to => 'mailer#preview' | ||
51 | get 'mailer/preview_note' | 51 | get 'mailer/preview_note' |
52 | get 'mailer/preview_user_new' | 52 | get 'mailer/preview_user_new' |
53 | get 'mailer/preview_issue_new' | 53 | get 'mailer/preview_issue_new' |
54 | 54 | ||
55 | + resources :hooks, :only => [:index, :create, :destroy] do | ||
56 | + get :test | ||
57 | + end | ||
55 | resource :logs | 58 | resource :logs |
56 | resource :resque, :controller => 'resque' | 59 | resource :resque, :controller => 'resque' |
57 | root :to => "dashboard#index" | 60 | root :to => "dashboard#index" |
db/schema.rb
@@ -11,7 +11,7 @@ | @@ -11,7 +11,7 @@ | ||
11 | # | 11 | # |
12 | # It's strongly recommended to check this file into your version control system. | 12 | # It's strongly recommended to check this file into your version control system. |
13 | 13 | ||
14 | -ActiveRecord::Schema.define(:version => 20120706065612) do | 14 | +ActiveRecord::Schema.define(:version => 20120712080407) do |
15 | 15 | ||
16 | create_table "events", :force => true do |t| | 16 | create_table "events", :force => true do |t| |
17 | t.string "target_type" | 17 | t.string "target_type" |
@@ -187,8 +187,9 @@ ActiveRecord::Schema.define(:version => 20120706065612) do | @@ -187,8 +187,9 @@ ActiveRecord::Schema.define(:version => 20120706065612) do | ||
187 | create_table "web_hooks", :force => true do |t| | 187 | create_table "web_hooks", :force => true do |t| |
188 | t.string "url" | 188 | t.string "url" |
189 | t.integer "project_id" | 189 | t.integer "project_id" |
190 | - t.datetime "created_at", :null => false | ||
191 | - t.datetime "updated_at", :null => false | 190 | + t.datetime "created_at", :null => false |
191 | + t.datetime "updated_at", :null => false | ||
192 | + t.string "type", :default => "ProjectHook" | ||
192 | end | 193 | end |
193 | 194 | ||
194 | create_table "wikis", :force => true do |t| | 195 | create_table "wikis", :force => true do |t| |
resque.sh
1 | mkdir -p tmp/pids | 1 | mkdir -p tmp/pids |
2 | -bundle exec rake environment resque:work QUEUE=post_receive,mailer RAILS_ENV=production PIDFILE=tmp/pids/resque_worker.pid BACKGROUND=yes | 2 | +bundle exec rake environment resque:work QUEUE=post_receive,mailer,system_hook RAILS_ENV=production PIDFILE=tmp/pids/resque_worker.pid BACKGROUND=yes |
resque_dev.sh
spec/factories.rb
@@ -7,6 +7,12 @@ Factory.add(:project, Project) do |obj| | @@ -7,6 +7,12 @@ Factory.add(:project, Project) do |obj| | ||
7 | obj.code = 'LGT' | 7 | obj.code = 'LGT' |
8 | end | 8 | end |
9 | 9 | ||
10 | +Factory.add(:project_without_owner, Project) do |obj| | ||
11 | + obj.name = Faker::Internet.user_name | ||
12 | + obj.path = 'gitlabhq' | ||
13 | + obj.code = 'LGT' | ||
14 | +end | ||
15 | + | ||
10 | Factory.add(:public_project, Project) do |obj| | 16 | Factory.add(:public_project, Project) do |obj| |
11 | obj.name = Faker::Internet.user_name | 17 | obj.name = Faker::Internet.user_name |
12 | obj.path = 'gitlabhq' | 18 | obj.path = 'gitlabhq' |
@@ -60,7 +66,11 @@ Factory.add(:key, Key) do |obj| | @@ -60,7 +66,11 @@ Factory.add(:key, Key) do |obj| | ||
60 | obj.key = File.read(File.join(Rails.root, "db", "pkey.example")) | 66 | obj.key = File.read(File.join(Rails.root, "db", "pkey.example")) |
61 | end | 67 | end |
62 | 68 | ||
63 | -Factory.add(:web_hook, WebHook) do |obj| | 69 | +Factory.add(:project_hook, ProjectHook) do |obj| |
70 | + obj.url = Faker::Internet.uri("http") | ||
71 | +end | ||
72 | + | ||
73 | +Factory.add(:system_hook, SystemHook) do |obj| | ||
64 | obj.url = Faker::Internet.uri("http") | 74 | obj.url = Faker::Internet.uri("http") |
65 | end | 75 | end |
66 | 76 |
spec/models/project_hooks_spec.rb
@@ -21,44 +21,44 @@ describe Project, "Hooks" do | @@ -21,44 +21,44 @@ describe Project, "Hooks" do | ||
21 | end | 21 | end |
22 | end | 22 | end |
23 | 23 | ||
24 | - describe "Web hooks" do | 24 | + describe "Project hooks" do |
25 | context "with no web hooks" do | 25 | context "with no web hooks" do |
26 | it "raises no errors" do | 26 | it "raises no errors" do |
27 | lambda { | 27 | lambda { |
28 | - project.execute_web_hooks('oldrev', 'newrev', 'ref', @user) | 28 | + project.execute_hooks('oldrev', 'newrev', 'ref', @user) |
29 | }.should_not raise_error | 29 | }.should_not raise_error |
30 | end | 30 | end |
31 | end | 31 | end |
32 | 32 | ||
33 | context "with web hooks" do | 33 | context "with web hooks" do |
34 | before do | 34 | before do |
35 | - @webhook = Factory(:web_hook) | ||
36 | - @webhook_2 = Factory(:web_hook) | ||
37 | - project.web_hooks << [@webhook, @webhook_2] | 35 | + @project_hook = Factory(:project_hook) |
36 | + @project_hook_2 = Factory(:project_hook) | ||
37 | + project.hooks << [@project_hook, @project_hook_2] | ||
38 | end | 38 | end |
39 | 39 | ||
40 | it "executes multiple web hook" do | 40 | it "executes multiple web hook" do |
41 | - @webhook.should_receive(:execute).once | ||
42 | - @webhook_2.should_receive(:execute).once | 41 | + @project_hook.should_receive(:execute).once |
42 | + @project_hook_2.should_receive(:execute).once | ||
43 | 43 | ||
44 | - project.execute_web_hooks('oldrev', 'newrev', 'refs/heads/master', @user) | 44 | + project.execute_hooks('oldrev', 'newrev', 'refs/heads/master', @user) |
45 | end | 45 | end |
46 | end | 46 | end |
47 | 47 | ||
48 | context "does not execute web hooks" do | 48 | context "does not execute web hooks" do |
49 | before do | 49 | before do |
50 | - @webhook = Factory(:web_hook) | ||
51 | - project.web_hooks << [@webhook] | 50 | + @project_hook = Factory(:project_hook) |
51 | + project.hooks << [@project_hook] | ||
52 | end | 52 | end |
53 | 53 | ||
54 | it "when pushing a branch for the first time" do | 54 | it "when pushing a branch for the first time" do |
55 | - @webhook.should_not_receive(:execute) | ||
56 | - project.execute_web_hooks('00000000000000000000000000000000', 'newrev', 'refs/heads/master', @user) | 55 | + @project_hook.should_not_receive(:execute) |
56 | + project.execute_hooks('00000000000000000000000000000000', 'newrev', 'refs/heads/master', @user) | ||
57 | end | 57 | end |
58 | 58 | ||
59 | it "when pushing tags" do | 59 | it "when pushing tags" do |
60 | - @webhook.should_not_receive(:execute) | ||
61 | - project.execute_web_hooks('oldrev', 'newrev', 'refs/tags/v1.0.0', @user) | 60 | + @project_hook.should_not_receive(:execute) |
61 | + project.execute_hooks('oldrev', 'newrev', 'refs/tags/v1.0.0', @user) | ||
62 | end | 62 | end |
63 | end | 63 | end |
64 | 64 |
spec/models/project_spec.rb
@@ -11,7 +11,7 @@ describe Project do | @@ -11,7 +11,7 @@ describe Project do | ||
11 | it { should have_many(:issues).dependent(:destroy) } | 11 | it { should have_many(:issues).dependent(:destroy) } |
12 | it { should have_many(:notes).dependent(:destroy) } | 12 | it { should have_many(:notes).dependent(:destroy) } |
13 | it { should have_many(:snippets).dependent(:destroy) } | 13 | it { should have_many(:snippets).dependent(:destroy) } |
14 | - it { should have_many(:web_hooks).dependent(:destroy) } | 14 | + it { should have_many(:hooks).dependent(:destroy) } |
15 | it { should have_many(:deploy_keys).dependent(:destroy) } | 15 | it { should have_many(:deploy_keys).dependent(:destroy) } |
16 | end | 16 | end |
17 | 17 |
@@ -0,0 +1,63 @@ | @@ -0,0 +1,63 @@ | ||
1 | +require "spec_helper" | ||
2 | + | ||
3 | +describe SystemHook do | ||
4 | + describe "execute" do | ||
5 | + before(:each) { ActiveRecord::Base.observers.enable(:all) } | ||
6 | + | ||
7 | + before(:each) do | ||
8 | + @system_hook = Factory :system_hook | ||
9 | + WebMock.stub_request(:post, @system_hook.url) | ||
10 | + end | ||
11 | + | ||
12 | + it "project_create hook" do | ||
13 | + user = Factory :user | ||
14 | + with_resque do | ||
15 | + project = Factory :project_without_owner, :owner => user | ||
16 | + end | ||
17 | + WebMock.should have_requested(:post, @system_hook.url).with(body: /project_create/).once | ||
18 | + end | ||
19 | + | ||
20 | + it "project_destroy hook" do | ||
21 | + project = Factory :project | ||
22 | + with_resque do | ||
23 | + project.destroy | ||
24 | + end | ||
25 | + WebMock.should have_requested(:post, @system_hook.url).with(body: /project_destroy/).once | ||
26 | + end | ||
27 | + | ||
28 | + it "user_create hook" do | ||
29 | + with_resque do | ||
30 | + Factory :user | ||
31 | + end | ||
32 | + WebMock.should have_requested(:post, @system_hook.url).with(body: /user_create/).once | ||
33 | + end | ||
34 | + | ||
35 | + it "user_destroy hook" do | ||
36 | + user = Factory :user | ||
37 | + with_resque do | ||
38 | + user.destroy | ||
39 | + end | ||
40 | + WebMock.should have_requested(:post, @system_hook.url).with(body: /user_destroy/).once | ||
41 | + end | ||
42 | + | ||
43 | + it "project_create hook" do | ||
44 | + user = Factory :user | ||
45 | + project = Factory :project | ||
46 | + with_resque do | ||
47 | + project.users << user | ||
48 | + end | ||
49 | + WebMock.should have_requested(:post, @system_hook.url).with(body: /user_add_to_team/).once | ||
50 | + end | ||
51 | + | ||
52 | + it "project_destroy hook" do | ||
53 | + user = Factory :user | ||
54 | + project = Factory :project | ||
55 | + project.users << user | ||
56 | + with_resque do | ||
57 | + project.users_projects.clear | ||
58 | + end | ||
59 | + WebMock.should have_requested(:post, @system_hook.url).with(body: /user_remove_from_team/).once | ||
60 | + end | ||
61 | + end | ||
62 | + | ||
63 | +end |
spec/models/web_hook_spec.rb
1 | require 'spec_helper' | 1 | require 'spec_helper' |
2 | 2 | ||
3 | -describe WebHook do | 3 | +describe ProjectHook do |
4 | describe "Associations" do | 4 | describe "Associations" do |
5 | it { should belong_to :project } | 5 | it { should belong_to :project } |
6 | end | 6 | end |
@@ -23,32 +23,32 @@ describe WebHook do | @@ -23,32 +23,32 @@ describe WebHook do | ||
23 | 23 | ||
24 | describe "execute" do | 24 | describe "execute" do |
25 | before(:each) do | 25 | before(:each) do |
26 | - @webhook = Factory :web_hook | 26 | + @project_hook = Factory :project_hook |
27 | @project = Factory :project | 27 | @project = Factory :project |
28 | - @project.web_hooks << [@webhook] | 28 | + @project.hooks << [@project_hook] |
29 | @data = { before: 'oldrev', after: 'newrev', ref: 'ref'} | 29 | @data = { before: 'oldrev', after: 'newrev', ref: 'ref'} |
30 | 30 | ||
31 | - WebMock.stub_request(:post, @webhook.url) | 31 | + WebMock.stub_request(:post, @project_hook.url) |
32 | end | 32 | end |
33 | 33 | ||
34 | it "POSTs to the web hook URL" do | 34 | it "POSTs to the web hook URL" do |
35 | - @webhook.execute(@data) | ||
36 | - WebMock.should have_requested(:post, @webhook.url).once | 35 | + @project_hook.execute(@data) |
36 | + WebMock.should have_requested(:post, @project_hook.url).once | ||
37 | end | 37 | end |
38 | 38 | ||
39 | it "POSTs the data as JSON" do | 39 | it "POSTs the data as JSON" do |
40 | json = @data.to_json | 40 | json = @data.to_json |
41 | 41 | ||
42 | - @webhook.execute(@data) | ||
43 | - WebMock.should have_requested(:post, @webhook.url).with(body: json).once | 42 | + @project_hook.execute(@data) |
43 | + WebMock.should have_requested(:post, @project_hook.url).with(body: json).once | ||
44 | end | 44 | end |
45 | 45 | ||
46 | it "catches exceptions" do | 46 | it "catches exceptions" do |
47 | WebHook.should_receive(:post).and_raise("Some HTTP Post error") | 47 | WebHook.should_receive(:post).and_raise("Some HTTP Post error") |
48 | 48 | ||
49 | lambda { | 49 | lambda { |
50 | - @webhook.execute(@data) | ||
51 | - }.should_not raise_error | 50 | + @project_hook.execute(@data) |
51 | + }.should raise_error | ||
52 | end | 52 | end |
53 | end | 53 | end |
54 | end | 54 | end |
@@ -0,0 +1,53 @@ | @@ -0,0 +1,53 @@ | ||
1 | +require 'spec_helper' | ||
2 | + | ||
3 | +describe "Admin::Hooks" do | ||
4 | + before do | ||
5 | + @project = Factory :project, | ||
6 | + :name => "LeGiT", | ||
7 | + :code => "LGT" | ||
8 | + login_as :admin | ||
9 | + | ||
10 | + @system_hook = Factory :system_hook | ||
11 | + | ||
12 | + end | ||
13 | + | ||
14 | + describe "GET /admin/hooks" do | ||
15 | + it "should be ok" do | ||
16 | + visit admin_root_path | ||
17 | + within ".main_menu" do | ||
18 | + click_on "Hooks" | ||
19 | + end | ||
20 | + current_path.should == admin_hooks_path | ||
21 | + end | ||
22 | + | ||
23 | + it "should have hooks list" do | ||
24 | + visit admin_hooks_path | ||
25 | + page.should have_content(@system_hook.url) | ||
26 | + end | ||
27 | + end | ||
28 | + | ||
29 | + describe "New Hook" do | ||
30 | + before do | ||
31 | + @url = Faker::Internet.uri("http") | ||
32 | + visit admin_hooks_path | ||
33 | + fill_in "hook_url", :with => @url | ||
34 | + expect { click_button "Add System Hook" }.to change(SystemHook, :count).by(1) | ||
35 | + end | ||
36 | + | ||
37 | + it "should open new hook popup" do | ||
38 | + page.current_path.should == admin_hooks_path | ||
39 | + page.should have_content(@url) | ||
40 | + end | ||
41 | + end | ||
42 | + | ||
43 | + describe "Test" do | ||
44 | + before do | ||
45 | + WebMock.stub_request(:post, @system_hook.url) | ||
46 | + visit admin_hooks_path | ||
47 | + click_link "Test Hook" | ||
48 | + end | ||
49 | + | ||
50 | + it { page.current_path.should == admin_hooks_path } | ||
51 | + end | ||
52 | + | ||
53 | +end |
spec/requests/admin/security_spec.rb
@@ -13,9 +13,9 @@ describe "Admin::Projects" do | @@ -13,9 +13,9 @@ describe "Admin::Projects" do | ||
13 | it { admin_users_path.should be_denied_for :visitor } | 13 | it { admin_users_path.should be_denied_for :visitor } |
14 | end | 14 | end |
15 | 15 | ||
16 | - describe "GET /admin/emails" do | ||
17 | - it { admin_emails_path.should be_allowed_for :admin } | ||
18 | - it { admin_emails_path.should be_denied_for :user } | ||
19 | - it { admin_emails_path.should be_denied_for :visitor } | 16 | + describe "GET /admin/hooks" do |
17 | + it { admin_hooks_path.should be_allowed_for :admin } | ||
18 | + it { admin_hooks_path.should be_denied_for :user } | ||
19 | + it { admin_hooks_path.should be_denied_for :visitor } | ||
20 | end | 20 | end |
21 | end | 21 | end |
spec/requests/hooks_spec.rb
@@ -9,7 +9,7 @@ describe "Hooks" do | @@ -9,7 +9,7 @@ describe "Hooks" do | ||
9 | 9 | ||
10 | describe "GET index" do | 10 | describe "GET index" do |
11 | it "should be available" do | 11 | it "should be available" do |
12 | - @hook = Factory :web_hook, :project => @project | 12 | + @hook = Factory :project_hook, :project => @project |
13 | visit project_hooks_path(@project) | 13 | visit project_hooks_path(@project) |
14 | page.should have_content "Hooks" | 14 | page.should have_content "Hooks" |
15 | page.should have_content @hook.url | 15 | page.should have_content @hook.url |
@@ -21,7 +21,7 @@ describe "Hooks" do | @@ -21,7 +21,7 @@ describe "Hooks" do | ||
21 | @url = Faker::Internet.uri("http") | 21 | @url = Faker::Internet.uri("http") |
22 | visit project_hooks_path(@project) | 22 | visit project_hooks_path(@project) |
23 | fill_in "hook_url", :with => @url | 23 | fill_in "hook_url", :with => @url |
24 | - expect { click_button "Add Web Hook" }.to change(WebHook, :count).by(1) | 24 | + expect { click_button "Add Web Hook" }.to change(ProjectHook, :count).by(1) |
25 | end | 25 | end |
26 | 26 | ||
27 | it "should open new team member popup" do | 27 | it "should open new team member popup" do |
@@ -32,7 +32,8 @@ describe "Hooks" do | @@ -32,7 +32,8 @@ describe "Hooks" do | ||
32 | 32 | ||
33 | describe "Test" do | 33 | describe "Test" do |
34 | before do | 34 | before do |
35 | - @hook = Factory :web_hook, :project => @project | 35 | + @hook = Factory :project_hook, :project => @project |
36 | + stub_request(:post, @hook.url) | ||
36 | visit project_hooks_path(@project) | 37 | visit project_hooks_path(@project) |
37 | click_link "Test Hook" | 38 | click_link "Test Hook" |
38 | end | 39 | end |
spec/workers/post_receive_spec.rb
@@ -22,14 +22,14 @@ describe PostReceive do | @@ -22,14 +22,14 @@ describe PostReceive do | ||
22 | Key.stub(find_by_identifier: nil) | 22 | Key.stub(find_by_identifier: nil) |
23 | 23 | ||
24 | project.should_not_receive(:observe_push) | 24 | project.should_not_receive(:observe_push) |
25 | - project.should_not_receive(:execute_web_hooks) | 25 | + project.should_not_receive(:execute_hooks) |
26 | 26 | ||
27 | PostReceive.perform(project.path, 'sha-old', 'sha-new', 'refs/heads/master', key_id).should be_false | 27 | PostReceive.perform(project.path, 'sha-old', 'sha-new', 'refs/heads/master', key_id).should be_false |
28 | end | 28 | end |
29 | 29 | ||
30 | it "asks the project to execute web hooks" do | 30 | it "asks the project to execute web hooks" do |
31 | Project.stub(find_by_path: project) | 31 | Project.stub(find_by_path: project) |
32 | - project.should_receive(:execute_web_hooks).with('sha-old', 'sha-new', 'refs/heads/master', project.owner) | 32 | + project.should_receive(:execute_hooks).with('sha-old', 'sha-new', 'refs/heads/master', project.owner) |
33 | 33 | ||
34 | PostReceive.perform(project.path, 'sha-old', 'sha-new', 'refs/heads/master', key_id) | 34 | PostReceive.perform(project.path, 'sha-old', 'sha-new', 'refs/heads/master', key_id) |
35 | end | 35 | end |