Merge branch 'zj-pipeline-schedule-owner' into 'master'

Foreign key for Pipeline schedule owner

Closes #31932

See merge request !11233
This commit is contained in:
Kamil Trzciński 2017-05-16 09:18:55 +00:00
commit b0ce5e1e30
7 changed files with 93 additions and 22 deletions

View File

@ -28,10 +28,18 @@ module Ci
!active? !active?
end end
def deactivate!
update_attribute(:active, false)
end
def importing_or_inactive? def importing_or_inactive?
importing? || inactive? importing? || inactive?
end end
def runnable_by_owner?
Ability.allowed?(owner, :create_pipeline, project)
end
def set_next_run_at def set_next_run_at
self.next_run_at = Gitlab::Ci::CronParser.new(cron, cron_timezone).next_time_from(Time.now) self.next_run_at = Gitlab::Ci::CronParser.new(cron, cron_timezone).next_time_from(Time.now)
end end

View File

@ -3,8 +3,14 @@ class PipelineScheduleWorker
include CronjobQueue include CronjobQueue
def perform def perform
Ci::PipelineSchedule.active.where("next_run_at < ?", Time.now).find_each do |schedule| Ci::PipelineSchedule.active.where("next_run_at < ?", Time.now)
.preload(:owner, :project).find_each do |schedule|
begin begin
unless schedule.runnable_by_owner?
schedule.deactivate!
next
end
Ci::CreatePipelineService.new(schedule.project, Ci::CreatePipelineService.new(schedule.project,
schedule.owner, schedule.owner,
ref: schedule.ref) ref: schedule.ref)

View File

@ -0,0 +1,4 @@
---
title: Add foreign key for pipeline schedule owner
merge_request: 11233
author:

View File

@ -0,0 +1,35 @@
class AddForeignKeyOnPipelineScheduleOwner < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
execute <<-SQL
UPDATE ci_pipeline_schedules
SET owner_id = NULL
WHERE NOT EXISTS (
SELECT true
FROM users
WHERE ci_pipeline_schedules.owner_id = users.id
)
SQL
add_concurrent_foreign_key(:ci_pipeline_schedules, :users, column: :owner_id, on_delete: on_delete)
end
def down
remove_foreign_key(:ci_pipeline_schedules, column: :owner_id)
end
private
def on_delete
if Gitlab::Database.mysql?
:nullify
else
'SET NULL'
end
end
end

View File

@ -11,7 +11,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20170508190732) do ActiveRecord::Schema.define(version: 20170510101043) do
# These are extensions that must be enabled in order to support this database # These are extensions that must be enabled in order to support this database
enable_extension "plpgsql" enable_extension "plpgsql"
@ -1416,6 +1416,7 @@ ActiveRecord::Schema.define(version: 20170508190732) do
add_foreign_key "chat_teams", "namespaces", on_delete: :cascade add_foreign_key "chat_teams", "namespaces", on_delete: :cascade
add_foreign_key "ci_builds", "ci_pipelines", column: "auto_canceled_by_id", name: "fk_a2141b1522", on_delete: :nullify add_foreign_key "ci_builds", "ci_pipelines", column: "auto_canceled_by_id", name: "fk_a2141b1522", on_delete: :nullify
add_foreign_key "ci_pipeline_schedules", "projects", name: "fk_8ead60fcc4", on_delete: :cascade add_foreign_key "ci_pipeline_schedules", "projects", name: "fk_8ead60fcc4", on_delete: :cascade
add_foreign_key "ci_pipeline_schedules", "users", column: "owner_id", name: "fk_9ea99f58d2", on_delete: :nullify
add_foreign_key "ci_pipelines", "ci_pipeline_schedules", column: "pipeline_schedule_id", name: "fk_3d34ab2e06", on_delete: :nullify add_foreign_key "ci_pipelines", "ci_pipeline_schedules", column: "pipeline_schedule_id", name: "fk_3d34ab2e06", on_delete: :nullify
add_foreign_key "ci_pipelines", "ci_pipelines", column: "auto_canceled_by_id", name: "fk_262d4c2d19", on_delete: :nullify add_foreign_key "ci_pipelines", "ci_pipelines", column: "auto_canceled_by_id", name: "fk_262d4c2d19", on_delete: :nullify
add_foreign_key "ci_trigger_requests", "ci_triggers", column: "trigger_id", name: "fk_b8ec8b7245", on_delete: :cascade add_foreign_key "ci_trigger_requests", "ci_triggers", column: "trigger_id", name: "fk_b8ec8b7245", on_delete: :cascade

View File

@ -35,6 +35,10 @@ To change the Sidekiq worker's frequency, you have to edit the `trigger_schedule
value in your `gitlab.rb` and restart GitLab. The Sidekiq worker's configuration value in your `gitlab.rb` and restart GitLab. The Sidekiq worker's configuration
on GiLab.com is able to be looked up at [here](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/config/gitlab.yml.example#L185). on GiLab.com is able to be looked up at [here](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/config/gitlab.yml.example#L185).
- Cron notation is parsed by [Rufus-Scheduler](https://github.com/jmettraux/rufus-scheduler). - Cron notation is parsed by [Rufus-Scheduler](https://github.com/jmettraux/rufus-scheduler).
- When the owner of the schedule does not have the ability to create pipelines
anymore, due to e.g. being blocked or removed from the project, the schedule is
deactivated. Another user can take ownership and activate it, so the schedule is
run again.
[ce-10533]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/10533 [ce-10533]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/10533
[ce-10853]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/10853 [ce-10853]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/10853

View File

@ -11,40 +11,53 @@ describe PipelineScheduleWorker do
end end
before do before do
project.add_master(user)
stub_ci_pipeline_to_return_yaml_file stub_ci_pipeline_to_return_yaml_file
pipeline_schedule.update_column(:next_run_at, 1.day.ago)
end end
context 'when there is a scheduled pipeline within next_run_at' do context 'when the schedule is runnable by the user' do
let(:next_run_at) { 2.days.ago }
before do before do
pipeline_schedule.update_column(:next_run_at, next_run_at) project.add_master(user)
end end
it 'creates a new pipeline' do context 'when there is a scheduled pipeline within next_run_at' do
expect { subject }.to change { project.pipelines.count }.by(1) it 'creates a new pipeline' do
expect { subject }.to change { project.pipelines.count }.by(1)
end
it 'updates the next_run_at field' do
subject
expect(pipeline_schedule.reload.next_run_at).to be > Time.now
end
it 'sets the schedule on the pipeline' do
subject
expect(project.pipelines.last.pipeline_schedule).to eq(pipeline_schedule)
end
end end
it 'updates the next_run_at field' do context 'inactive schedule' do
subject before do
pipeline_schedule.deactivate!
end
expect(pipeline_schedule.reload.next_run_at).to be > Time.now it 'does not creates a new pipeline' do
end expect { subject }.not_to change { project.pipelines.count }
end
it 'sets the schedule on the pipeline' do
subject
expect(project.pipelines.last.pipeline_schedule).to eq(pipeline_schedule)
end end
end end
context 'inactive schedule' do context 'when the schedule is not runnable by the user' do
before do it 'deactivates the schedule' do
pipeline_schedule.update(active: false) subject
expect(pipeline_schedule.reload.active).to be_falsy
end end
it 'does not creates a new pipeline' do it 'does not schedule a pipeline' do
expect { subject }.not_to change { project.pipelines.count } expect { subject }.not_to change { project.pipelines.count }
end end
end end