Commit 4f067ae931bef908312bbf7162abb3b6fdb85f8d
Exists in
master
and in
4 other branches
Merge branch 'feature/event_hooks' of /home/git/repositories/gitlab/gitlabhq
Showing
27 changed files
with
447 additions
and
268 deletions
Show diff stats
CHANGELOG
| @@ -7,6 +7,7 @@ v 6.4.0 | @@ -7,6 +7,7 @@ v 6.4.0 | ||
| 7 | - Side-by-side diff view (Steven Thonus) | 7 | - Side-by-side diff view (Steven Thonus) |
| 8 | - Internal projects (Jason Hollingsworth) | 8 | - Internal projects (Jason Hollingsworth) |
| 9 | - Allow removal of avatar (Drew Blessing) | 9 | - Allow removal of avatar (Drew Blessing) |
| 10 | + - Project web hooks now support issues and merge request events | ||
| 10 | 11 | ||
| 11 | v 6.3.0 | 12 | v 6.3.0 |
| 12 | - API for adding gitlab-ci service | 13 | - API for adding gitlab-ci service |
app/assets/stylesheets/gitlab_bootstrap/forms.scss
app/helpers/application_helper.rb
| @@ -207,4 +207,12 @@ module ApplicationHelper | @@ -207,4 +207,12 @@ module ApplicationHelper | ||
| 207 | def broadcast_message | 207 | def broadcast_message |
| 208 | BroadcastMessage.current | 208 | BroadcastMessage.current |
| 209 | end | 209 | end |
| 210 | + | ||
| 211 | + def highlight_js(&block) | ||
| 212 | + string = capture(&block) | ||
| 213 | + | ||
| 214 | + content_tag :div, class: user_color_scheme_class do | ||
| 215 | + Pygments::Lexer[:js].highlight(string).html_safe | ||
| 216 | + end | ||
| 217 | + end | ||
| 210 | end | 218 | end |
app/models/concerns/issuable.rb
| @@ -111,4 +111,11 @@ module Issuable | @@ -111,4 +111,11 @@ module Issuable | ||
| 111 | end | 111 | end |
| 112 | users.concat(mentions.reduce([], :|)).uniq | 112 | users.concat(mentions.reduce([], :|)).uniq |
| 113 | end | 113 | end |
| 114 | + | ||
| 115 | + def to_hook_data | ||
| 116 | + { | ||
| 117 | + object_kind: self.class.name.underscore, | ||
| 118 | + object_attributes: self.attributes | ||
| 119 | + } | ||
| 120 | + end | ||
| 114 | end | 121 | end |
app/models/project.rb
| @@ -298,8 +298,10 @@ class Project < ActiveRecord::Base | @@ -298,8 +298,10 @@ class Project < ActiveRecord::Base | ||
| 298 | ProjectTransferService.new.transfer(self, new_namespace) | 298 | ProjectTransferService.new.transfer(self, new_namespace) |
| 299 | end | 299 | end |
| 300 | 300 | ||
| 301 | - def execute_hooks(data) | ||
| 302 | - hooks.each { |hook| hook.async_execute(data) } | 301 | + def execute_hooks(data, hooks_scope = :push_hooks) |
| 302 | + hooks.send(hooks_scope).each do |hook| | ||
| 303 | + hook.async_execute(data) | ||
| 304 | + end | ||
| 303 | end | 305 | end |
| 304 | 306 | ||
| 305 | def execute_services(data) | 307 | def execute_services(data) |
app/models/project_hook.rb
| @@ -2,15 +2,24 @@ | @@ -2,15 +2,24 @@ | ||
| 2 | # | 2 | # |
| 3 | # Table name: web_hooks | 3 | # Table name: web_hooks |
| 4 | # | 4 | # |
| 5 | -# id :integer not null, primary key | ||
| 6 | -# url :string(255) | ||
| 7 | -# project_id :integer | ||
| 8 | -# created_at :datetime not null | ||
| 9 | -# updated_at :datetime not null | ||
| 10 | -# type :string(255) default("ProjectHook") | ||
| 11 | -# service_id :integer | 5 | +# id :integer not null, primary key |
| 6 | +# url :string(255) | ||
| 7 | +# project_id :integer | ||
| 8 | +# created_at :datetime not null | ||
| 9 | +# updated_at :datetime not null | ||
| 10 | +# type :string(255) default("ProjectHook") | ||
| 11 | +# service_id :integer | ||
| 12 | +# push_events :boolean default(TRUE), not null | ||
| 13 | +# issues_events :boolean default(FALSE), not null | ||
| 14 | +# merge_requests_events :boolean default(FALSE), not null | ||
| 12 | # | 15 | # |
| 13 | 16 | ||
| 14 | class ProjectHook < WebHook | 17 | class ProjectHook < WebHook |
| 15 | belongs_to :project | 18 | belongs_to :project |
| 19 | + | ||
| 20 | + attr_accessible :push_events, :issues_events, :merge_requests_events | ||
| 21 | + | ||
| 22 | + scope :push_hooks, -> { where(push_events: true) } | ||
| 23 | + scope :issue_hooks, -> { where(issues_events: true) } | ||
| 24 | + scope :merge_request_hooks, -> { where(merge_requests_events: true) } | ||
| 16 | end | 25 | end |
app/models/service_hook.rb
| @@ -2,13 +2,16 @@ | @@ -2,13 +2,16 @@ | ||
| 2 | # | 2 | # |
| 3 | # Table name: web_hooks | 3 | # Table name: web_hooks |
| 4 | # | 4 | # |
| 5 | -# id :integer not null, primary key | ||
| 6 | -# url :string(255) | ||
| 7 | -# project_id :integer | ||
| 8 | -# created_at :datetime not null | ||
| 9 | -# updated_at :datetime not null | ||
| 10 | -# type :string(255) default("ProjectHook") | ||
| 11 | -# service_id :integer | 5 | +# id :integer not null, primary key |
| 6 | +# url :string(255) | ||
| 7 | +# project_id :integer | ||
| 8 | +# created_at :datetime not null | ||
| 9 | +# updated_at :datetime not null | ||
| 10 | +# type :string(255) default("ProjectHook") | ||
| 11 | +# service_id :integer | ||
| 12 | +# push_events :boolean default(TRUE), not null | ||
| 13 | +# issues_events :boolean default(FALSE), not null | ||
| 14 | +# merge_requests_events :boolean default(FALSE), not null | ||
| 12 | # | 15 | # |
| 13 | 16 | ||
| 14 | class ServiceHook < WebHook | 17 | class ServiceHook < WebHook |
app/models/system_hook.rb
| @@ -2,13 +2,16 @@ | @@ -2,13 +2,16 @@ | ||
| 2 | # | 2 | # |
| 3 | # Table name: web_hooks | 3 | # Table name: web_hooks |
| 4 | # | 4 | # |
| 5 | -# id :integer not null, primary key | ||
| 6 | -# url :string(255) | ||
| 7 | -# project_id :integer | ||
| 8 | -# created_at :datetime not null | ||
| 9 | -# updated_at :datetime not null | ||
| 10 | -# type :string(255) default("ProjectHook") | ||
| 11 | -# service_id :integer | 5 | +# id :integer not null, primary key |
| 6 | +# url :string(255) | ||
| 7 | +# project_id :integer | ||
| 8 | +# created_at :datetime not null | ||
| 9 | +# updated_at :datetime not null | ||
| 10 | +# type :string(255) default("ProjectHook") | ||
| 11 | +# service_id :integer | ||
| 12 | +# push_events :boolean default(TRUE), not null | ||
| 13 | +# issues_events :boolean default(FALSE), not null | ||
| 14 | +# merge_requests_events :boolean default(FALSE), not null | ||
| 12 | # | 15 | # |
| 13 | 16 | ||
| 14 | class SystemHook < WebHook | 17 | class SystemHook < WebHook |
app/models/web_hook.rb
| @@ -2,13 +2,16 @@ | @@ -2,13 +2,16 @@ | ||
| 2 | # | 2 | # |
| 3 | # Table name: web_hooks | 3 | # Table name: web_hooks |
| 4 | # | 4 | # |
| 5 | -# id :integer not null, primary key | ||
| 6 | -# url :string(255) | ||
| 7 | -# project_id :integer | ||
| 8 | -# created_at :datetime not null | ||
| 9 | -# updated_at :datetime not null | ||
| 10 | -# type :string(255) default("ProjectHook") | ||
| 11 | -# service_id :integer | 5 | +# id :integer not null, primary key |
| 6 | +# url :string(255) | ||
| 7 | +# project_id :integer | ||
| 8 | +# created_at :datetime not null | ||
| 9 | +# updated_at :datetime not null | ||
| 10 | +# type :string(255) default("ProjectHook") | ||
| 11 | +# service_id :integer | ||
| 12 | +# push_events :boolean default(TRUE), not null | ||
| 13 | +# issues_events :boolean default(FALSE), not null | ||
| 14 | +# merge_requests_events :boolean default(FALSE), not null | ||
| 12 | # | 15 | # |
| 13 | 16 | ||
| 14 | class WebHook < ActiveRecord::Base | 17 | class WebHook < ActiveRecord::Base |
app/observers/issue_observer.rb
| 1 | class IssueObserver < BaseObserver | 1 | class IssueObserver < BaseObserver |
| 2 | def after_create(issue) | 2 | def after_create(issue) |
| 3 | notification.new_issue(issue, current_user) | 3 | notification.new_issue(issue, current_user) |
| 4 | - | ||
| 5 | issue.create_cross_references!(issue.project, current_user) | 4 | issue.create_cross_references!(issue.project, current_user) |
| 5 | + execute_hooks(issue) | ||
| 6 | end | 6 | end |
| 7 | 7 | ||
| 8 | def after_close(issue, transition) | 8 | def after_close(issue, transition) |
| 9 | notification.close_issue(issue, current_user) | 9 | notification.close_issue(issue, current_user) |
| 10 | - | ||
| 11 | create_note(issue) | 10 | create_note(issue) |
| 11 | + execute_hooks(issue) | ||
| 12 | end | 12 | end |
| 13 | 13 | ||
| 14 | def after_reopen(issue, transition) | 14 | def after_reopen(issue, transition) |
| @@ -29,4 +29,8 @@ class IssueObserver < BaseObserver | @@ -29,4 +29,8 @@ class IssueObserver < BaseObserver | ||
| 29 | def create_note(issue) | 29 | def create_note(issue) |
| 30 | Note.create_status_change_note(issue, issue.project, current_user, issue.state, current_commit) | 30 | Note.create_status_change_note(issue, issue.project, current_user, issue.state, current_commit) |
| 31 | end | 31 | end |
| 32 | + | ||
| 33 | + def execute_hooks(issue) | ||
| 34 | + issue.project.execute_hooks(issue.to_hook_data, :issue_hooks) | ||
| 35 | + end | ||
| 32 | end | 36 | end |
app/observers/merge_request_observer.rb
| @@ -7,15 +7,15 @@ class MergeRequestObserver < ActivityObserver | @@ -7,15 +7,15 @@ class MergeRequestObserver < ActivityObserver | ||
| 7 | end | 7 | end |
| 8 | 8 | ||
| 9 | notification.new_merge_request(merge_request, current_user) | 9 | notification.new_merge_request(merge_request, current_user) |
| 10 | - | ||
| 11 | merge_request.create_cross_references!(merge_request.project, current_user) | 10 | merge_request.create_cross_references!(merge_request.project, current_user) |
| 11 | + execute_hooks(merge_request) | ||
| 12 | end | 12 | end |
| 13 | 13 | ||
| 14 | def after_close(merge_request, transition) | 14 | def after_close(merge_request, transition) |
| 15 | create_event(merge_request, Event::CLOSED) | 15 | create_event(merge_request, Event::CLOSED) |
| 16 | - Note.create_status_change_note(merge_request, merge_request.target_project, current_user, merge_request.state, nil) | ||
| 17 | - | ||
| 18 | notification.close_mr(merge_request, current_user) | 16 | notification.close_mr(merge_request, current_user) |
| 17 | + create_note(merge_request) | ||
| 18 | + execute_hooks(merge_request) | ||
| 19 | end | 19 | end |
| 20 | 20 | ||
| 21 | def after_merge(merge_request, transition) | 21 | def after_merge(merge_request, transition) |
| @@ -31,11 +31,13 @@ class MergeRequestObserver < ActivityObserver | @@ -31,11 +31,13 @@ class MergeRequestObserver < ActivityObserver | ||
| 31 | action: Event::MERGED, | 31 | action: Event::MERGED, |
| 32 | author_id: merge_request.author_id_of_changes | 32 | author_id: merge_request.author_id_of_changes |
| 33 | ) | 33 | ) |
| 34 | + | ||
| 35 | + execute_hooks(merge_request) | ||
| 34 | end | 36 | end |
| 35 | 37 | ||
| 36 | def after_reopen(merge_request, transition) | 38 | def after_reopen(merge_request, transition) |
| 37 | create_event(merge_request, Event::REOPENED) | 39 | create_event(merge_request, Event::REOPENED) |
| 38 | - Note.create_status_change_note(merge_request, merge_request.target_project, current_user, merge_request.state, nil) | 40 | + create_note(merge_request) |
| 39 | end | 41 | end |
| 40 | 42 | ||
| 41 | def after_update(merge_request) | 43 | def after_update(merge_request) |
| @@ -53,4 +55,17 @@ class MergeRequestObserver < ActivityObserver | @@ -53,4 +55,17 @@ class MergeRequestObserver < ActivityObserver | ||
| 53 | author_id: current_user.id | 55 | author_id: current_user.id |
| 54 | ) | 56 | ) |
| 55 | end | 57 | end |
| 58 | + | ||
| 59 | + private | ||
| 60 | + | ||
| 61 | + # Create merge request note with service comment like 'Status changed to closed' | ||
| 62 | + def create_note(merge_request) | ||
| 63 | + Note.create_status_change_note(merge_request, merge_request.target_project, current_user, merge_request.state, nil) | ||
| 64 | + end | ||
| 65 | + | ||
| 66 | + def execute_hooks(merge_request) | ||
| 67 | + if merge_request.project | ||
| 68 | + merge_request.project.execute_hooks(merge_request.to_hook_data, :merge_request_hooks) | ||
| 69 | + end | ||
| 70 | + end | ||
| 56 | end | 71 | end |
app/services/git_push_service.rb
| @@ -32,7 +32,7 @@ class GitPushService | @@ -32,7 +32,7 @@ class GitPushService | ||
| 32 | end | 32 | end |
| 33 | 33 | ||
| 34 | if push_to_branch?(ref) | 34 | if push_to_branch?(ref) |
| 35 | - project.execute_hooks(@push_data.dup) | 35 | + project.execute_hooks(@push_data.dup, :push_hooks) |
| 36 | project.execute_services(@push_data.dup) | 36 | project.execute_services(@push_data.dup) |
| 37 | end | 37 | end |
| 38 | 38 |
app/views/help/web_hooks.html.haml
| 1 | = render layout: 'help/layout' do | 1 | = render layout: 'help/layout' do |
| 2 | - %h3.page-title Web hooks | 2 | + %h3.page-title Project web hooks |
| 3 | + %p.light | ||
| 4 | + Project web hooks allow you to trigger url if new code is pushed or new issue is created | ||
| 5 | + %hr | ||
| 3 | 6 | ||
| 4 | %p.slead | 7 | %p.slead |
| 5 | - Every GitLab project can trigger a web server whenever the repo is pushed to. | 8 | + You can configure web hook to listen for specific events like pushes, issues, merge requests. |
| 9 | + %br | ||
| 10 | + GitLab will send POST request with data to web hook url. | ||
| 6 | %br | 11 | %br |
| 7 | Web Hooks can be used to update an external issue tracker, trigger CI builds, update a backup mirror, or even deploy to your production server. | 12 | Web Hooks can be used to update an external issue tracker, trigger CI builds, update a backup mirror, or even deploy to your production server. |
| 13 | + %hr | ||
| 14 | + | ||
| 15 | + %h4 Push events | ||
| 16 | + %p.light | ||
| 17 | + Triggered when you push to the repository except pushing tags. | ||
| 8 | %br | 18 | %br |
| 9 | - GitLab will send POST request with commits information on every push. | ||
| 10 | - %h5 Hooks request example: | ||
| 11 | - = render "projects/hooks/data_ex" | 19 | + Request body: |
| 20 | + = highlight_js do | ||
| 21 | + :erb | ||
| 22 | + { | ||
| 23 | + "before": "95790bf891e76fee5e1747ab589903a6a1f80f22", | ||
| 24 | + "after": "da1560886d4f094c3e6c9ef40349f7d38b5d27d7", | ||
| 25 | + "ref": "refs/heads/master", | ||
| 26 | + "user_id": 4, | ||
| 27 | + "user_name": "John Smith", | ||
| 28 | + "project_id": 15, | ||
| 29 | + "repository": { | ||
| 30 | + "name": "Diaspora", | ||
| 31 | + "url": "git@localhost:diaspora.git", | ||
| 32 | + "description": "", | ||
| 33 | + "homepage": "http://localhost/diaspora", | ||
| 34 | + }, | ||
| 35 | + "commits": [ | ||
| 36 | + { | ||
| 37 | + "id": "b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327", | ||
| 38 | + "message": "Update Catalan translation to e38cb41.", | ||
| 39 | + "timestamp": "2011-12-12T14:27:31+02:00", | ||
| 40 | + "url": "http://localhost/diaspora/commits/b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327", | ||
| 41 | + "author": { | ||
| 42 | + "name": "Jordi Mallach", | ||
| 43 | + "email": "jordi@softcatala.org", | ||
| 44 | + } | ||
| 45 | + }, | ||
| 46 | + // ... | ||
| 47 | + { | ||
| 48 | + "id": "da1560886d4f094c3e6c9ef40349f7d38b5d27d7", | ||
| 49 | + "message": "fixed readme", | ||
| 50 | + "timestamp": "2012-01-03T23:36:29+02:00", | ||
| 51 | + "url": "http://localhost/diaspora/commits/da1560886d4f094c3e6c9ef40349f7d38b5d27d7", | ||
| 52 | + "author": { | ||
| 53 | + "name": "GitLab dev user", | ||
| 54 | + "email": "gitlabdev@dv6700.(none)", | ||
| 55 | + }, | ||
| 56 | + }, | ||
| 57 | + ], | ||
| 58 | + "total_commits_count": 4, | ||
| 59 | + }; | ||
| 60 | + | ||
| 12 | 61 | ||
| 62 | + %h4.prepend-top-20 Issues events | ||
| 63 | + %p.light | ||
| 64 | + Triggered when new issue created or existing issue was closed. | ||
| 65 | + %br | ||
| 66 | + Request body: | ||
| 67 | + = highlight_js do | ||
| 68 | + :erb | ||
| 69 | + { | ||
| 70 | + "object_kind":"issue", | ||
| 71 | + "object_attributes":{ | ||
| 72 | + "id":301, | ||
| 73 | + "title":"New API: create/update/delete file", | ||
| 74 | + "assignee_id":51, | ||
| 75 | + "author_id":51, | ||
| 76 | + "project_id":14, | ||
| 77 | + "created_at":"2013-12-03T17:15:43Z", | ||
| 78 | + "updated_at":"2013-12-03T17:15:43Z", | ||
| 79 | + "position":0, | ||
| 80 | + "branch_name":null, | ||
| 81 | + "description":"Create new API for manipulations with repository", | ||
| 82 | + "milestone_id":null, | ||
| 83 | + "state":"opened", | ||
| 84 | + "iid":23 | ||
| 85 | + } | ||
| 86 | + } | ||
| 87 | + %h4.prepend-top-20 Merge request events | ||
| 88 | + %p.light | ||
| 89 | + Triggered when new merge request created or existing merge request was merged/closed. | ||
| 90 | + %br | ||
| 91 | + Request body: | ||
| 92 | + = highlight_js do | ||
| 93 | + :erb | ||
| 94 | + { | ||
| 95 | + "object_kind":"merge_request", | ||
| 96 | + "object_attributes":{ | ||
| 97 | + "id":99, | ||
| 98 | + "target_branch":"master", | ||
| 99 | + "source_branch":"ms-viewport", | ||
| 100 | + "source_project_id":14, | ||
| 101 | + "author_id":51, | ||
| 102 | + "assignee_id":6, | ||
| 103 | + "title":"MS-Viewport", | ||
| 104 | + "created_at":"2013-12-03T17:23:34Z", | ||
| 105 | + "updated_at":"2013-12-03T17:23:34Z", | ||
| 106 | + "st_commits":null, | ||
| 107 | + "st_diffs":null, | ||
| 108 | + "milestone_id":null, | ||
| 109 | + "state":"opened", | ||
| 110 | + "merge_status":"unchecked", | ||
| 111 | + "target_project_id":14, | ||
| 112 | + "iid":1, | ||
| 113 | + "description":"" | ||
| 114 | + } | ||
| 115 | + } |
app/views/projects/hooks/_data_ex.html.erb
| @@ -1,44 +0,0 @@ | @@ -1,44 +0,0 @@ | ||
| 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 | - "project_id": 15, | ||
| 9 | - "repository": { | ||
| 10 | - "name": "Diaspora", | ||
| 11 | - "url": "git@localhost:diaspora.git", | ||
| 12 | - "description": "", | ||
| 13 | - "homepage": "http://localhost/diaspora", | ||
| 14 | - }, | ||
| 15 | - "commits": [ | ||
| 16 | - { | ||
| 17 | - "id": "b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327", | ||
| 18 | - "message": "Update Catalan translation to e38cb41.", | ||
| 19 | - "timestamp": "2011-12-12T14:27:31+02:00", | ||
| 20 | - "url": "http://localhost/diaspora/commits/b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327", | ||
| 21 | - "author": { | ||
| 22 | - "name": "Jordi Mallach", | ||
| 23 | - "email": "jordi@softcatala.org", | ||
| 24 | - } | ||
| 25 | - }, | ||
| 26 | - // ... | ||
| 27 | - { | ||
| 28 | - "id": "da1560886d4f094c3e6c9ef40349f7d38b5d27d7", | ||
| 29 | - "message": "fixed readme", | ||
| 30 | - "timestamp": "2012-01-03T23:36:29+02:00", | ||
| 31 | - "url": "http://localhost/diaspora/commits/da1560886d4f094c3e6c9ef40349f7d38b5d27d7", | ||
| 32 | - "author": { | ||
| 33 | - "name": "GitLab dev user", | ||
| 34 | - "email": "gitlabdev@dv6700.(none)", | ||
| 35 | - }, | ||
| 36 | - }, | ||
| 37 | - ], | ||
| 38 | - "total_commits_count": 4, | ||
| 39 | -}; | ||
| 40 | -eos | ||
| 41 | -%> | ||
| 42 | -<div class="<%= user_color_scheme_class%>"> | ||
| 43 | - <%= raw Pygments::Lexer[:js].highlight(data_ex_str) %> | ||
| 44 | -</div> |
app/views/projects/hooks/index.html.haml
| 1 | %h3.page-title | 1 | %h3.page-title |
| 2 | - Post-receive hooks | 2 | + Web hooks |
| 3 | 3 | ||
| 4 | %p.light | 4 | %p.light |
| 5 | - #{link_to "Post-receive hooks ", help_web_hooks_path, class: "vlink"} can be | ||
| 6 | - used for binding events when someone pushes to the repository. | 5 | + #{link_to "Web hooks ", help_web_hooks_path, class: "vlink"} can be |
| 6 | + used for binding events when something happends to the the project. | ||
| 7 | 7 | ||
| 8 | %hr.clearfix | 8 | %hr.clearfix |
| 9 | 9 | ||
| @@ -13,23 +13,50 @@ | @@ -13,23 +13,50 @@ | ||
| 13 | - @hook.errors.full_messages.each do |msg| | 13 | - @hook.errors.full_messages.each do |msg| |
| 14 | %p= msg | 14 | %p= msg |
| 15 | .control-group | 15 | .control-group |
| 16 | - = f.label :url, "URL:" | 16 | + = f.label :url, "URL" |
| 17 | .controls | 17 | .controls |
| 18 | = f.text_field :url, class: "text_field input-xxlarge input-xpadding", placeholder: 'http://example.com/trigger-ci.json' | 18 | = f.text_field :url, class: "text_field input-xxlarge input-xpadding", placeholder: 'http://example.com/trigger-ci.json' |
| 19 | | 19 | |
| 20 | = f.submit "Add Web Hook", class: "btn btn-create" | 20 | = f.submit "Add Web Hook", class: "btn btn-create" |
| 21 | + .control-group | ||
| 22 | + = f.label :url, "Trigger" | ||
| 23 | + .controls | ||
| 24 | + %div | ||
| 25 | + = f.check_box :push_events, class: 'pull-left' | ||
| 26 | + .prepend-left-20 | ||
| 27 | + = f.label :push_events, class: 'list-label' do | ||
| 28 | + %strong Push events | ||
| 29 | + %p.light | ||
| 30 | + This url will be triggered in case of push to repository | ||
| 31 | + %div | ||
| 32 | + = f.check_box :issues_events, class: 'pull-left' | ||
| 33 | + .prepend-left-20 | ||
| 34 | + = f.label :issues_events, class: 'list-label' do | ||
| 35 | + %strong Issues events | ||
| 36 | + %p.light | ||
| 37 | + This url will be triggered for created issues | ||
| 38 | + %div | ||
| 39 | + = f.check_box :merge_requests_events, class: 'pull-left' | ||
| 40 | + .prepend-left-20 | ||
| 41 | + = f.label :merge_requests_events, class: 'list-label' do | ||
| 42 | + %strong Merge Request events | ||
| 43 | + %p.light | ||
| 44 | + This url will be triggered for created merge requests | ||
| 21 | %hr | 45 | %hr |
| 22 | 46 | ||
| 23 | -if @hooks.any? | 47 | -if @hooks.any? |
| 24 | .ui-box | 48 | .ui-box |
| 25 | .title | 49 | .title |
| 26 | - Hooks (#{@hooks.count}) | 50 | + Web Hooks (#{@hooks.count}) |
| 27 | %ul.well-list | 51 | %ul.well-list |
| 28 | - @hooks.each do |hook| | 52 | - @hooks.each do |hook| |
| 29 | %li | 53 | %li |
| 30 | - %span.badge.badge-info POST | ||
| 31 | - → | ||
| 32 | - %span.monospace= hook.url | ||
| 33 | .pull-right | 54 | .pull-right |
| 34 | = link_to 'Test Hook', test_project_hook_path(@project, hook), class: "btn btn-small grouped" | 55 | = link_to 'Test Hook', test_project_hook_path(@project, hook), class: "btn btn-small grouped" |
| 35 | = link_to 'Remove', project_hook_path(@project, hook), confirm: 'Are you sure?', method: :delete, class: "btn btn-remove btn-small grouped" | 56 | = link_to 'Remove', project_hook_path(@project, hook), confirm: 'Are you sure?', method: :delete, class: "btn btn-remove btn-small grouped" |
| 57 | + .clearfix | ||
| 58 | + %span.monospace= hook.url | ||
| 59 | + %p | ||
| 60 | + - %w(push_events issues_events merge_requests_events).each do |trigger| | ||
| 61 | + - if hook.send(trigger) | ||
| 62 | + %span.label.label-gray= trigger.titleize |
db/migrate/20131202192556_add_event_fields_for_web_hook.rb
0 → 100644
| @@ -0,0 +1,7 @@ | @@ -0,0 +1,7 @@ | ||
| 1 | +class AddEventFieldsForWebHook < ActiveRecord::Migration | ||
| 2 | + def change | ||
| 3 | + add_column :web_hooks, :push_events, :boolean, default: true, null: false | ||
| 4 | + add_column :web_hooks, :issues_events, :boolean, default: false, null: false | ||
| 5 | + add_column :web_hooks, :merge_requests_events, :boolean, default: false, null: false | ||
| 6 | + end | ||
| 7 | +end |
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 => 20131112220935) do | 14 | +ActiveRecord::Schema.define(:version => 20131202192556) do |
| 15 | 15 | ||
| 16 | create_table "broadcast_messages", :force => true do |t| | 16 | create_table "broadcast_messages", :force => true do |t| |
| 17 | t.text "message", :null => false | 17 | t.text "message", :null => false |
| @@ -334,10 +334,13 @@ ActiveRecord::Schema.define(:version => 20131112220935) do | @@ -334,10 +334,13 @@ ActiveRecord::Schema.define(:version => 20131112220935) do | ||
| 334 | create_table "web_hooks", :force => true do |t| | 334 | create_table "web_hooks", :force => true do |t| |
| 335 | t.string "url" | 335 | t.string "url" |
| 336 | t.integer "project_id" | 336 | t.integer "project_id" |
| 337 | - t.datetime "created_at", :null => false | ||
| 338 | - t.datetime "updated_at", :null => false | ||
| 339 | - t.string "type", :default => "ProjectHook" | 337 | + t.datetime "created_at", :null => false |
| 338 | + t.datetime "updated_at", :null => false | ||
| 339 | + t.string "type", :default => "ProjectHook" | ||
| 340 | t.integer "service_id" | 340 | t.integer "service_id" |
| 341 | + t.boolean "push_events", :default => true, :null => false | ||
| 342 | + t.boolean "issues_events", :default => false, :null => false | ||
| 343 | + t.boolean "merge_requests_events", :default => false, :null => false | ||
| 341 | end | 344 | end |
| 342 | 345 | ||
| 343 | add_index "web_hooks", ["project_id"], :name => "index_web_hooks_on_project_id" | 346 | add_index "web_hooks", ["project_id"], :name => "index_web_hooks_on_project_id" |
doc/api/projects.md
| @@ -402,6 +402,10 @@ Parameters: | @@ -402,6 +402,10 @@ Parameters: | ||
| 402 | { | 402 | { |
| 403 | "id": 1, | 403 | "id": 1, |
| 404 | "url": "http://example.com/hook", | 404 | "url": "http://example.com/hook", |
| 405 | + "project_id": 3, | ||
| 406 | + "push_events": "true", | ||
| 407 | + "issues_events": "true", | ||
| 408 | + "merge_requests_events": "true", | ||
| 405 | "created_at": "2012-10-12T17:04:47Z" | 409 | "created_at": "2012-10-12T17:04:47Z" |
| 406 | } | 410 | } |
| 407 | ``` | 411 | ``` |
| @@ -419,6 +423,9 @@ Parameters: | @@ -419,6 +423,9 @@ Parameters: | ||
| 419 | 423 | ||
| 420 | + `id` (required) - The ID or NAME of a project | 424 | + `id` (required) - The ID or NAME of a project |
| 421 | + `url` (required) - The hook URL | 425 | + `url` (required) - The hook URL |
| 426 | ++ `push_events` - Trigger hook on push events | ||
| 427 | ++ `issues_events` - Trigger hook on issues events | ||
| 428 | ++ `merge_requests_events` - Trigger hook on merge_requests events | ||
| 422 | 429 | ||
| 423 | 430 | ||
| 424 | ### Edit project hook | 431 | ### Edit project hook |
| @@ -434,6 +441,9 @@ Parameters: | @@ -434,6 +441,9 @@ Parameters: | ||
| 434 | + `id` (required) - The ID or NAME of a project | 441 | + `id` (required) - The ID or NAME of a project |
| 435 | + `hook_id` (required) - The ID of a project hook | 442 | + `hook_id` (required) - The ID of a project hook |
| 436 | + `url` (required) - The hook URL | 443 | + `url` (required) - The hook URL |
| 444 | ++ `push_events` - Trigger hook on push events | ||
| 445 | ++ `issues_events` - Trigger hook on issues events | ||
| 446 | ++ `merge_requests_events` - Trigger hook on merge_requests events | ||
| 437 | 447 | ||
| 438 | 448 | ||
| 439 | ### Delete project hook | 449 | ### Delete project hook |
lib/api/entities.rb
| @@ -24,6 +24,10 @@ module API | @@ -24,6 +24,10 @@ module API | ||
| 24 | expose :id, :url, :created_at | 24 | expose :id, :url, :created_at |
| 25 | end | 25 | end |
| 26 | 26 | ||
| 27 | + class ProjectHook < Hook | ||
| 28 | + expose :project_id, :push_events, :issues_events, :merge_requests_events | ||
| 29 | + end | ||
| 30 | + | ||
| 27 | class ForkedFromProject < Grape::Entity | 31 | class ForkedFromProject < Grape::Entity |
| 28 | expose :id | 32 | expose :id |
| 29 | expose :name, :name_with_namespace | 33 | expose :name, :name_with_namespace |
lib/api/project_hooks.rb
| @@ -22,7 +22,7 @@ module API | @@ -22,7 +22,7 @@ module API | ||
| 22 | # GET /projects/:id/hooks | 22 | # GET /projects/:id/hooks |
| 23 | get ":id/hooks" do | 23 | get ":id/hooks" do |
| 24 | @hooks = paginate user_project.hooks | 24 | @hooks = paginate user_project.hooks |
| 25 | - present @hooks, with: Entities::Hook | 25 | + present @hooks, with: Entities::ProjectHook |
| 26 | end | 26 | end |
| 27 | 27 | ||
| 28 | # Get a project hook | 28 | # Get a project hook |
| @@ -34,7 +34,7 @@ module API | @@ -34,7 +34,7 @@ module API | ||
| 34 | # GET /projects/:id/hooks/:hook_id | 34 | # GET /projects/:id/hooks/:hook_id |
| 35 | get ":id/hooks/:hook_id" do | 35 | get ":id/hooks/:hook_id" do |
| 36 | @hook = user_project.hooks.find(params[:hook_id]) | 36 | @hook = user_project.hooks.find(params[:hook_id]) |
| 37 | - present @hook, with: Entities::Hook | 37 | + present @hook, with: Entities::ProjectHook |
| 38 | end | 38 | end |
| 39 | 39 | ||
| 40 | 40 | ||
| @@ -47,10 +47,11 @@ module API | @@ -47,10 +47,11 @@ module API | ||
| 47 | # POST /projects/:id/hooks | 47 | # POST /projects/:id/hooks |
| 48 | post ":id/hooks" do | 48 | post ":id/hooks" do |
| 49 | required_attributes! [:url] | 49 | required_attributes! [:url] |
| 50 | + attrs = attributes_for_keys [:url, :push_events, :issues_events, :merge_requests_events] | ||
| 51 | + @hook = user_project.hooks.new(attrs) | ||
| 50 | 52 | ||
| 51 | - @hook = user_project.hooks.new({"url" => params[:url]}) | ||
| 52 | if @hook.save | 53 | if @hook.save |
| 53 | - present @hook, with: Entities::Hook | 54 | + present @hook, with: Entities::ProjectHook |
| 54 | else | 55 | else |
| 55 | if @hook.errors[:url].present? | 56 | if @hook.errors[:url].present? |
| 56 | error!("Invalid url given", 422) | 57 | error!("Invalid url given", 422) |
| @@ -70,10 +71,10 @@ module API | @@ -70,10 +71,10 @@ module API | ||
| 70 | put ":id/hooks/:hook_id" do | 71 | put ":id/hooks/:hook_id" do |
| 71 | @hook = user_project.hooks.find(params[:hook_id]) | 72 | @hook = user_project.hooks.find(params[:hook_id]) |
| 72 | required_attributes! [:url] | 73 | required_attributes! [:url] |
| 74 | + attrs = attributes_for_keys [:url, :push_events, :issues_events, :merge_requests_events] | ||
| 73 | 75 | ||
| 74 | - attrs = attributes_for_keys [:url] | ||
| 75 | if @hook.update_attributes attrs | 76 | if @hook.update_attributes attrs |
| 76 | - present @hook, with: Entities::Hook | 77 | + present @hook, with: Entities::ProjectHook |
| 77 | else | 78 | else |
| 78 | if @hook.errors[:url].present? | 79 | if @hook.errors[:url].present? |
| 79 | error!("Invalid url given", 422) | 80 | error!("Invalid url given", 422) |
spec/models/service_hook_spec.rb
| @@ -2,13 +2,16 @@ | @@ -2,13 +2,16 @@ | ||
| 2 | # | 2 | # |
| 3 | # Table name: web_hooks | 3 | # Table name: web_hooks |
| 4 | # | 4 | # |
| 5 | -# id :integer not null, primary key | ||
| 6 | -# url :string(255) | ||
| 7 | -# project_id :integer | ||
| 8 | -# created_at :datetime not null | ||
| 9 | -# updated_at :datetime not null | ||
| 10 | -# type :string(255) default("ProjectHook") | ||
| 11 | -# service_id :integer | 5 | +# id :integer not null, primary key |
| 6 | +# url :string(255) | ||
| 7 | +# project_id :integer | ||
| 8 | +# created_at :datetime not null | ||
| 9 | +# updated_at :datetime not null | ||
| 10 | +# type :string(255) default("ProjectHook") | ||
| 11 | +# service_id :integer | ||
| 12 | +# push_events :boolean default(TRUE), not null | ||
| 13 | +# issues_events :boolean default(FALSE), not null | ||
| 14 | +# merge_requests_events :boolean default(FALSE), not null | ||
| 12 | # | 15 | # |
| 13 | 16 | ||
| 14 | require "spec_helper" | 17 | require "spec_helper" |
spec/models/system_hook_spec.rb
| @@ -2,13 +2,16 @@ | @@ -2,13 +2,16 @@ | ||
| 2 | # | 2 | # |
| 3 | # Table name: web_hooks | 3 | # Table name: web_hooks |
| 4 | # | 4 | # |
| 5 | -# id :integer not null, primary key | ||
| 6 | -# url :string(255) | ||
| 7 | -# project_id :integer | ||
| 8 | -# created_at :datetime not null | ||
| 9 | -# updated_at :datetime not null | ||
| 10 | -# type :string(255) default("ProjectHook") | ||
| 11 | -# service_id :integer | 5 | +# id :integer not null, primary key |
| 6 | +# url :string(255) | ||
| 7 | +# project_id :integer | ||
| 8 | +# created_at :datetime not null | ||
| 9 | +# updated_at :datetime not null | ||
| 10 | +# type :string(255) default("ProjectHook") | ||
| 11 | +# service_id :integer | ||
| 12 | +# push_events :boolean default(TRUE), not null | ||
| 13 | +# issues_events :boolean default(FALSE), not null | ||
| 14 | +# merge_requests_events :boolean default(FALSE), not null | ||
| 12 | # | 15 | # |
| 13 | 16 | ||
| 14 | require "spec_helper" | 17 | require "spec_helper" |
spec/models/web_hook_spec.rb
| @@ -2,13 +2,16 @@ | @@ -2,13 +2,16 @@ | ||
| 2 | # | 2 | # |
| 3 | # Table name: web_hooks | 3 | # Table name: web_hooks |
| 4 | # | 4 | # |
| 5 | -# id :integer not null, primary key | ||
| 6 | -# url :string(255) | ||
| 7 | -# project_id :integer | ||
| 8 | -# created_at :datetime not null | ||
| 9 | -# updated_at :datetime not null | ||
| 10 | -# type :string(255) default("ProjectHook") | ||
| 11 | -# service_id :integer | 5 | +# id :integer not null, primary key |
| 6 | +# url :string(255) | ||
| 7 | +# project_id :integer | ||
| 8 | +# created_at :datetime not null | ||
| 9 | +# updated_at :datetime not null | ||
| 10 | +# type :string(255) default("ProjectHook") | ||
| 11 | +# service_id :integer | ||
| 12 | +# push_events :boolean default(TRUE), not null | ||
| 13 | +# issues_events :boolean default(FALSE), not null | ||
| 14 | +# merge_requests_events :boolean default(FALSE), not null | ||
| 12 | # | 15 | # |
| 13 | 16 | ||
| 14 | require 'spec_helper' | 17 | require 'spec_helper' |
spec/observers/merge_request_observer_spec.rb
| @@ -4,7 +4,7 @@ describe MergeRequestObserver do | @@ -4,7 +4,7 @@ describe MergeRequestObserver do | ||
| 4 | let(:some_user) { create :user } | 4 | let(:some_user) { create :user } |
| 5 | let(:assignee) { create :user } | 5 | let(:assignee) { create :user } |
| 6 | let(:author) { create :user } | 6 | let(:author) { create :user } |
| 7 | - let(:mr_mock) { double(:merge_request, id: 42, assignee: assignee, author: author) } | 7 | + let(:mr_mock) { double(:merge_request, id: 42, assignee: assignee, author: author).as_null_object } |
| 8 | let(:assigned_mr) { create(:merge_request, assignee: assignee, author: author, target_project: create(:project)) } | 8 | let(:assigned_mr) { create(:merge_request, assignee: assignee, author: author, target_project: create(:project)) } |
| 9 | let(:unassigned_mr) { create(:merge_request, author: author, target_project: create(:project)) } | 9 | let(:unassigned_mr) { create(:merge_request, author: author, target_project: create(:project)) } |
| 10 | let(:closed_assigned_mr) { create(:closed_merge_request, assignee: assignee, author: author, target_project: create(:project)) } | 10 | let(:closed_assigned_mr) { create(:closed_merge_request, assignee: assignee, author: author, target_project: create(:project)) } |
| @@ -0,0 +1,132 @@ | @@ -0,0 +1,132 @@ | ||
| 1 | +require 'spec_helper' | ||
| 2 | + | ||
| 3 | +describe API::API, 'ProjectHooks' do | ||
| 4 | + include ApiHelpers | ||
| 5 | + before(:each) { enable_observers } | ||
| 6 | + after(:each) { disable_observers } | ||
| 7 | + | ||
| 8 | + let(:user) { create(:user) } | ||
| 9 | + let(:user3) { create(:user) } | ||
| 10 | + let!(:project) { create(:project_with_code, creator_id: user.id, namespace: user.namespace) } | ||
| 11 | + let!(:hook) { create(:project_hook, project: project, url: "http://example.com") } | ||
| 12 | + | ||
| 13 | + before do | ||
| 14 | + project.team << [user, :master] | ||
| 15 | + project.team << [user3, :developer] | ||
| 16 | + end | ||
| 17 | + | ||
| 18 | + describe "GET /projects/:id/hooks" do | ||
| 19 | + context "authorized user" do | ||
| 20 | + it "should return project hooks" do | ||
| 21 | + get api("/projects/#{project.id}/hooks", user) | ||
| 22 | + response.status.should == 200 | ||
| 23 | + | ||
| 24 | + json_response.should be_an Array | ||
| 25 | + json_response.count.should == 1 | ||
| 26 | + json_response.first['url'].should == "http://example.com" | ||
| 27 | + end | ||
| 28 | + end | ||
| 29 | + | ||
| 30 | + context "unauthorized user" do | ||
| 31 | + it "should not access project hooks" do | ||
| 32 | + get api("/projects/#{project.id}/hooks", user3) | ||
| 33 | + response.status.should == 403 | ||
| 34 | + end | ||
| 35 | + end | ||
| 36 | + end | ||
| 37 | + | ||
| 38 | + describe "GET /projects/:id/hooks/:hook_id" do | ||
| 39 | + context "authorized user" do | ||
| 40 | + it "should return a project hook" do | ||
| 41 | + get api("/projects/#{project.id}/hooks/#{hook.id}", user) | ||
| 42 | + response.status.should == 200 | ||
| 43 | + json_response['url'].should == hook.url | ||
| 44 | + end | ||
| 45 | + | ||
| 46 | + it "should return a 404 error if hook id is not available" do | ||
| 47 | + get api("/projects/#{project.id}/hooks/1234", user) | ||
| 48 | + response.status.should == 404 | ||
| 49 | + end | ||
| 50 | + end | ||
| 51 | + | ||
| 52 | + context "unauthorized user" do | ||
| 53 | + it "should not access an existing hook" do | ||
| 54 | + get api("/projects/#{project.id}/hooks/#{hook.id}", user3) | ||
| 55 | + response.status.should == 403 | ||
| 56 | + end | ||
| 57 | + end | ||
| 58 | + | ||
| 59 | + it "should return a 404 error if hook id is not available" do | ||
| 60 | + get api("/projects/#{project.id}/hooks/1234", user) | ||
| 61 | + response.status.should == 404 | ||
| 62 | + end | ||
| 63 | + end | ||
| 64 | + | ||
| 65 | + describe "POST /projects/:id/hooks" do | ||
| 66 | + it "should add hook to project" do | ||
| 67 | + expect { | ||
| 68 | + post api("/projects/#{project.id}/hooks", user), | ||
| 69 | + url: "http://example.com", issues_events: true | ||
| 70 | + }.to change {project.hooks.count}.by(1) | ||
| 71 | + response.status.should == 201 | ||
| 72 | + end | ||
| 73 | + | ||
| 74 | + it "should return a 400 error if url not given" do | ||
| 75 | + post api("/projects/#{project.id}/hooks", user) | ||
| 76 | + response.status.should == 400 | ||
| 77 | + end | ||
| 78 | + | ||
| 79 | + it "should return a 422 error if url not valid" do | ||
| 80 | + post api("/projects/#{project.id}/hooks", user), "url" => "ftp://example.com" | ||
| 81 | + response.status.should == 422 | ||
| 82 | + end | ||
| 83 | + end | ||
| 84 | + | ||
| 85 | + describe "PUT /projects/:id/hooks/:hook_id" do | ||
| 86 | + it "should update an existing project hook" do | ||
| 87 | + put api("/projects/#{project.id}/hooks/#{hook.id}", user), | ||
| 88 | + url: 'http://example.org', push_events: false | ||
| 89 | + response.status.should == 200 | ||
| 90 | + json_response['url'].should == 'http://example.org' | ||
| 91 | + end | ||
| 92 | + | ||
| 93 | + it "should return 404 error if hook id not found" do | ||
| 94 | + put api("/projects/#{project.id}/hooks/1234", user), url: 'http://example.org' | ||
| 95 | + response.status.should == 404 | ||
| 96 | + end | ||
| 97 | + | ||
| 98 | + it "should return 400 error if url is not given" do | ||
| 99 | + put api("/projects/#{project.id}/hooks/#{hook.id}", user) | ||
| 100 | + response.status.should == 400 | ||
| 101 | + end | ||
| 102 | + | ||
| 103 | + it "should return a 422 error if url is not valid" do | ||
| 104 | + put api("/projects/#{project.id}/hooks/#{hook.id}", user), url: 'ftp://example.com' | ||
| 105 | + response.status.should == 422 | ||
| 106 | + end | ||
| 107 | + end | ||
| 108 | + | ||
| 109 | + describe "DELETE /projects/:id/hooks/:hook_id" do | ||
| 110 | + it "should delete hook from project" do | ||
| 111 | + expect { | ||
| 112 | + delete api("/projects/#{project.id}/hooks/#{hook.id}", user) | ||
| 113 | + }.to change {project.hooks.count}.by(-1) | ||
| 114 | + response.status.should == 200 | ||
| 115 | + end | ||
| 116 | + | ||
| 117 | + it "should return success when deleting hook" do | ||
| 118 | + delete api("/projects/#{project.id}/hooks/#{hook.id}", user) | ||
| 119 | + response.status.should == 200 | ||
| 120 | + end | ||
| 121 | + | ||
| 122 | + it "should return success when deleting non existent hook" do | ||
| 123 | + delete api("/projects/#{project.id}/hooks/42", user) | ||
| 124 | + response.status.should == 200 | ||
| 125 | + end | ||
| 126 | + | ||
| 127 | + it "should return a 405 error if hook id not given" do | ||
| 128 | + delete api("/projects/#{project.id}/hooks", user) | ||
| 129 | + response.status.should == 405 | ||
| 130 | + end | ||
| 131 | + end | ||
| 132 | +end |
spec/requests/api/projects_spec.rb
| @@ -10,7 +10,6 @@ describe API::API do | @@ -10,7 +10,6 @@ describe API::API do | ||
| 10 | let(:user3) { create(:user) } | 10 | let(:user3) { create(:user) } |
| 11 | let(:admin) { create(:admin) } | 11 | let(:admin) { create(:admin) } |
| 12 | let!(:project) { create(:project_with_code, creator_id: user.id, namespace: user.namespace) } | 12 | let!(:project) { create(:project_with_code, creator_id: user.id, namespace: user.namespace) } |
| 13 | - let!(:hook) { create(:project_hook, project: project, url: "http://example.com") } | ||
| 14 | let!(:snippet) { create(:project_snippet, author: user, project: project, title: 'example') } | 13 | let!(:snippet) { create(:project_snippet, author: user, project: project, title: 'example') } |
| 15 | let!(:users_project) { create(:users_project, user: user, project: project, project_access: UsersProject::MASTER) } | 14 | let!(:users_project) { create(:users_project, user: user, project: project, project_access: UsersProject::MASTER) } |
| 16 | let!(:users_project2) { create(:users_project, user: user3, project: project, project_access: UsersProject::DEVELOPER) } | 15 | let!(:users_project2) { create(:users_project, user: user3, project: project, project_access: UsersProject::DEVELOPER) } |
| @@ -439,121 +438,6 @@ describe API::API do | @@ -439,121 +438,6 @@ describe API::API do | ||
| 439 | end | 438 | end |
| 440 | end | 439 | end |
| 441 | 440 | ||
| 442 | - describe "GET /projects/:id/hooks" do | ||
| 443 | - context "authorized user" do | ||
| 444 | - it "should return project hooks" do | ||
| 445 | - get api("/projects/#{project.id}/hooks", user) | ||
| 446 | - response.status.should == 200 | ||
| 447 | - | ||
| 448 | - json_response.should be_an Array | ||
| 449 | - json_response.count.should == 1 | ||
| 450 | - json_response.first['url'].should == "http://example.com" | ||
| 451 | - end | ||
| 452 | - end | ||
| 453 | - | ||
| 454 | - context "unauthorized user" do | ||
| 455 | - it "should not access project hooks" do | ||
| 456 | - get api("/projects/#{project.id}/hooks", user3) | ||
| 457 | - response.status.should == 403 | ||
| 458 | - end | ||
| 459 | - end | ||
| 460 | - end | ||
| 461 | - | ||
| 462 | - describe "GET /projects/:id/hooks/:hook_id" do | ||
| 463 | - context "authorized user" do | ||
| 464 | - it "should return a project hook" do | ||
| 465 | - get api("/projects/#{project.id}/hooks/#{hook.id}", user) | ||
| 466 | - response.status.should == 200 | ||
| 467 | - json_response['url'].should == hook.url | ||
| 468 | - end | ||
| 469 | - | ||
| 470 | - it "should return a 404 error if hook id is not available" do | ||
| 471 | - get api("/projects/#{project.id}/hooks/1234", user) | ||
| 472 | - response.status.should == 404 | ||
| 473 | - end | ||
| 474 | - end | ||
| 475 | - | ||
| 476 | - context "unauthorized user" do | ||
| 477 | - it "should not access an existing hook" do | ||
| 478 | - get api("/projects/#{project.id}/hooks/#{hook.id}", user3) | ||
| 479 | - response.status.should == 403 | ||
| 480 | - end | ||
| 481 | - end | ||
| 482 | - | ||
| 483 | - it "should return a 404 error if hook id is not available" do | ||
| 484 | - get api("/projects/#{project.id}/hooks/1234", user) | ||
| 485 | - response.status.should == 404 | ||
| 486 | - end | ||
| 487 | - end | ||
| 488 | - | ||
| 489 | - describe "POST /projects/:id/hooks" do | ||
| 490 | - it "should add hook to project" do | ||
| 491 | - expect { | ||
| 492 | - post api("/projects/#{project.id}/hooks", user), | ||
| 493 | - url: "http://example.com" | ||
| 494 | - }.to change {project.hooks.count}.by(1) | ||
| 495 | - response.status.should == 201 | ||
| 496 | - end | ||
| 497 | - | ||
| 498 | - it "should return a 400 error if url not given" do | ||
| 499 | - post api("/projects/#{project.id}/hooks", user) | ||
| 500 | - response.status.should == 400 | ||
| 501 | - end | ||
| 502 | - | ||
| 503 | - it "should return a 422 error if url not valid" do | ||
| 504 | - post api("/projects/#{project.id}/hooks", user), "url" => "ftp://example.com" | ||
| 505 | - response.status.should == 422 | ||
| 506 | - end | ||
| 507 | - end | ||
| 508 | - | ||
| 509 | - describe "PUT /projects/:id/hooks/:hook_id" do | ||
| 510 | - it "should update an existing project hook" do | ||
| 511 | - put api("/projects/#{project.id}/hooks/#{hook.id}", user), | ||
| 512 | - url: 'http://example.org' | ||
| 513 | - response.status.should == 200 | ||
| 514 | - json_response['url'].should == 'http://example.org' | ||
| 515 | - end | ||
| 516 | - | ||
| 517 | - it "should return 404 error if hook id not found" do | ||
| 518 | - put api("/projects/#{project.id}/hooks/1234", user), url: 'http://example.org' | ||
| 519 | - response.status.should == 404 | ||
| 520 | - end | ||
| 521 | - | ||
| 522 | - it "should return 400 error if url is not given" do | ||
| 523 | - put api("/projects/#{project.id}/hooks/#{hook.id}", user) | ||
| 524 | - response.status.should == 400 | ||
| 525 | - end | ||
| 526 | - | ||
| 527 | - it "should return a 422 error if url is not valid" do | ||
| 528 | - put api("/projects/#{project.id}/hooks/#{hook.id}", user), url: 'ftp://example.com' | ||
| 529 | - response.status.should == 422 | ||
| 530 | - end | ||
| 531 | - end | ||
| 532 | - | ||
| 533 | - describe "DELETE /projects/:id/hooks/:hook_id" do | ||
| 534 | - it "should delete hook from project" do | ||
| 535 | - expect { | ||
| 536 | - delete api("/projects/#{project.id}/hooks/#{hook.id}", user) | ||
| 537 | - }.to change {project.hooks.count}.by(-1) | ||
| 538 | - response.status.should == 200 | ||
| 539 | - end | ||
| 540 | - | ||
| 541 | - it "should return success when deleting hook" do | ||
| 542 | - delete api("/projects/#{project.id}/hooks/#{hook.id}", user) | ||
| 543 | - response.status.should == 200 | ||
| 544 | - end | ||
| 545 | - | ||
| 546 | - it "should return success when deleting non existent hook" do | ||
| 547 | - delete api("/projects/#{project.id}/hooks/42", user) | ||
| 548 | - response.status.should == 200 | ||
| 549 | - end | ||
| 550 | - | ||
| 551 | - it "should return a 405 error if hook id not given" do | ||
| 552 | - delete api("/projects/#{project.id}/hooks", user) | ||
| 553 | - response.status.should == 405 | ||
| 554 | - end | ||
| 555 | - end | ||
| 556 | - | ||
| 557 | describe "GET /projects/:id/snippets" do | 441 | describe "GET /projects/:id/snippets" do |
| 558 | it "should return an array of project snippets" do | 442 | it "should return an array of project snippets" do |
| 559 | get api("/projects/#{project.id}/snippets", user) | 443 | get api("/projects/#{project.id}/snippets", user) |
spec/services/git_push_service_spec.rb
| @@ -74,38 +74,19 @@ describe GitPushService do | @@ -74,38 +74,19 @@ describe GitPushService do | ||
| 74 | end | 74 | end |
| 75 | 75 | ||
| 76 | describe "Web Hooks" do | 76 | describe "Web Hooks" do |
| 77 | - context "with web hooks" do | ||
| 78 | - before do | ||
| 79 | - @project_hook = create(:project_hook) | ||
| 80 | - @project_hook_2 = create(:project_hook) | ||
| 81 | - project.hooks << [@project_hook, @project_hook_2] | ||
| 82 | - | ||
| 83 | - stub_request(:post, @project_hook.url) | ||
| 84 | - stub_request(:post, @project_hook_2.url) | ||
| 85 | - end | ||
| 86 | - | ||
| 87 | - it "executes multiple web hook" do | ||
| 88 | - @project_hook.should_receive(:async_execute).once | ||
| 89 | - @project_hook_2.should_receive(:async_execute).once | ||
| 90 | - | ||
| 91 | - service.execute(project, user, @oldrev, @newrev, @ref) | ||
| 92 | - end | ||
| 93 | - end | ||
| 94 | - | ||
| 95 | context "execute web hooks" do | 77 | context "execute web hooks" do |
| 96 | - before do | ||
| 97 | - @project_hook = create(:project_hook) | ||
| 98 | - project.hooks << [@project_hook] | ||
| 99 | - stub_request(:post, @project_hook.url) | ||
| 100 | - end | ||
| 101 | - | ||
| 102 | it "when pushing a branch for the first time" do | 78 | it "when pushing a branch for the first time" do |
| 103 | - @project_hook.should_receive(:async_execute) | 79 | + project.should_receive(:execute_hooks) |
| 104 | service.execute(project, user, @blankrev, 'newrev', 'refs/heads/master') | 80 | service.execute(project, user, @blankrev, 'newrev', 'refs/heads/master') |
| 105 | end | 81 | end |
| 106 | 82 | ||
| 83 | + it "when pushing new commits to existing branch" do | ||
| 84 | + project.should_receive(:execute_hooks) | ||
| 85 | + service.execute(project, user, 'oldrev', 'newrev', 'refs/heads/master') | ||
| 86 | + end | ||
| 87 | + | ||
| 107 | it "when pushing tags" do | 88 | it "when pushing tags" do |
| 108 | - @project_hook.should_not_receive(:async_execute) | 89 | + project.should_not_receive(:execute_hooks) |
| 109 | service.execute(project, user, 'newrev', 'newrev', 'refs/tags/v1.0.0') | 90 | service.execute(project, user, 'newrev', 'newrev', 'refs/tags/v1.0.0') |
| 110 | end | 91 | end |
| 111 | end | 92 | end |