diff options
-rw-r--r-- | app/models/hooks/system_hook.rb | 2 | ||||
-rw-r--r-- | app/models/hooks/web_hook.rb | 1 | ||||
-rw-r--r-- | app/workers/post_receive.rb | 25 | ||||
-rw-r--r-- | db/migrate/20170503023315_add_repository_update_events_to_web_hooks.rb | 15 | ||||
-rw-r--r-- | db/schema.rb | 1 | ||||
-rw-r--r-- | lib/gitlab/data_builder/repository.rb | 35 | ||||
-rw-r--r-- | lib/gitlab/git_post_receive.rb | 10 | ||||
-rw-r--r-- | spec/lib/gitlab/import_export/safe_model_attributes.yml | 1 | ||||
-rw-r--r-- | spec/models/hooks/system_hook_spec.rb | 8 | ||||
-rw-r--r-- | spec/workers/post_receive_spec.rb | 23 |
10 files changed, 117 insertions, 4 deletions
diff --git a/app/models/hooks/system_hook.rb b/app/models/hooks/system_hook.rb index 777bad1e724..f97debb7113 100644 --- a/app/models/hooks/system_hook.rb +++ b/app/models/hooks/system_hook.rb @@ -1,4 +1,6 @@ class SystemHook < WebHook + scope :repository_update_hooks, -> { where(repository_update_events: true) } + def async_execute(data, hook_name) Sidekiq::Client.enqueue(SystemHookWorker, id, data, hook_name) end diff --git a/app/models/hooks/web_hook.rb b/app/models/hooks/web_hook.rb index 22a177ed367..7cf03aabd6f 100644 --- a/app/models/hooks/web_hook.rb +++ b/app/models/hooks/web_hook.rb @@ -10,6 +10,7 @@ class WebHook < ActiveRecord::Base default_value_for :tag_push_events, false default_value_for :build_events, false default_value_for :pipeline_events, false + default_value_for :repository_update_events, false default_value_for :enable_ssl_verification, true scope :push_hooks, -> { where(push_events: true) } diff --git a/app/workers/post_receive.rb b/app/workers/post_receive.rb index 127d8dfbb61..c29571d3c62 100644 --- a/app/workers/post_receive.rb +++ b/app/workers/post_receive.rb @@ -20,13 +20,32 @@ class PostReceive # Nothing defined here yet. else process_project_changes(post_received) + process_repository_update(post_received) end end - def process_project_changes(post_received) - post_received.changes.each do |change| - oldrev, newrev, ref = change.strip.split(' ') + def process_repository_update(post_received) + changes = [] + refs = Set.new + + post_received.changes_refs do |oldrev, newrev, ref| + @user ||= post_received.identify(newrev) + unless @user + log("Triggered hook for non-existing user \"#{post_received.identifier}\"") + return false + end + + changes << Gitlab::DataBuilder::Repository.single_change(oldrev, newrev, ref) + refs << ref + end + + hook_data = Gitlab::DataBuilder::Repository.update(post_received.project, @user, changes, refs.to_a) + SystemHooksService.new.execute_hooks(hook_data, :repository_update_hooks) + end + + def process_project_changes(post_received) + post_received.changes_refs do |oldrev, newrev, ref| @user ||= post_received.identify(newrev) unless @user diff --git a/db/migrate/20170503023315_add_repository_update_events_to_web_hooks.rb b/db/migrate/20170503023315_add_repository_update_events_to_web_hooks.rb new file mode 100644 index 00000000000..0faea87a962 --- /dev/null +++ b/db/migrate/20170503023315_add_repository_update_events_to_web_hooks.rb @@ -0,0 +1,15 @@ +class AddRepositoryUpdateEventsToWebHooks < ActiveRecord::Migration + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + + disable_ddl_transaction! + + def up + add_column_with_default :web_hooks, :repository_update_events, :boolean, default: false, allow_null: false + end + + def down + remove_column :web_hooks, :repository_update_events + end +end diff --git a/db/schema.rb b/db/schema.rb index 60077ffd812..65eaccf766a 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -1404,6 +1404,7 @@ ActiveRecord::Schema.define(version: 20170508190732) do t.string "token" t.boolean "pipeline_events", default: false, null: false t.boolean "confidential_issues_events", default: false, null: false + t.boolean "repository_update_events", default: false, null: false end add_index "web_hooks", ["project_id"], name: "index_web_hooks_on_project_id", using: :btree diff --git a/lib/gitlab/data_builder/repository.rb b/lib/gitlab/data_builder/repository.rb new file mode 100644 index 00000000000..b42dc052949 --- /dev/null +++ b/lib/gitlab/data_builder/repository.rb @@ -0,0 +1,35 @@ +module Gitlab + module DataBuilder + module Repository + extend self + + # Produce a hash of post-receive data + def update(project, user, changes, refs) + { + event_name: 'repository_update', + + user_id: user.id, + user_name: user.name, + user_email: user.email, + user_avatar: user.avatar_url, + + project_id: project.id, + project: project.hook_attrs, + + changes: changes, + + refs: refs + } + end + + # Produce a hash of partial data for a single change + def single_change(oldrev, newrev, ref) + { + before: oldrev, + after: newrev, + ref: ref + } + end + end + end +end diff --git a/lib/gitlab/git_post_receive.rb b/lib/gitlab/git_post_receive.rb index 0e14253ab4e..742118b76a8 100644 --- a/lib/gitlab/git_post_receive.rb +++ b/lib/gitlab/git_post_receive.rb @@ -13,6 +13,16 @@ module Gitlab super(identifier, project, revision) end + def changes_refs + return enum_for(:changes_refs) unless block_given? + + changes.each do |change| + oldrev, newrev, ref = change.strip.split(' ') + + yield oldrev, newrev, ref + end + end + private def deserialize_changes(changes) diff --git a/spec/lib/gitlab/import_export/safe_model_attributes.yml b/spec/lib/gitlab/import_export/safe_model_attributes.yml index f63fb7aeec6..2b95f76e045 100644 --- a/spec/lib/gitlab/import_export/safe_model_attributes.yml +++ b/spec/lib/gitlab/import_export/safe_model_attributes.yml @@ -317,6 +317,7 @@ ProjectHook: - token - group_id - confidential_issues_events +- repository_update_events ProtectedBranch: - id - project_id diff --git a/spec/models/hooks/system_hook_spec.rb b/spec/models/hooks/system_hook_spec.rb index 8acec805584..a9e3ac3b679 100644 --- a/spec/models/hooks/system_hook_spec.rb +++ b/spec/models/hooks/system_hook_spec.rb @@ -105,4 +105,12 @@ describe SystemHook, models: true do ).once end end + + describe '.repository_update_hooks' do + it 'returns hooks for repository update events only' do + hook = create(:system_hook, repository_update_events: true) + create(:system_hook, repository_update_events: false) + expect(SystemHook.repository_update_hooks).to eq([hook]) + end + end end diff --git a/spec/workers/post_receive_spec.rb b/spec/workers/post_receive_spec.rb index 0260416dbe2..3289c2df1fb 100644 --- a/spec/workers/post_receive_spec.rb +++ b/spec/workers/post_receive_spec.rb @@ -9,7 +9,7 @@ describe PostReceive do let(:key) { create(:key, user: project.owner) } let(:key_id) { key.shell_id } - context "as a resque worker" do + context "as a sidekiq worker" do it "reponds to #perform" do expect(described_class.new).to respond_to(:perform) end @@ -93,6 +93,27 @@ describe PostReceive do end end + describe '#process_repository_update' do + let(:changes) {'123456 789012 refs/heads/tést'} + let(:fake_hook_data) do + { event_name: 'repository_update' } + end + + before do + allow_any_instance_of(Gitlab::GitPostReceive).to receive(:identify).and_return(project.owner) + allow_any_instance_of(Gitlab::DataBuilder::Repository).to receive(:update).and_return(fake_hook_data) + # silence hooks so we can isolate + allow_any_instance_of(Key).to receive(:post_create_hook).and_return(true) + allow(subject).to receive(:process_project_changes).and_return(true) + end + + it 'calls SystemHooksService' do + expect_any_instance_of(SystemHooksService).to receive(:execute_hooks).with(fake_hook_data, :repository_update_hooks).and_return(true) + + subject.perform(pwd(project), key_id, base64_changes) + end + end + context "webhook" do it "fetches the correct project" do expect(Project).to receive(:find_by).with(id: project.id.to_s) |