Commit 4eacd587 authored by Douwe Maan's avatar Douwe Maan

Merge branch 'fj-3821-push-web-hook-event' into 'master'

Use `push` web hook events for pull mirroring

Closes #3821

See merge request gitlab-org/gitlab-ee!3453
parents 1724b6a3 9cdcc230
---
title: Added enpoint that triggers the pull mirroring process
merge_request: 3453
author:
type: added
...@@ -1427,3 +1427,15 @@ Read more in the [Branches](branches.md) documentation. ...@@ -1427,3 +1427,15 @@ Read more in the [Branches](branches.md) documentation.
## Project members ## Project members
Read more in the [Project members](members.md) documentation. Read more in the [Project members](members.md) documentation.
## Start the pull mirroring process for a Project
> Introduced in GitLab 10.3. **Note:** Available in [GitLab Enterprise Edition Starter](https://about.gitlab.com/gitlab-ee).
```
POST /projects/:id/mirror/pull
```
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
...@@ -2,8 +2,7 @@ class Projects::MirrorsController < Projects::ApplicationController ...@@ -2,8 +2,7 @@ class Projects::MirrorsController < Projects::ApplicationController
include RepositorySettingsRedirect include RepositorySettingsRedirect
include SafeMirrorParams include SafeMirrorParams
# Authorize # Authorize
before_action :authorize_admin_project!, except: [:update_now] before_action :authorize_admin_project!
before_action :authorize_push_code!, only: [:update_now]
before_action :remote_mirror, only: [:update] before_action :remote_mirror, only: [:update]
before_action :check_repository_mirrors_available! before_action :check_repository_mirrors_available!
......
module EE module EE
module ProjectsHelper module ProjectsHelper
def can_force_update_mirror?(project)
return true if project.mirror_hard_failed?
return true unless project.mirror_last_update_at
Time.now - project.mirror_last_update_at >= 5.minutes
end
def can_change_push_rule?(push_rule, rule) def can_change_push_rule?(push_rule, rule)
return true if push_rule.global? return true if push_rule.global?
......
...@@ -229,6 +229,8 @@ module EE ...@@ -229,6 +229,8 @@ module EE
end end
def force_import_job! def force_import_job!
return if scheduled_mirror? || updating_mirror?
mirror_data = self.mirror_data mirror_data = self.mirror_data
mirror_data.set_next_execution_to_now mirror_data.set_next_execution_to_now
......
...@@ -8,11 +8,6 @@ ...@@ -8,11 +8,6 @@
%span.btn.disabled %span.btn.disabled
= icon("refresh spin") = icon("refresh spin")
Updating&hellip; Updating&hellip;
- elsif !can_force_update_mirror?(@project)
%span.btn.disabled{ data: { toggle: 'tooltip', placement: 'auto top' }, style: 'cursor: default',
title: 'You can only force update once every five minutes.' }
= icon("refresh")
Update Now
- else - else
= link_to update_now_project_mirror_path(@project), method: :post, class: 'btn' do = link_to update_now_project_mirror_path(@project), method: :post, class: 'btn' do
= icon("refresh") = icon("refresh")
......
...@@ -477,6 +477,17 @@ module API ...@@ -477,6 +477,17 @@ module API
conflict!(error.message) conflict!(error.message)
end end
end end
desc 'Triggers a pull mirror operation'
post ":id/mirror/pull" do
authorize_admin_project
return render_api_error!('The project is not mirrored', 400) unless user_project.mirror?
user_project.force_import_job!
status 200
end
end end
end end
end end
...@@ -61,6 +61,10 @@ FactoryGirl.define do ...@@ -61,6 +61,10 @@ FactoryGirl.define do
visibility_level Gitlab::VisibilityLevel::PRIVATE visibility_level Gitlab::VisibilityLevel::PRIVATE
end end
trait :import_none do
import_status :none
end
trait :import_scheduled do trait :import_scheduled do
import_status :scheduled import_status :scheduled
......
...@@ -1932,6 +1932,146 @@ describe API::Projects do ...@@ -1932,6 +1932,146 @@ describe API::Projects do
end end
end end
describe 'POST /projects/:id/mirror/pull' do
context 'when the project is not mirrored' do
it 'returns error' do
allow(project).to receive(:mirror?).and_return(false)
post api("/projects/#{project.id}/mirror/pull", user)
expect(response).to have_gitlab_http_status(400)
end
end
context 'when the project is mirrored' do
before do
allow_any_instance_of(Projects::UpdateMirrorService).to receive(:execute).and_return(status: :success)
end
context 'when import state is' do
def project_in_state(state)
project = create(:project, :repository, :mirror, state, namespace: user.namespace)
project.mirror_data.update_attributes(next_execution_timestamp: 10.minutes.from_now)
project
end
it 'none it triggers the pull mirroring operation' do
project = project_in_state(:import_none)
expect(UpdateAllMirrorsWorker).to receive(:perform_async).once
post api("/projects/#{project.id}/mirror/pull", user)
expect(response).to have_gitlab_http_status(200)
end
it 'failed it triggers the pull mirroring operation' do
project = project_in_state(:import_failed)
expect(UpdateAllMirrorsWorker).to receive(:perform_async).once
post api("/projects/#{project.id}/mirror/pull", user)
expect(response).to have_gitlab_http_status(200)
end
it 'finished it triggers the pull mirroring operation' do
project = project_in_state(:import_finished)
expect(UpdateAllMirrorsWorker).to receive(:perform_async).once
post api("/projects/#{project.id}/mirror/pull", user)
expect(response).to have_gitlab_http_status(200)
end
it 'scheduled does not trigger the pull mirroring operation and returns 200' do
project = project_in_state(:import_scheduled)
expect(UpdateAllMirrorsWorker).not_to receive(:perform_async)
post api("/projects/#{project.id}/mirror/pull", user)
expect(response).to have_gitlab_http_status(200)
end
it 'started does not trigger the pull mirroring operation and returns 200' do
project = project_in_state(:import_started)
expect(UpdateAllMirrorsWorker).not_to receive(:perform_async)
post api("/projects/#{project.id}/mirror/pull", user)
expect(response).to have_gitlab_http_status(200)
end
end
context 'when user' do
let(:project_mirrored) { create(:project, :repository, :mirror, :import_finished, namespace: user.namespace) }
def project_member(role, user)
create(:project_member, role, user: user, project: project_mirrored)
end
context 'is unauthenticated' do
it 'returns authentication error' do
post api("/projects/#{project_mirrored.id}/mirror/pull")
expect(response).to have_gitlab_http_status(401)
end
end
context 'is authenticated as developer' do
it 'returns forbidden error' do
project_member(:developer, user3)
post api("/projects/#{project_mirrored.id}/mirror/pull", user3)
expect(response).to have_gitlab_http_status(403)
end
end
context 'is authenticated as reporter' do
it 'returns forbidden error' do
project_member(:reporter, user3)
post api("/projects/#{project_mirrored.id}/mirror/pull", user3)
expect(response).to have_gitlab_http_status(403)
end
end
context 'is authenticated as guest' do
it 'returns forbidden error' do
project_member(:guest, user3)
post api("/projects/#{project_mirrored.id}/mirror/pull", user3)
expect(response).to have_gitlab_http_status(403)
end
end
context 'is authenticated as master' do
it 'triggers the pull mirroring operation' do
project_member(:master, user3)
post api("/projects/#{project_mirrored.id}/mirror/pull", user3)
expect(response).to have_gitlab_http_status(200)
end
end
context 'is authenticated as owner' do
it 'triggers the pull mirroring operation' do
post api("/projects/#{project_mirrored.id}/mirror/pull", user)
expect(response).to have_gitlab_http_status(200)
end
end
end
end
end
it_behaves_like 'custom attributes endpoints', 'projects' do it_behaves_like 'custom attributes endpoints', 'projects' do
let(:attributable) { project } let(:attributable) { project }
let(:other_attributable) { project2 } let(:other_attributable) { project2 }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment