Commit 392c411b authored by Yorick Peterse's avatar Yorick Peterse

Introduce new ProjectCiCdSetting

This model and the corresponding table will be used for storing settings
specific to CI/CD, starting with the "group_runners_enabled" boolean.

The model is called ProjectCiCdSetting and not ProjectCiCdSettings. The
project exporter doesn't like plural model names as it uses "classify"
which turns those into singular (so "ProjectCiCdSettings" becomes
"ProjectCiCdSetting", producing an error if said class is undefined).

The initial work in this commit was done by Dylan Griffith, with most of
the migration work being done by Yorick Peterse.
parent 4fcee586
...@@ -68,6 +68,11 @@ class Project < ActiveRecord::Base ...@@ -68,6 +68,11 @@ class Project < ActiveRecord::Base
after_save :update_project_statistics, if: :namespace_id_changed? after_save :update_project_statistics, if: :namespace_id_changed?
after_create :create_project_feature, unless: :project_feature after_create :create_project_feature, unless: :project_feature
after_create :create_ci_cd_settings,
unless: :ci_cd_settings,
if: proc { ProjectCiCdSetting.available? }
after_create :set_last_activity_at after_create :set_last_activity_at
after_create :set_last_repository_updated_at after_create :set_last_repository_updated_at
after_update :update_forks_visibility_level after_update :update_forks_visibility_level
...@@ -231,6 +236,7 @@ class Project < ActiveRecord::Base ...@@ -231,6 +236,7 @@ class Project < ActiveRecord::Base
has_many :custom_attributes, class_name: 'ProjectCustomAttribute' has_many :custom_attributes, class_name: 'ProjectCustomAttribute'
has_many :project_badges, class_name: 'ProjectBadge' has_many :project_badges, class_name: 'ProjectBadge'
has_one :ci_cd_settings, class_name: 'ProjectCiCdSetting'
accepts_nested_attributes_for :variables, allow_destroy: true accepts_nested_attributes_for :variables, allow_destroy: true
accepts_nested_attributes_for :project_feature, update_only: true accepts_nested_attributes_for :project_feature, update_only: true
......
class ProjectCiCdSetting < ActiveRecord::Base
belongs_to :project
# The version of the schema that first introduced this model/table.
MINIMUM_SCHEMA_VERSION = 20180403035759
def self.available?
@available ||=
ActiveRecord::Migrator.current_version >= MINIMUM_SCHEMA_VERSION
end
def self.reset_column_information
@available = nil
super
end
end
---
title: Introduce new ProjectCiCdSetting model with group_runners_enabled
merge_request: 18144
author:
type: performance
class CreateProjectCiCdSettings < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
unless table_exists?(:project_ci_cd_settings)
create_table(:project_ci_cd_settings) do |t|
t.integer(:project_id, null: false)
t.boolean(:group_runners_enabled, default: true, null: false)
end
end
disable_statement_timeout
# This particular INSERT will take between 10 and 20 seconds.
execute 'INSERT INTO project_ci_cd_settings (project_id) SELECT id FROM projects'
# We add the index and foreign key separately so the above INSERT statement
# takes as little time as possible.
add_concurrent_index(:project_ci_cd_settings, :project_id, unique: true)
add_foreign_key_with_retry
end
def down
drop_table :project_ci_cd_settings
end
def add_foreign_key_with_retry
if Gitlab::Database.mysql?
# When using MySQL we don't support online upgrades, thus projects can't
# be deleted while we are running this migration.
return add_project_id_foreign_key
end
# Between the initial INSERT and the addition of the foreign key some
# projects may have been removed, leaving orphaned rows in our new settings
# table.
loop do
remove_orphaned_settings
begin
add_project_id_foreign_key
break
rescue ActiveRecord::InvalidForeignKey
say 'project_ci_cd_settings contains some orphaned rows, retrying...'
end
end
end
def add_project_id_foreign_key
add_concurrent_foreign_key(:project_ci_cd_settings, :projects, column: :project_id)
end
def remove_orphaned_settings
execute <<~SQL
DELETE FROM project_ci_cd_settings
WHERE NOT EXISTS (
SELECT 1
FROM projects
WHERE projects.id = project_ci_cd_settings.project_id
)
SQL
end
end
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class PopulateMissingProjectCiCdSettings < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
# MySQL does not support online upgrades, thus there can't be any missing
# rows.
return if Gitlab::Database.mysql?
# Projects created after the initial migration but before the code started
# using ProjectCiCdSetting won't have a corresponding row in
# project_ci_cd_settings, so let's fix that.
execute <<~SQL
INSERT INTO project_ci_cd_settings (project_id)
SELECT id
FROM projects
WHERE NOT EXISTS (
SELECT 1
FROM project_ci_cd_settings
WHERE project_ci_cd_settings.project_id = projects.id
)
SQL
end
def down
# There's nothing to revert for this migration.
end
end
...@@ -11,7 +11,7 @@ ...@@ -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: 20180405142733) do ActiveRecord::Schema.define(version: 20180409170809) 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"
...@@ -1432,6 +1432,13 @@ ActiveRecord::Schema.define(version: 20180405142733) do ...@@ -1432,6 +1432,13 @@ ActiveRecord::Schema.define(version: 20180405142733) do
add_index "project_auto_devops", ["project_id"], name: "index_project_auto_devops_on_project_id", unique: true, using: :btree add_index "project_auto_devops", ["project_id"], name: "index_project_auto_devops_on_project_id", unique: true, using: :btree
create_table "project_ci_cd_settings", force: :cascade do |t|
t.integer "project_id", null: false
t.boolean "group_runners_enabled", default: true, null: false
end
add_index "project_ci_cd_settings", ["project_id"], name: "index_project_ci_cd_settings_on_project_id", unique: true, using: :btree
create_table "project_custom_attributes", force: :cascade do |t| create_table "project_custom_attributes", force: :cascade do |t|
t.datetime "created_at", null: false t.datetime "created_at", null: false
t.datetime "updated_at", null: false t.datetime "updated_at", null: false
...@@ -2157,6 +2164,7 @@ ActiveRecord::Schema.define(version: 20180405142733) do ...@@ -2157,6 +2164,7 @@ ActiveRecord::Schema.define(version: 20180405142733) do
add_foreign_key "project_authorizations", "projects", on_delete: :cascade add_foreign_key "project_authorizations", "projects", on_delete: :cascade
add_foreign_key "project_authorizations", "users", on_delete: :cascade add_foreign_key "project_authorizations", "users", on_delete: :cascade
add_foreign_key "project_auto_devops", "projects", on_delete: :cascade add_foreign_key "project_auto_devops", "projects", on_delete: :cascade
add_foreign_key "project_ci_cd_settings", "projects", name: "fk_24c15d2f2e", on_delete: :cascade
add_foreign_key "project_custom_attributes", "projects", on_delete: :cascade add_foreign_key "project_custom_attributes", "projects", on_delete: :cascade
add_foreign_key "project_deploy_tokens", "deploy_tokens", on_delete: :cascade add_foreign_key "project_deploy_tokens", "deploy_tokens", on_delete: :cascade
add_foreign_key "project_deploy_tokens", "projects", on_delete: :cascade add_foreign_key "project_deploy_tokens", "projects", on_delete: :cascade
......
...@@ -66,6 +66,7 @@ project_tree: ...@@ -66,6 +66,7 @@ project_tree:
- :project_feature - :project_feature
- :custom_attributes - :custom_attributes
- :project_badges - :project_badges
- :ci_cd_settings
# Only include the following attributes for the models specified. # Only include the following attributes for the models specified.
included_attributes: included_attributes:
...@@ -75,6 +76,8 @@ included_attributes: ...@@ -75,6 +76,8 @@ included_attributes:
- :username - :username
author: author:
- :name - :name
ci_cd_settings:
- :group_runners_enabled
# Do not include the following attributes for the models specified. # Do not include the following attributes for the models specified.
excluded_attributes: excluded_attributes:
......
...@@ -17,7 +17,8 @@ module Gitlab ...@@ -17,7 +17,8 @@ module Gitlab
auto_devops: :project_auto_devops, auto_devops: :project_auto_devops,
label: :project_label, label: :project_label,
custom_attributes: 'ProjectCustomAttribute', custom_attributes: 'ProjectCustomAttribute',
project_badges: 'Badge' }.freeze project_badges: 'Badge',
ci_cd_settings: 'ProjectCiCdSetting' }.freeze
USER_REFERENCES = %w[author_id assignee_id updated_by_id user_id created_by_id last_edited_by_id merge_user_id resolved_by_id closed_by_id].freeze USER_REFERENCES = %w[author_id assignee_id updated_by_id user_id created_by_id last_edited_by_id merge_user_id resolved_by_id closed_by_id].freeze
......
...@@ -286,6 +286,7 @@ project: ...@@ -286,6 +286,7 @@ project:
- internal_ids - internal_ids
- project_deploy_tokens - project_deploy_tokens
- deploy_tokens - deploy_tokens
- ci_cd_settings
award_emoji: award_emoji:
- awardable - awardable
- user - user
......
...@@ -552,3 +552,5 @@ Badge: ...@@ -552,3 +552,5 @@ Badge:
- created_at - created_at
- updated_at - updated_at
- type - type
ProjectCiCdSetting:
- group_runners_enabled
# frozen_string_literal: true
require 'spec_helper'
describe ProjectCiCdSetting do
describe '.available?' do
before do
described_class.reset_column_information
end
it 'returns true' do
expect(described_class).to be_available
end
it 'memoizes the schema version' do
expect(ActiveRecord::Migrator)
.to receive(:current_version)
.and_call_original
.once
2.times { described_class.available? }
end
end
end
...@@ -93,6 +93,15 @@ describe Project do ...@@ -93,6 +93,15 @@ describe Project do
end end
end end
context 'when creating a new project' do
it 'automatically creates a CI/CD settings row' do
project = create(:project)
expect(project.ci_cd_settings).to be_an_instance_of(ProjectCiCdSetting)
expect(project.ci_cd_settings).to be_persisted
end
end
describe '#members & #requesters' do describe '#members & #requesters' do
let(:project) { create(:project, :public, :access_requestable) } let(:project) { create(:project, :public, :access_requestable) }
let(:requester) { create(:user) } let(:requester) { create(:user) }
......
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