diff --git a/app/helpers/application_settings_helper.rb b/app/helpers/application_settings_helper.rb
index 0bf5f9e8409..ba2bb030f19 100644
--- a/app/helpers/application_settings_helper.rb
+++ b/app/helpers/application_settings_helper.rb
@@ -283,6 +283,7 @@ module ApplicationSettingsHelper
:max_export_size,
:max_import_size,
:max_pages_size,
+ :max_pages_custom_domains_per_project,
:max_yaml_size_bytes,
:max_yaml_depth,
:metrics_method_call_threshold,
diff --git a/app/helpers/projects/pages_helper.rb b/app/helpers/projects/pages_helper.rb
new file mode 100644
index 00000000000..f46c11db1db
--- /dev/null
+++ b/app/helpers/projects/pages_helper.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+module Projects
+ module PagesHelper
+ def can_create_pages_custom_domains?(current_user, project)
+ current_user.can?(:update_pages, project) &&
+ (Gitlab.config.pages.external_http || Gitlab.config.pages.external_https) &&
+ project.can_create_custom_domains?
+ end
+ end
+end
diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb
index 2a04cc35ece..3590faa818a 100644
--- a/app/models/application_setting.rb
+++ b/app/models/application_setting.rb
@@ -217,6 +217,10 @@ class ApplicationSetting < ApplicationRecord
numericality: { only_integer: true, greater_than_or_equal_to: 0,
less_than: ::Gitlab::Pages::MAX_SIZE / 1.megabyte }
+ validates :max_pages_custom_domains_per_project,
+ presence: true,
+ numericality: { only_integer: true, greater_than_or_equal_to: 0 }
+
validates :jobs_per_stage_page_size,
presence: true,
numericality: { only_integer: true, greater_than_or_equal_to: 0 }
diff --git a/app/models/pages_domain.rb b/app/models/pages_domain.rb
index 2e25839c47f..569f56fa982 100644
--- a/app/models/pages_domain.rb
+++ b/app/models/pages_domain.rb
@@ -33,6 +33,7 @@ class PagesDomain < ApplicationRecord
validate :validate_pages_domain
validate :validate_matching_key, if: ->(domain) { domain.certificate.present? || domain.key.present? }
validate :validate_intermediates, if: ->(domain) { domain.certificate.present? && domain.certificate_changed? }
+ validate :validate_custom_domain_count_per_project, on: :create
default_value_for(:auto_ssl_enabled, allows_nil: false) { ::Gitlab::LetsEncrypt.enabled? }
default_value_for :scope, allows_nil: false, value: :project
@@ -224,6 +225,16 @@ class PagesDomain < ApplicationRecord
self.auto_ssl_failed = false
end
+ def validate_custom_domain_count_per_project
+ return unless project
+
+ unless project.can_create_custom_domains?
+ self.errors.add(
+ :base,
+ _("This project reached the limit of custom domains. (Max %d)") % Gitlab::CurrentSettings.max_pages_custom_domains_per_project)
+ end
+ end
+
private
def pages_deployed?
diff --git a/app/models/project.rb b/app/models/project.rb
index 5130a476332..46295545e91 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -3036,6 +3036,12 @@ class Project < ApplicationRecord
deployments.where(id: deployment_id).fast_destroy_all
end
+ def can_create_custom_domains?
+ return true if Gitlab::CurrentSettings.max_pages_custom_domains_per_project == 0
+
+ pages_domains.count < Gitlab::CurrentSettings.max_pages_custom_domains_per_project
+ end
+
private
# overridden in EE
diff --git a/app/views/admin/application_settings/_pages.html.haml b/app/views/admin/application_settings/_pages.html.haml
index 5ef8a24ba39..cf43d3ddeca 100644
--- a/app/views/admin/application_settings/_pages.html.haml
+++ b/app/views/admin/application_settings/_pages.html.haml
@@ -22,6 +22,13 @@
- pages_link_url = help_page_path('administration/pages/index', anchor: 'set-maximum-size-of-gitlab-pages-site-in-a-project')
- pages_link_start = ''.html_safe % { url: pages_link_url }
= s_('AdminSettings|Set the maximum size of GitLab Pages per project (0 for unlimited). %{link_start}Learn more.%{link_end}').html_safe % { link_start: pages_link_start, link_end: ''.html_safe }
+ .form-group
+ = f.label :max_pages_custom_domains_per_project, s_('AdminSettings|Maximum number of custom domains per project'), class: 'label-bold'
+ = f.number_field :max_pages_custom_domains_per_project, class: 'form-control gl-form-input'
+ .form-text.text-muted
+ - pages_link_url = help_page_path('administration/pages/index', anchor: 'set-maximum-number-of-gitlab-pages-custom-domains-for-a-project')
+ - pages_link_start = ''.html_safe % { url: pages_link_url }
+ = s_('AdminSettings|Set the maximum number of GitLab Pages custom domains per project (0 for unlimited). %{link_start}Learn more.%{link_end}').html_safe % { link_start: pages_link_start, link_end: ''.html_safe }
%h5
= s_("AdminSettings|Configure Let's Encrypt")
%p
diff --git a/app/views/projects/pages/_header.html.haml b/app/views/projects/pages/_header.html.haml
index da35f2fdf09..cf51796e878 100644
--- a/app/views/projects/pages/_header.html.haml
+++ b/app/views/projects/pages/_header.html.haml
@@ -1,4 +1,4 @@
-- can_add_new_domain = can?(current_user, :update_pages, @project) && (Gitlab.config.pages.external_http || Gitlab.config.pages.external_https)
+- can_add_new_domain = can_create_pages_custom_domains?(current_user, @project)
%h1.page-title.gl-font-size-h-display.with-button
= s_('GitLabPages|Pages')
diff --git a/db/migrate/20220818095225_add_max_pages_custom_domains_per_project.rb b/db/migrate/20220818095225_add_max_pages_custom_domains_per_project.rb
new file mode 100644
index 00000000000..c5e1f5aede6
--- /dev/null
+++ b/db/migrate/20220818095225_add_max_pages_custom_domains_per_project.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+class AddMaxPagesCustomDomainsPerProject < Gitlab::Database::Migration[2.0]
+ disable_ddl_transaction!
+
+ CONSTRAINT_NAME = "app_settings_max_pages_custom_domains_per_project_check"
+
+ def up
+ return if column_exists?(:application_settings, :max_pages_custom_domains_per_project)
+
+ add_column :application_settings, :max_pages_custom_domains_per_project, :integer, null: false, default: 0
+ add_check_constraint :application_settings, "max_pages_custom_domains_per_project >= 0", CONSTRAINT_NAME
+ end
+
+ def down
+ return unless column_exists?(:application_settings, :max_pages_custom_domains_per_project)
+
+ remove_column :application_settings, :max_pages_custom_domains_per_project
+ end
+end
diff --git a/db/schema_migrations/20220818095225 b/db/schema_migrations/20220818095225
new file mode 100644
index 00000000000..9f420931b9d
--- /dev/null
+++ b/db/schema_migrations/20220818095225
@@ -0,0 +1 @@
+ec31d14ce1a9f7b08985c2d304ab768a41139e81b694dcb1ec920623201504e6
\ No newline at end of file
diff --git a/db/structure.sql b/db/structure.sql
index 7cc22d2150b..69ab2d880da 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -11510,11 +11510,13 @@ CREATE TABLE application_settings (
package_registry_cleanup_policies_worker_capacity integer DEFAULT 2 NOT NULL,
deactivate_dormant_users_period integer DEFAULT 90 NOT NULL,
auto_ban_user_on_excessive_projects_download boolean DEFAULT false NOT NULL,
+ max_pages_custom_domains_per_project integer DEFAULT 0 NOT NULL,
CONSTRAINT app_settings_container_reg_cleanup_tags_max_list_size_positive CHECK ((container_registry_cleanup_tags_service_max_list_size >= 0)),
CONSTRAINT app_settings_container_registry_pre_import_tags_rate_positive CHECK ((container_registry_pre_import_tags_rate >= (0)::numeric)),
CONSTRAINT app_settings_dep_proxy_ttl_policies_worker_capacity_positive CHECK ((dependency_proxy_ttl_group_policy_worker_capacity >= 0)),
CONSTRAINT app_settings_ext_pipeline_validation_service_url_text_limit CHECK ((char_length(external_pipeline_validation_service_url) <= 255)),
CONSTRAINT app_settings_git_rate_limit_users_allowlist_max_usernames CHECK ((cardinality(git_rate_limit_users_allowlist) <= 100)),
+ CONSTRAINT app_settings_max_pages_custom_domains_per_project_check CHECK ((max_pages_custom_domains_per_project >= 0)),
CONSTRAINT app_settings_p_cleanup_package_file_worker_capacity_positive CHECK ((packages_cleanup_package_file_worker_capacity >= 0)),
CONSTRAINT app_settings_pkg_registry_cleanup_pol_worker_capacity_gte_zero CHECK ((package_registry_cleanup_policies_worker_capacity >= 0)),
CONSTRAINT app_settings_registry_exp_policies_worker_capacity_positive CHECK ((container_registry_expiration_policies_worker_capacity >= 0)),
diff --git a/doc/administration/gitaly/recovery.md b/doc/administration/gitaly/recovery.md
index bd4846a986d..4bbf25d7cdd 100644
--- a/doc/administration/gitaly/recovery.md
+++ b/doc/administration/gitaly/recovery.md
@@ -430,6 +430,44 @@ This command fails if:
- The repository is already being tracked by the Praefect database.
- The repository does not exist on disk.
+### Manually track large numbers of repositories
+
+> [Introduced](https://gitlab.com/gitlab-org/omnibus-gitlab/-/merge_requests/6319) in GitLab 15.4.
+
+The `track-repositories` Praefect sub-command adds large batches of on-disk repositories to the Praefect database for tracking. This can
+be useful when migrating an existing instance to new infrastructure and ingesting all existing repositories into a fresh Gitaly Cluster.
+
+```shell
+# Omnibus GitLab install
+sudo gitlab-ctl praefect track-repositories --input-path /path/to/input.json
+
+# Source install
+sudo /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml track-repositories -input-path /path/to/input.json
+```
+
+The command validates that all entries:
+
+- Are formatted correctly and contain required fields.
+- Correspond to a valid Git repository on disk.
+- Are not currently tracked in the Praefect database.
+
+If any entry fails these checks, the command aborts prior to attempting to track a repository.
+
+- `input-path` is the path to a file containing a list of repositories formatted as newline-delimited JSON objects. Objects must contain the following keys:
+ - `relative_path`: corresponds with `repository` in [track-repositories](#manually-track-repositories).
+ - `authoritative-storage`: the storage Praefect is to treat as the primary.
+ - `virtual-storage`: the virtual storage the repository is located in.
+
+ For example:
+
+ ```json
+ {"relative_path":"@hashed/f5/ca/f5ca38f748a1d6eaf726b8a42fb575c3c71f1864a8143301782de13da2d9202b.git","authoritative_storage":"gitaly-1","virtual_storage":"default"}
+ {"relative_path":"@hashed/f8/9f/f89f8d0e735a91c5269ab08d72fa27670d000e7561698d6e664e7b603f5c4e40.git","authoritative_storage":"gitaly-2","virtual_storage":"default"}
+ ```
+
+- `-replicate-immediately`, causes the command to replicate the repository to its secondaries immediately.
+ Otherwise, replication jobs are scheduled for execution in the database and are picked up by a Praefect background process.
+
### List virtual storage details
> [Introduced](https://gitlab.com/gitlab-org/gitaly/-/merge_requests/4609) in GitLab 15.1.
diff --git a/doc/administration/pages/index.md b/doc/administration/pages/index.md
index bea6328ccdd..c5b4852eda8 100644
--- a/doc/administration/pages/index.md
+++ b/doc/administration/pages/index.md
@@ -738,6 +738,19 @@ To set the maximum size of GitLab Pages site in a project, overriding the inheri
1. Enter a value under **Maximum size of pages** in MB.
1. Select **Save changes**.
+## Set maximum number of GitLab Pages custom domains for a project
+
+Prerequisite:
+
+- You must be an administrator of a self-managed GitLab instance.
+
+To set the maximum number of GitLab Pages custom domains for a project:
+
+1. On the top bar, select **Menu > Admin**.
+1. On the left sidebar, select **Settings > Preferences**, and expand **Pages**.
+1. Enter a value for **Maximum number of custom domains per project**. Use `0` for unlimited domains.
+1. Select **Save changes**.
+
## Running GitLab Pages on a separate server
You can run the GitLab Pages daemon on a separate server to decrease the load on
diff --git a/doc/ci/caching/index.md b/doc/ci/caching/index.md
index 07bda2baadf..9269b8886c7 100644
--- a/doc/ci/caching/index.md
+++ b/doc/ci/caching/index.md
@@ -84,7 +84,8 @@ test-job:
paths:
- .yarn-cache/
script:
- - bundle install --path=vendor
+ - bundle config set --local path 'vendor/ruby'
+ - bundle install
- yarn install --cache-folder .yarn-cache
- echo Run tests...
```
@@ -353,7 +354,8 @@ cache:
before_script:
- ruby -v # Print out ruby version for debugging
- - bundle install -j $(nproc) --path vendor/ruby # Install dependencies into ./vendor/ruby
+ - bundle config set --local path 'vendor/ruby' # The location to install the specified gems to
+ - bundle install -j $(nproc) # Install dependencies into ./vendor/ruby
rspec:
script:
@@ -379,14 +381,16 @@ cache:
test_job:
stage: test
before_script:
- - bundle install --without production --path vendor/ruby
+ - bundle config set --local path 'vendor/ruby'
+ - bundle install --without production
script:
- bundle exec rspec
deploy_job:
stage: production
before_script:
- - bundle install --without test --path vendor/ruby
+ - bundle config set --local path 'vendor/ruby' # The location to install the specified gems to
+ - bundle install --without test
script:
- bundle exec deploy
```
diff --git a/lib/api/settings.rb b/lib/api/settings.rb
index c25a56d5f08..f393f862f55 100644
--- a/lib/api/settings.rb
+++ b/lib/api/settings.rb
@@ -98,6 +98,7 @@ module API
optional :max_export_size, type: Integer, desc: 'Maximum export size in MB'
optional :max_import_size, type: Integer, desc: 'Maximum import size in MB'
optional :max_pages_size, type: Integer, desc: 'Maximum size of pages in MB'
+ optional :max_pages_custom_domains_per_project, type: Integer, desc: 'Maximum number of GitLab Pages custom domains per project'
optional :metrics_method_call_threshold, type: Integer, desc: 'A method call is only tracked when it takes longer to complete than the given amount of milliseconds.'
optional :password_authentication_enabled, type: Boolean, desc: 'Flag indicating if password authentication is enabled for the web interface' # support legacy names, can be removed in v5
optional :password_authentication_enabled_for_web, type: Boolean, desc: 'Flag indicating if password authentication is enabled for the web interface'
diff --git a/lib/gitlab/github_import/importer/events/changed_assignee.rb b/lib/gitlab/github_import/importer/events/changed_assignee.rb
index 7b18ea807a5..b75d41f40de 100644
--- a/lib/gitlab/github_import/importer/events/changed_assignee.rb
+++ b/lib/gitlab/github_import/importer/events/changed_assignee.rb
@@ -7,22 +7,22 @@ module Gitlab
class ChangedAssignee < BaseImporter
def execute(issue_event)
assignee_id = author_id(issue_event, author_key: :assignee)
- assigner_id = author_id(issue_event, author_key: :assigner)
+ author_id = author_id(issue_event, author_key: :actor)
- note_body = parse_body(issue_event, assigner_id, assignee_id)
+ note_body = parse_body(issue_event, assignee_id)
- create_note(issue_event, note_body, assigner_id)
+ create_note(issue_event, note_body, author_id)
end
private
- def create_note(issue_event, note_body, assigner_id)
+ def create_note(issue_event, note_body, author_id)
Note.create!(
system: true,
noteable_type: issuable_type(issue_event),
noteable_id: issuable_db_id(issue_event),
project: project,
- author_id: assigner_id,
+ author_id: author_id,
note: note_body,
system_note_metadata: SystemNoteMetadata.new(
{
@@ -36,12 +36,14 @@ module Gitlab
)
end
- def parse_body(issue_event, assigner_id, assignee_id)
+ def parse_body(issue_event, assignee_id)
+ assignee = User.find(assignee_id).to_reference
+
Gitlab::I18n.with_default_locale do
if issue_event.event == "unassigned"
- "unassigned #{User.find(assigner_id).to_reference}"
+ "unassigned #{assignee}"
else
- "assigned to #{User.find(assignee_id).to_reference}"
+ "assigned to #{assignee}"
end
end
end
diff --git a/lib/gitlab/github_import/representation/issue_event.rb b/lib/gitlab/github_import/representation/issue_event.rb
index 67a5df73a97..3dfebbc7d29 100644
--- a/lib/gitlab/github_import/representation/issue_event.rb
+++ b/lib/gitlab/github_import/representation/issue_event.rb
@@ -10,7 +10,7 @@ module Gitlab
attr_reader :attributes
expose_attribute :id, :actor, :event, :commit_id, :label_title, :old_title, :new_title,
- :milestone_title, :issue, :source, :assignee, :assigner, :created_at
+ :milestone_title, :issue, :source, :assignee, :created_at
# attributes - A Hash containing the event details. The keys of this
# Hash (and any nested hashes) must be symbols.
@@ -47,7 +47,6 @@ module Gitlab
issue: event.issue&.to_h&.symbolize_keys,
source: event.source,
assignee: user_representation(event.assignee),
- assigner: user_representation(event.assigner),
created_at: event.created_at
)
end
@@ -57,7 +56,6 @@ module Gitlab
hash = Representation.symbolize_hash(raw_hash)
hash[:actor] = user_representation(hash[:actor], source: :hash)
hash[:assignee] = user_representation(hash[:assignee], source: :hash)
- hash[:assigner] = user_representation(hash[:assigner], source: :hash)
new(hash)
end
diff --git a/lib/gitlab/github_import/user_finder.rb b/lib/gitlab/github_import/user_finder.rb
index 6d6a00d260d..1805939dfef 100644
--- a/lib/gitlab/github_import/user_finder.rb
+++ b/lib/gitlab/github_import/user_finder.rb
@@ -45,8 +45,6 @@ module Gitlab
object&.actor
when :assignee
object&.assignee
- when :assigner
- object&.assigner
else
object&.author
end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 3d138d02cc0..7bfa1123c81 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -2802,6 +2802,9 @@ msgstr ""
msgid "AdminSettings|Maximum number of active pipelines per project"
msgstr ""
+msgid "AdminSettings|Maximum number of custom domains per project"
+msgstr ""
+
msgid "AdminSettings|Maximum number of jobs in a single pipeline"
msgstr ""
@@ -2892,6 +2895,9 @@ msgstr ""
msgid "AdminSettings|Set the initial name and protections for the default branch of new repositories created in the instance."
msgstr ""
+msgid "AdminSettings|Set the maximum number of GitLab Pages custom domains per project (0 for unlimited). %{link_start}Learn more.%{link_end}"
+msgstr ""
+
msgid "AdminSettings|Set the maximum size of GitLab Pages per project (0 for unlimited). %{link_start}Learn more.%{link_end}"
msgstr ""
@@ -40657,6 +40663,9 @@ msgstr ""
msgid "This project path either does not exist or you do not have access."
msgstr ""
+msgid "This project reached the limit of custom domains. (Max %d)"
+msgstr ""
+
msgid "This project will be deleted on %{date}"
msgstr ""
diff --git a/spec/helpers/projects/pages_helper_spec.rb b/spec/helpers/projects/pages_helper_spec.rb
new file mode 100644
index 00000000000..4a4cebc9d70
--- /dev/null
+++ b/spec/helpers/projects/pages_helper_spec.rb
@@ -0,0 +1,68 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Projects::PagesHelper do
+ let(:user) { create(:user) }
+ let(:project) { create(:project) }
+
+ before do
+ stub_config(pages: {
+ access_control: true,
+ external_http: true,
+ external_https: true,
+ host: "new.domain.com"
+ })
+ end
+
+ context 'when the user have permission' do
+ before do
+ project.add_maintainer(user)
+ end
+
+ context 'on custom domain' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:external_http, :external_https, :can_create) do
+ false | false | false
+ false | true | true
+ true | false | true
+ true | true | true
+ end
+
+ with_them do
+ it do
+ stub_config(pages: { external_http: external_http, external_https: external_https })
+
+ expect(can_create_pages_custom_domains?(user, project)).to be can_create
+ end
+ end
+ end
+
+ context 'on domain limit' do
+ it 'can create new domains when the limit is 0' do
+ Gitlab::CurrentSettings.update!(max_pages_custom_domains_per_project: 0)
+
+ expect(can_create_pages_custom_domains?(user, project)).to be true
+ end
+
+ it 'validates custom domain creation is only allowed upto max value' do
+ Gitlab::CurrentSettings.update!(max_pages_custom_domains_per_project: 1)
+
+ expect(can_create_pages_custom_domains?(user, project)).to be true
+ create(:pages_domain, project: project)
+ expect(can_create_pages_custom_domains?(user, project)).to be false
+ end
+ end
+ end
+
+ context 'when the user does not have permission' do
+ before do
+ project.add_guest(user)
+ end
+
+ it 'validates user cannot create domain' do
+ expect(can_create_pages_custom_domains?(user, project)).to be false
+ end
+ end
+end
diff --git a/spec/lib/gitlab/github_import/importer/events/changed_assignee_spec.rb b/spec/lib/gitlab/github_import/importer/events/changed_assignee_spec.rb
index d840227992f..dbc72574ec2 100644
--- a/spec/lib/gitlab/github_import/importer/events/changed_assignee_spec.rb
+++ b/spec/lib/gitlab/github_import/importer/events/changed_assignee_spec.rb
@@ -6,8 +6,8 @@ RSpec.describe Gitlab::GithubImport::Importer::Events::ChangedAssignee do
subject(:importer) { described_class.new(project, client) }
let_it_be(:project) { create(:project, :repository) }
+ let_it_be(:author) { create(:user) }
let_it_be(:assignee) { create(:user) }
- let_it_be(:assigner) { create(:user) }
let(:client) { instance_double('Gitlab::GithubImport::Client') }
let(:issuable) { create(:issue, project: project) }
@@ -15,11 +15,10 @@ RSpec.describe Gitlab::GithubImport::Importer::Events::ChangedAssignee do
let(:issue_event) do
Gitlab::GithubImport::Representation::IssueEvent.from_json_hash(
'id' => 6501124486,
- 'actor' => { 'id' => 4, 'login' => 'alice' },
+ 'actor' => { 'id' => author.id, 'login' => author.username },
'event' => event_type,
'commit_id' => nil,
'created_at' => '2022-04-26 18:30:53 UTC',
- 'assigner' => { 'id' => assigner.id, 'login' => assigner.username },
'assignee' => { 'id' => assignee.id, 'login' => assignee.username },
'issue' => { 'number' => issuable.iid, pull_request: issuable.is_a?(MergeRequest) }
)
@@ -30,7 +29,7 @@ RSpec.describe Gitlab::GithubImport::Importer::Events::ChangedAssignee do
noteable_id: issuable.id,
noteable_type: issuable.class.name,
project_id: project.id,
- author_id: assigner.id,
+ author_id: author.id,
system: true,
created_at: issue_event.created_at,
updated_at: issue_event.created_at
@@ -77,7 +76,7 @@ RSpec.describe Gitlab::GithubImport::Importer::Events::ChangedAssignee do
context 'when importing an unassigned event' do
let(:event_type) { 'unassigned' }
- let(:expected_note_attrs) { note_attrs.merge(note: "unassigned @#{assigner.username}") }
+ let(:expected_note_attrs) { note_attrs.merge(note: "unassigned @#{assignee.username}") }
it_behaves_like 'create expected notes'
end
@@ -89,8 +88,8 @@ RSpec.describe Gitlab::GithubImport::Importer::Events::ChangedAssignee do
allow(finder).to receive(:database_id).and_return(issuable.id)
end
allow_next_instance_of(Gitlab::GithubImport::UserFinder) do |finder|
+ allow(finder).to receive(:find).with(author.id, author.username).and_return(author.id)
allow(finder).to receive(:find).with(assignee.id, assignee.username).and_return(assignee.id)
- allow(finder).to receive(:find).with(assigner.id, assigner.username).and_return(assigner.id)
end
end
diff --git a/spec/lib/gitlab/github_import/representation/issue_event_spec.rb b/spec/lib/gitlab/github_import/representation/issue_event_spec.rb
index d3a98035e73..2414e46470a 100644
--- a/spec/lib/gitlab/github_import/representation/issue_event_spec.rb
+++ b/spec/lib/gitlab/github_import/representation/issue_event_spec.rb
@@ -91,26 +91,20 @@ RSpec.describe Gitlab::GithubImport::Representation::IssueEvent do
end
end
- context 'when assignee and assigner data is present' do
- it 'includes assignee and assigner details' do
+ context 'when assignee data is present' do
+ it 'includes assignee details' do
expect(issue_event.assignee)
.to be_an_instance_of(Gitlab::GithubImport::Representation::User)
expect(issue_event.assignee.id).to eq(5)
expect(issue_event.assignee.login).to eq('tom')
-
- expect(issue_event.assigner)
- .to be_an_instance_of(Gitlab::GithubImport::Representation::User)
- expect(issue_event.assigner.id).to eq(6)
- expect(issue_event.assigner.login).to eq('jerry')
end
end
- context 'when assignee and assigner data is empty' do
+ context 'when assignee data is empty' do
let(:with_assignee) { false }
it 'does not return such info' do
expect(issue_event.assignee).to eq nil
- expect(issue_event.assigner).to eq nil
end
end
@@ -148,7 +142,7 @@ RSpec.describe Gitlab::GithubImport::Representation::IssueEvent do
let(:response) do
event_resource = Struct.new(
:id, :node_id, :url, :actor, :event, :commit_id, :commit_url, :label, :rename, :milestone,
- :source, :assignee, :assigner, :issue, :created_at, :performed_via_github_app,
+ :source, :assignee, :issue, :created_at, :performed_via_github_app,
keyword_init: true
)
user_resource = Struct.new(:id, :login, keyword_init: true)
@@ -166,7 +160,6 @@ RSpec.describe Gitlab::GithubImport::Representation::IssueEvent do
milestone: with_milestone ? { title: 'milestone title' } : nil,
source: { type: 'issue', id: 123456 },
assignee: with_assignee ? user_resource.new(id: 5, login: 'tom') : nil,
- assigner: with_assignee ? user_resource.new(id: 6, login: 'jerry') : nil,
issue: { 'number' => 2, 'pull_request' => pull_request },
created_at: '2022-04-26 18:30:53 UTC',
performed_via_github_app: nil
@@ -203,7 +196,6 @@ RSpec.describe Gitlab::GithubImport::Representation::IssueEvent do
'milestone_title' => (with_milestone ? 'milestone title' : nil),
'source' => { 'type' => 'issue', 'id' => 123456 },
'assignee' => (with_assignee ? { 'id' => 5, 'login' => 'tom' } : nil),
- 'assigner' => (with_assignee ? { 'id' => 6, 'login' => 'jerry' } : nil),
'issue' => { 'number' => 2, 'pull_request' => pull_request },
'created_at' => '2022-04-26 18:30:53 UTC',
'performed_via_github_app' => nil
diff --git a/spec/lib/gitlab/github_import/user_finder_spec.rb b/spec/lib/gitlab/github_import/user_finder_spec.rb
index d85e298785c..27426763232 100644
--- a/spec/lib/gitlab/github_import/user_finder_spec.rb
+++ b/spec/lib/gitlab/github_import/user_finder_spec.rb
@@ -67,12 +67,6 @@ RSpec.describe Gitlab::GithubImport::UserFinder, :clean_gitlab_redis_cache do
it_behaves_like 'user ID finder', :assignee
end
-
- context 'when the author_key parameter is :assigner' do
- let(:issue_event) { double('Gitlab::GithubImport::Representation::IssueEvent', assigner: user) }
-
- it_behaves_like 'user ID finder', :assigner
- end
end
end
diff --git a/spec/models/application_setting_spec.rb b/spec/models/application_setting_spec.rb
index 16e1d8fbc4d..b5f153e7add 100644
--- a/spec/models/application_setting_spec.rb
+++ b/spec/models/application_setting_spec.rb
@@ -116,12 +116,20 @@ RSpec.describe ApplicationSetting do
it { is_expected.to validate_presence_of(:max_yaml_depth) }
it { is_expected.to validate_numericality_of(:max_yaml_depth).only_integer.is_greater_than(0) }
it { is_expected.to validate_presence_of(:max_pages_size) }
+ it { is_expected.to validate_presence_of(:max_pages_custom_domains_per_project) }
it 'ensures max_pages_size is an integer greater than 0 (or equal to 0 to indicate unlimited/maximum)' do
is_expected.to validate_numericality_of(:max_pages_size).only_integer.is_greater_than_or_equal_to(0)
.is_less_than(::Gitlab::Pages::MAX_SIZE / 1.megabyte)
end
+ it 'ensures max_pages_custom_domains_per_project is an integer greater than 0 (or equal to 0 to indicate unlimited/maximum)' do
+ is_expected
+ .to validate_numericality_of(:max_pages_custom_domains_per_project)
+ .only_integer
+ .is_greater_than_or_equal_to(0)
+ end
+
it { is_expected.to validate_presence_of(:jobs_per_stage_page_size) }
it { is_expected.to validate_numericality_of(:jobs_per_stage_page_size).only_integer.is_greater_than_or_equal_to(0) }
diff --git a/spec/models/pages_domain_spec.rb b/spec/models/pages_domain_spec.rb
index 4691d38184a..644b2ce172a 100644
--- a/spec/models/pages_domain_spec.rb
+++ b/spec/models/pages_domain_spec.rb
@@ -62,7 +62,7 @@ RSpec.describe PagesDomain do
let(:domain) { 'my.domain.com' }
let(:project) do
- instance_double(Project, pages_https_only?: pages_https_only)
+ instance_double(Project, pages_https_only?: pages_https_only, can_create_custom_domains?: true)
end
let(:pages_domain) do
@@ -571,6 +571,32 @@ RSpec.describe PagesDomain do
end
end
+ describe '#validate_custom_domain_count_per_project' do
+ let_it_be(:project) { create(:project) }
+
+ context 'when max custom domain setting is set to 0' do
+ it 'returns without an error' do
+ pages_domain = create(:pages_domain, project: project)
+
+ expect(pages_domain).to be_valid
+ end
+ end
+
+ context 'when max custom domain setting is not set to 0' do
+ it 'returns with an error for extra domains' do
+ Gitlab::CurrentSettings.update!(max_pages_custom_domains_per_project: 1)
+
+ pages_domain = create(:pages_domain, project: project)
+ expect(pages_domain).to be_valid
+
+ pages_domain = build(:pages_domain, project: project)
+ expect(pages_domain).not_to be_valid
+ expect(pages_domain.errors.full_messages)
+ .to contain_exactly('This project reached the limit of custom domains. (Max 1)')
+ end
+ end
+ end
+
describe '.find_by_domain_case_insensitive' do
it 'lookup is case-insensitive' do
pages_domain = create(:pages_domain, domain: "Pages.IO")
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 77abb7c4dae..664882fd782 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -8337,6 +8337,25 @@ RSpec.describe Project, factory_default: :keep do
end
end
+ describe '#can_create_custom_domains?' do
+ let_it_be(:project) { create(:project) }
+ let_it_be(:pages_domain) { create(:pages_domain, project: project) }
+
+ subject { project.can_create_custom_domains? }
+
+ context 'when max custom domain setting is set to 0' do
+ it { is_expected.to be true }
+ end
+
+ context 'when max custom domain setting is not set to 0' do
+ before do
+ Gitlab::CurrentSettings.update!(max_pages_custom_domains_per_project: 1)
+ end
+
+ it { is_expected.to be false }
+ end
+ end
+
private
def finish_job(export_job)