Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2023-11-01 03:10:42 +00:00
parent 533fed8bd8
commit 24ed1c84da
50 changed files with 437 additions and 164 deletions

View File

@ -1465,15 +1465,6 @@ Layout/ArgumentAlignment:
- 'spec/lib/gitlab/data_builder/push_spec.rb'
- 'spec/lib/gitlab/database/migration_helpers_spec.rb'
- 'spec/lib/gitlab/dependency_linker/parser/gemfile_spec.rb'
- 'spec/lib/gitlab/diff/file_collection/compare_spec.rb'
- 'spec/lib/gitlab/diff/file_collection/merge_request_diff_batch_spec.rb'
- 'spec/lib/gitlab/diff/file_collection/paginated_merge_request_diff_spec.rb'
- 'spec/lib/gitlab/diff/file_spec.rb'
- 'spec/lib/gitlab/diff/highlight_cache_spec.rb'
- 'spec/lib/gitlab/diff/line_spec.rb'
- 'spec/lib/gitlab/diff/suggestion_diff_spec.rb'
- 'spec/lib/gitlab/diff/suggestion_spec.rb'
- 'spec/lib/gitlab/diff/suggestions_parser_spec.rb'
- 'spec/lib/gitlab/email/hook/delivery_metrics_observer_spec.rb'
- 'spec/lib/gitlab/email/hook/smime_signature_interceptor_spec.rb'
- 'spec/lib/gitlab/error_tracking/processor/context_payload_processor_spec.rb'

View File

@ -7,6 +7,7 @@ import {
GlFormGroup,
GlFormTextarea,
GlButton,
GlSprintf,
GlFormRadio,
GlFormRadioGroup,
} from '@gitlab/ui';
@ -56,6 +57,7 @@ export default {
GlIcon,
GlLink,
GlButton,
GlSprintf,
GlFormInput,
GlFormTextarea,
GlFormGroup,
@ -91,6 +93,9 @@ export default {
projectDescription: {
default: '',
},
projectDefaultBranch: {
default: '',
},
projectVisibility: {
default: '',
},
@ -116,6 +121,7 @@ export default {
required: false,
skipValidation: true,
}),
branches: initFormField({ value: '', required: true, skipValidation: true }),
visibility: initFormField({ value: null }),
},
};
@ -168,6 +174,18 @@ export default {
return allowedLevels;
},
branchesOptions() {
return [
{
text: s__('ForkProject|All branches'),
value: '',
},
{
text: s__(`ForkProject|Only the default branch %{defaultBranch}`),
value: this.projectDefaultBranch,
},
];
},
visibilityLevels() {
return [
{
@ -245,7 +263,7 @@ export default {
this.form.showValidation = false;
const { projectId } = this;
const { name, slug, description, visibility, namespace } = this.form.fields;
const { name, slug, description, branches, visibility, namespace } = this.form.fields;
const postParams = {
id: projectId,
@ -253,6 +271,7 @@ export default {
namespace_id: namespace.value.id,
path: slug.value,
description: description.value,
branches: branches.value,
visibility: visibility.value,
};
@ -263,6 +282,7 @@ export default {
const { data } = await axios.post(url, postParams);
redirectTo(data.web_url); // eslint-disable-line import/no-deprecated
} catch (error) {
this.isSaving = false;
createAlert({
message: s__(
'ForkProject|An error occurred while forking the project. Please try again.',
@ -348,6 +368,34 @@ export default {
/>
</gl-form-group>
<gl-form-group>
<label>
{{ s__('ForkProject|Branches to include') }}
</label>
<gl-form-radio-group
v-model="form.fields.branches.value"
data-testid="fork-branches-radio-group"
name="branches"
:aria-label="__('branches')"
required
>
<gl-form-radio
v-for="{ text, value } in branchesOptions"
:key="value"
:value="value"
:data-testid="`radio-${value}`"
>
<div>
<gl-sprintf :message="text">
<template #defaultBranch>
<code class="gl-ml-2">{{ projectDefaultBranch }}</code>
</template>
</gl-sprintf>
</div>
</gl-form-radio>
</gl-form-radio-group>
</gl-form-group>
<gl-form-group
v-validation:[form.showValidation]
:invalid-feedback="s__('ForkProject|Please select a visibility level')"

View File

@ -15,6 +15,7 @@ const {
projectId,
projectName,
projectPath,
projectDefaultBranch,
projectDescription,
projectVisibility,
restrictedVisibilityLevels,
@ -38,6 +39,7 @@ new Vue({
projectName,
projectPath,
projectDescription,
projectDefaultBranch,
projectVisibility,
restrictedVisibilityLevels: JSON.parse(restrictedVisibilityLevels),
},

View File

@ -5,6 +5,8 @@ import {
sprintfWorkItem,
I18N_WORK_ITEM_ERROR_UPDATING,
TRACKING_CATEGORY_SHOW,
WORK_ITEM_TITLE_MAX_LENGTH,
I18N_MAX_CHARS_IN_WORK_ITEM_TITLE_MESSAGE,
} from '../constants';
import { getUpdateWorkItemMutation } from './update_work_item';
import ItemTitle from './item_title.vue';
@ -56,6 +58,11 @@ export default {
return;
}
if (updatedTitle.length > WORK_ITEM_TITLE_MAX_LENGTH) {
this.$emit('error', sprintfWorkItem(I18N_MAX_CHARS_IN_WORK_ITEM_TITLE_MESSAGE));
return;
}
const input = {
id: this.workItemId,
title: updatedTitle,

View File

@ -45,6 +45,8 @@ export const WORK_ITEM_TYPE_VALUE_REQUIREMENTS = 'Requirements';
export const WORK_ITEM_TYPE_VALUE_KEY_RESULT = 'Key Result';
export const WORK_ITEM_TYPE_VALUE_OBJECTIVE = 'Objective';
export const WORK_ITEM_TITLE_MAX_LENGTH = 255;
export const i18n = {
fetchErrorTitle: s__('WorkItem|Work item not found'),
fetchError: s__(
@ -108,6 +110,11 @@ export const I18N_WORK_ITEM_ERROR_COPY_EMAIL = s__(
'WorkItem|Something went wrong while copying the %{workItemType} email address. Please try again.',
);
export const I18N_MAX_CHARS_IN_WORK_ITEM_TITLE_MESSAGE = sprintf(
s__('WorkItem|Title cannot have more than %{WORK_ITEM_TITLE_MAX_LENGTH} characters.'),
{ WORK_ITEM_TITLE_MAX_LENGTH },
);
export const I18N_WORK_ITEM_COPY_CREATE_NOTE_EMAIL = s__(
'WorkItem|Copy %{workItemType} email address',
);

View File

@ -1444,12 +1444,10 @@ class Project < ApplicationRecord
end
def build_or_assign_import_data(data: nil, credentials: nil)
return if data.nil? && credentials.nil?
project_import_data = import_data || build_import_data
project_import_data.merge_data(data.to_h)
project_import_data.merge_credentials(credentials.to_h)
project_import_data.merge_data(data.to_h) if data
project_import_data.merge_credentials(credentials.to_h) if credentials
project_import_data
end

View File

@ -17,6 +17,10 @@ module Projects
@valid_fork_targets ||= ForkTargetsFinder.new(@project, current_user).execute(options)
end
def valid_fork_branch?(branch)
@project.repository.branch_exists?(branch)
end
def valid_fork_target?(namespace = target_namespace)
return true if current_user.admin?
@ -68,7 +72,8 @@ module Projects
external_authorization_classification_label: @project.external_authorization_classification_label,
suggestion_commit_message: @project.suggestion_commit_message,
merge_commit_template: @project.merge_commit_template,
squash_commit_template: @project.squash_commit_template
squash_commit_template: @project.squash_commit_template,
import_data: { data: { fork_branch: branch } }
}
if @project.avatar.present? && @project.avatar.image?
@ -145,6 +150,12 @@ module Projects
def stream_audit_event(forked_project)
# Defined in EE
end
def branch
# We extract branch name from @params[:branches] because the front end
# insists on sending it as 'branches'.
@params[:branches]
end
end
end

View File

@ -15,5 +15,5 @@
.form-group
= f.label :gitlab_shell_operation_limit, s_('ShellOperations|Maximum number of Git operations per minute'), class: 'gl-font-bold'
= f.number_field :gitlab_shell_operation_limit, class: 'form-control gl-form-input'
%span.form-text.text-muted= _('Set to 0 to disable the limit.')
= f.submit _('Save changes'), pajamas_button: true

View File

@ -2,8 +2,7 @@
= form_errors(@application_setting)
%fieldset
= html_escape(_("Set any rate limit to %{code_open}0%{code_close} to disable the limit.")) % { code_open: '<code>'.html_safe, code_close: '</code>'.html_safe }
= html_escape(_("Set to 0 to disable the limits."))
%fieldset
.form-group

View File

@ -11,16 +11,16 @@
= f.label :raw_blob_request_limit, _('Raw blob request rate limit per minute'), class: 'label-bold'
= f.number_field :raw_blob_request_limit, class: 'form-control gl-form-input'
.form-text.text-muted
= _('Maximum number of requests per minute for each raw path (default is `300`). Set to `0` to disable throttling.')
= _('Maximum number of requests per minute for each raw path (default is 300). Set to 0 to disable throttling.')
.form-group
= f.label :push_event_hooks_limit, class: 'label-bold'
= f.number_field :push_event_hooks_limit, class: 'form-control gl-form-input'
.form-text.text-muted
= _('Maximum number of changes (branches or tags) in a single push above which webhooks and integrations are not triggered (default is `3`). Setting to `0` does not disable throttling.')
= _('Maximum number of changes (branches or tags) in a single push above which webhooks and integrations are not triggered (default is 3). Setting to 0 does not disable throttling.')
.form-group
= f.label :push_event_activities_limit, class: 'label-bold'
= f.number_field :push_event_activities_limit, class: 'form-control gl-form-input'
.form-text.text-muted
= _('Maximum number of changes (branches or tags) in a single push above which a bulk push event is created (default is `3`). Setting to `0` does not disable throttling.')
= _('Maximum number of changes (branches or tags) in a single push above which a bulk push event is created (default is 3). Setting to 0 does not disable throttling.')
= f.submit _('Save changes'), pajamas_button: true

View File

@ -16,6 +16,6 @@
= f.label :projects_api_rate_limit_unauthenticated, _('Maximum requests per 10 minutes per IP address'), class: 'label-bold'
= f.number_field :projects_api_rate_limit_unauthenticated, class: 'form-control gl-form-input'
.form-text.gl-text-gray-600
= _("Set this number to 0 to disable the limit.")
= _("Set to 0 to disable the limit.")
= f.submit _('Save changes'), data: { qa_selector: 'save_changes_button' }, pajamas_button: true

View File

@ -9,6 +9,7 @@
project_id: @project.id,
project_name: @project.name,
project_path: @project.path,
project_default_branch: @project.default_branch,
project_description: @project.description,
project_visibility: @project.visibility,
restricted_visibility_levels: Gitlab::CurrentSettings.restricted_visibility_levels.to_json } }

View File

@ -2,6 +2,7 @@
class RepositoryForkWorker # rubocop:disable Scalability/IdempotentWorker
include ApplicationWorker
include Gitlab::Utils::StrongMemoize
data_consistency :always
@ -12,10 +13,8 @@ class RepositoryForkWorker # rubocop:disable Scalability/IdempotentWorker
feature_category :source_code_management
def perform(*args)
target_project_id = args.shift
target_project = Project.find(target_project_id)
@target_project_id = args.shift
source_project = target_project.forked_from_project
unless source_project
return target_project.import_state.mark_as_failed(_('Source project cannot be found.'))
end
@ -25,6 +24,21 @@ class RepositoryForkWorker # rubocop:disable Scalability/IdempotentWorker
private
def target_project
Project.find(@target_project_id)
end
strong_memoize_attr :target_project
def source_project
@source_project ||= target_project.forked_from_project
end
def branch
return unless target_project.import_data&.data
target_project.import_data.data['fork_branch']
end
def fork_repository(target_project, source_project)
return unless start_fork(target_project)
@ -46,7 +60,7 @@ class RepositoryForkWorker # rubocop:disable Scalability/IdempotentWorker
source_repo = source_project.repository.raw
target_repo = target_project.repository.raw
::Gitlab::GitalyClient::RepositoryService.new(target_repo).fork_repository(source_repo)
::Gitlab::GitalyClient::RepositoryService.new(target_repo).fork_repository(source_repo, branch)
rescue GRPC::BadStatus => e
Gitlab::ErrorTracking.track_exception(e, source_project_id: source_project.id, target_project_id: target_project.id)

View File

@ -11,3 +11,7 @@ description: Storing namespaces records for groups, users and projects
introduced_by_url: https://github.com/gitlabhq/gitlabhq/pull/2051
milestone: "<6.0"
gitlab_schema: gitlab_main_cell
schema_inconsistencies:
- type: missing_indexes
object_name: index_namespaces_on_created_at
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/134948

View File

@ -0,0 +1,24 @@
# frozen_string_literal: true
class DropIndexNamespacesOnCreatedAtForGitlabCom < Gitlab::Database::Migration[2.1]
disable_ddl_transaction!
TABLE_NAME = :namespaces
INDEX_NAME = :index_namespaces_on_created_at
def up
return unless should_run?
remove_concurrent_index_by_name TABLE_NAME, INDEX_NAME
end
def down
return unless should_run?
add_concurrent_index TABLE_NAME, :created_at, name: INDEX_NAME
end
def should_run?
Gitlab.com_except_jh?
end
end

View File

@ -0,0 +1,21 @@
# frozen_string_literal: true
class DropProjectSettingsJitsuKey < Gitlab::Database::Migration[2.2]
milestone '16.6'
disable_ddl_transaction!
def up
with_lock_retries do
remove_column :project_settings, :jitsu_key, if_exists: true
end
end
def down
with_lock_retries do
add_column :project_settings, :jitsu_key, :text, if_not_exists: true
end
add_text_limit :project_settings, :jitsu_key, 100
end
end

View File

@ -0,0 +1 @@
8ad5065584f72084ee929e479725593330d0d13542dc4939476d62f831c6f2e8

View File

@ -0,0 +1 @@
dc0065c2caffdf5bbf79c1e94f8bdb6d415a836cc575109d25df8217423be0e1

View File

@ -21829,7 +21829,6 @@ CREATE TABLE project_settings (
selective_code_owner_removals boolean DEFAULT false NOT NULL,
issue_branch_template text,
show_diff_preview_in_email boolean DEFAULT true NOT NULL,
jitsu_key text,
suggested_reviewers_enabled boolean DEFAULT false NOT NULL,
only_allow_merge_if_all_status_checks_passed boolean DEFAULT false NOT NULL,
mirror_branch_regex text,
@ -21847,7 +21846,6 @@ CREATE TABLE project_settings (
encrypted_product_analytics_configurator_connection_string_iv bytea,
pages_multiple_versions_enabled boolean DEFAULT false NOT NULL,
CONSTRAINT check_1a30456322 CHECK ((char_length(pages_unique_domain) <= 63)),
CONSTRAINT check_2981f15877 CHECK ((char_length(jitsu_key) <= 100)),
CONSTRAINT check_3a03e7557a CHECK ((char_length(previous_default_branch) <= 4096)),
CONSTRAINT check_3ca5cbffe6 CHECK ((char_length(issue_branch_template) <= 255)),
CONSTRAINT check_4b142e71f3 CHECK ((char_length(product_analytics_data_collector_host) <= 255)),

View File

@ -20,7 +20,7 @@ POST /projects/:id/ci/lint
| `content` | string | Yes | The CI/CD configuration content. |
| `dry_run` | boolean | No | Run [pipeline creation simulation](../ci/lint.md#simulate-a-pipeline), or only do static check. Default: `false`. |
| `include_jobs` | boolean | No | If the list of jobs that would exist in a static check or pipeline simulation should be included in the response. Default: `false`. |
| `ref` | string | No | When `dry_run` is `true`, sets the branch or tag to use. Defaults to the project's default branch when not set. |
| `ref` | string | No | When `dry_run` is `true`, sets the branch or tag context to use to validate the CI/CD YAML configuration. Defaults to the project's default branch when not set. |
Example request:
@ -71,7 +71,7 @@ GET /projects/:id/ci/lint
|----------------|---------|----------|-------------|
| `dry_run` | boolean | No | Run pipeline creation simulation, or only do static check. |
| `include_jobs` | boolean | No | If the list of jobs that would exist in a static check or pipeline simulation should be included in the response. Default: `false`. |
| `ref` | string | No | When `dry_run` is `true`, sets the branch or tag to use. Defaults to the project's default branch when not set. |
| `ref` | string | No | When `dry_run` is `true`, sets the branch or tag context to use to validate the CI/CD YAML configuration. Defaults to the project's default branch when not set. |
| `sha` | string | No | The commit SHA of a branch or tag. Defaults to the SHA of the head of the project's default branch when not set. |
Example request:

View File

@ -1794,6 +1794,7 @@ POST /projects/:id/fork
| `namespace` | integer or string | No | _(Deprecated)_ The ID or path of the namespace that the project is forked to. |
| `path` | string | No | The path assigned to the resultant project after forking. |
| `visibility` | string | No | The [visibility level](#project-visibility-level) assigned to the resultant project after forking. |
| `branches` | string | No | Branches to fork (empty for all branches). |
## List forks of a project

View File

@ -470,6 +470,7 @@ module API
optional :description, type: String, desc: 'The description that will be assigned to the fork', documentation: { example: 'Description' }
optional :visibility, type: String, values: Gitlab::VisibilityLevel.string_values, desc: 'The visibility of the fork'
optional :mr_default_target_self, type: Boolean, desc: 'Merge requests of this forked project targets itself by default'
optional :branches, type: String, desc: 'Branches to fork'
end
post ':id/fork', feature_category: :source_code_management do
Gitlab::QueryLimiting.disable!('https://gitlab.com/gitlab-org/gitlab/-/issues/20759')
@ -489,6 +490,7 @@ module API
service = ::Projects::ForkService.new(user_project, current_user, fork_params)
not_found!('Source Branch') if fork_params[:branches].present? && !service.valid_fork_branch?(fork_params[:branches])
not_found!('Target Namespace') unless service.valid_fork_target?
forked_project = service.execute

View File

@ -1,5 +1,5 @@
variables:
AUTO_BUILD_IMAGE_VERSION: 'v1.44.0'
AUTO_BUILD_IMAGE_VERSION: 'v1.46.0'
build:
stage: build

View File

@ -1,5 +1,5 @@
variables:
AUTO_BUILD_IMAGE_VERSION: 'v1.44.0'
AUTO_BUILD_IMAGE_VERSION: 'v1.46.0'
build:
stage: build

View File

@ -31,6 +31,7 @@ module Gitlab
'_test_gitlab_main_cell_' => :gitlab_main_cell,
'_test_gitlab_main_' => :gitlab_main,
'_test_gitlab_ci_' => :gitlab_ci,
'_test_gitlab_jh_' => :gitlab_jh,
'_test_gitlab_embedding_' => :gitlab_embedding,
'_test_gitlab_geo_' => :gitlab_geo,
'_test_gitlab_pm_' => :gitlab_pm,

View File

@ -3,7 +3,7 @@
module Gitlab
module Database
class TablesLocker
GITLAB_SCHEMAS_TO_IGNORE = %i[gitlab_embedding gitlab_geo].freeze
GITLAB_SCHEMAS_TO_IGNORE = %i[gitlab_embedding gitlab_geo gitlab_jh].freeze
def initialize(logger: nil, dry_run: false, include_partitions: true)
@logger = logger

View File

@ -3,7 +3,7 @@
module Gitlab
module Database
class TablesTruncate
GITLAB_SCHEMAS_TO_IGNORE = %i[gitlab_geo gitlab_embedding].freeze
GITLAB_SCHEMAS_TO_IGNORE = %i[gitlab_geo gitlab_embedding gitlab_jh].freeze
def initialize(database_name:, min_batch_size: 5, logger: nil, until_table: nil, dry_run: false)
@database_name = database_name

View File

@ -136,10 +136,13 @@ module Gitlab
response.base.presence
end
def fork_repository(source_repository)
def fork_repository(source_repository, branch = nil)
revision = branch.present? ? "refs/heads/#{branch}" : ""
request = Gitaly::CreateForkRequest.new(
repository: @gitaly_repo,
source_repository: source_repository.gitaly_repository
source_repository: source_repository.gitaly_repository,
revision: revision
)
gitaly_client_call(

View File

@ -20861,9 +20861,15 @@ msgstr ""
msgid "ForkProject|A fork is a copy of a project."
msgstr ""
msgid "ForkProject|All branches"
msgstr ""
msgid "ForkProject|An error occurred while forking the project. Please try again."
msgstr ""
msgid "ForkProject|Branches to include"
msgstr ""
msgid "ForkProject|Cancel"
msgstr ""
@ -20879,6 +20885,9 @@ msgstr ""
msgid "ForkProject|Internal"
msgstr ""
msgid "ForkProject|Only the default branch %{defaultBranch}"
msgstr ""
msgid "ForkProject|Please select a namespace"
msgstr ""
@ -29147,10 +29156,10 @@ msgstr ""
msgid "Maximum number of %{name} (%{count}) exceeded"
msgstr ""
msgid "Maximum number of changes (branches or tags) in a single push above which a bulk push event is created (default is `3`). Setting to `0` does not disable throttling."
msgid "Maximum number of changes (branches or tags) in a single push above which a bulk push event is created (default is 3). Setting to 0 does not disable throttling."
msgstr ""
msgid "Maximum number of changes (branches or tags) in a single push above which webhooks and integrations are not triggered (default is `3`). Setting to `0` does not disable throttling."
msgid "Maximum number of changes (branches or tags) in a single push above which webhooks and integrations are not triggered (default is 3). Setting to 0 does not disable throttling."
msgstr ""
msgid "Maximum number of comments exceeded"
@ -29171,7 +29180,7 @@ msgstr ""
msgid "Maximum number of requests per minute for an unauthenticated IP address"
msgstr ""
msgid "Maximum number of requests per minute for each raw path (default is `300`). Set to `0` to disable throttling."
msgid "Maximum number of requests per minute for each raw path (default is 300). Set to 0 to disable throttling."
msgstr ""
msgid "Maximum number of stages per value stream exceeded"
@ -44247,9 +44256,6 @@ msgstr ""
msgid "Set a password on your account to pull or push via %{protocol}."
msgstr ""
msgid "Set any rate limit to %{code_open}0%{code_close} to disable the limit."
msgstr ""
msgid "Set due date"
msgstr ""
@ -44355,6 +44361,12 @@ msgstr ""
msgid "Set to 0 for no size limit."
msgstr ""
msgid "Set to 0 to disable the limit."
msgstr ""
msgid "Set to 0 to disable the limits."
msgstr ""
msgid "Set to 0 to disable timeout."
msgstr ""
@ -54394,6 +54406,9 @@ msgstr ""
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr ""
msgid "WorkItem|Title cannot have more than %{WORK_ITEM_TITLE_MAX_LENGTH} characters."
msgstr ""
msgid "WorkItem|Turn off confidentiality"
msgstr ""
@ -55922,6 +55937,9 @@ msgstr[1] ""
msgid "branch name"
msgstr ""
msgid "branches"
msgstr ""
msgid "builds"
msgstr ""

View File

@ -35,6 +35,8 @@ module RuboCop
swap_foreign_keys
swap_indexes
reset_trigger_function
cleanup_conversion_of_integer_to_bigint
revert_initialize_conversion_of_integer_to_bigint
].sort.freeze
MSG = "The method is not allowed to be called within the `with_lock_retries` block, the only allowed methods are: #{ALLOWED_MIGRATION_METHODS.join(', ')}".freeze

View File

@ -14,6 +14,7 @@ RSpec.shared_examples 'validate dictionary' do |objects, directory_path, require
introduced_by_url
milestone
gitlab_schema
schema_inconsistencies
]
end
@ -169,7 +170,7 @@ RSpec.shared_examples 'validate dictionary' do |objects, directory_path, require
end
RSpec.describe 'Views documentation', feature_category: :database do
database_base_models = Gitlab::Database.database_base_models.select { |k, _| k != 'geo' }
database_base_models = Gitlab::Database.database_base_models.select { |k, _| %w[geo jh].exclude?(k) }
views = database_base_models.flat_map { |_, m| m.connection.views }.sort.uniq
directory_path = File.join('db', 'docs', 'views')
required_fields = %i[feature_categories view_name gitlab_schema]
@ -178,7 +179,7 @@ RSpec.describe 'Views documentation', feature_category: :database do
end
RSpec.describe 'Tables documentation', feature_category: :database do
database_base_models = Gitlab::Database.database_base_models.select { |k, _| k != 'geo' }
database_base_models = Gitlab::Database.database_base_models.select { |k, _| %w[geo jh].exclude?(k) }
tables = database_base_models.flat_map { |_, m| m.connection.tables }.sort.uniq
directory_path = File.join('db', 'docs')
required_fields = %i[feature_categories table_name gitlab_schema]

View File

@ -1,4 +1,11 @@
import { GlFormInputGroup, GlFormInput, GlForm, GlFormRadioGroup, GlFormRadio } from '@gitlab/ui';
import {
GlFormInputGroup,
GlFormInput,
GlForm,
GlFormRadioGroup,
GlFormRadio,
GlSprintf,
} from '@gitlab/ui';
import { getByRole } from '@testing-library/dom';
import { mount, shallowMount } from '@vue/test-utils';
import axios from 'axios';
@ -41,6 +48,7 @@ describe('ForkForm component', () => {
projectPath: 'project-name',
projectDescription: 'some project description',
projectVisibility: 'private',
projectDefaultBranch: 'main',
restrictedVisibilityLevels: [],
};
@ -96,6 +104,7 @@ describe('ForkForm component', () => {
GlFormInput,
GlFormRadioGroup,
GlFormRadio,
GlSprintf,
},
});
};
@ -118,13 +127,13 @@ describe('ForkForm component', () => {
const findInternalRadio = () => wrapper.find('[data-testid="radio-internal"]');
const findPublicRadio = () => wrapper.find('[data-testid="radio-public"]');
const findForkNameInput = () => wrapper.find('[data-testid="fork-name-input"]');
const findGlFormRadioGroup = () => wrapper.findComponent(GlFormRadioGroup);
const findForkUrlInput = () => wrapper.findComponent(ProjectNamespace);
const findForkSlugInput = () => wrapper.find('[data-testid="fork-slug-input"]');
const findForkDescriptionTextarea = () =>
wrapper.find('[data-testid="fork-description-textarea"]');
const findVisibilityRadioGroup = () =>
wrapper.find('[data-testid="fork-visibility-radio-group"]');
const findBranchesRadioGroup = () => wrapper.find('[data-testid="fork-branches-radio-group"]');
it('will go to cancelPath when click cancel button', () => {
createComponent();
@ -203,11 +212,25 @@ describe('ForkForm component', () => {
});
});
describe('branches options', () => {
const formRadios = () => findBranchesRadioGroup().findAllComponents(GlFormRadio);
it('displays 2 branches options', () => {
createComponent();
expect(formRadios()).toHaveLength(2);
});
it('displays the correct description for each option', () => {
createComponent();
expect(formRadios().at(0).text()).toBe('All branches');
expect(formRadios().at(1).text()).toMatchInterpolatedText('Only the default branch main');
});
});
describe('visibility level', () => {
it('displays the correct description', () => {
createComponent();
const formRadios = wrapper.findAllComponents(GlFormRadio);
const formRadios = findVisibilityRadioGroup().findAllComponents(GlFormRadio);
Object.keys(PROJECT_VISIBILITY_TYPE).forEach((visibilityType, index) => {
expect(formRadios.at(index).text()).toBe(PROJECT_VISIBILITY_TYPE[visibilityType]);
@ -217,7 +240,7 @@ describe('ForkForm component', () => {
it('displays all 3 visibility levels', () => {
createComponent();
expect(wrapper.findAllComponents(GlFormRadio)).toHaveLength(3);
expect(findVisibilityRadioGroup().findAllComponents(GlFormRadio)).toHaveLength(3);
});
describe('when the namespace is changed', () => {
@ -236,7 +259,7 @@ describe('ForkForm component', () => {
it('resets the visibility to max allowed below current level', async () => {
createFullComponent({ projectVisibility: 'public' }, { namespaces });
expect(findGlFormRadioGroup().vm.$attrs.checked).toBe('public');
expect(findVisibilityRadioGroup().vm.$attrs.checked).toBe('public');
fillForm({
name: 'one',
@ -251,7 +274,7 @@ describe('ForkForm component', () => {
it('does not reset the visibility when current level is allowed', async () => {
createFullComponent({ projectVisibility: 'public' }, { namespaces });
expect(findGlFormRadioGroup().vm.$attrs.checked).toBe('public');
expect(findVisibilityRadioGroup().vm.$attrs.checked).toBe('public');
fillForm({
name: 'two',
@ -266,7 +289,7 @@ describe('ForkForm component', () => {
it('does not reset the visibility when visibility cap is increased', async () => {
createFullComponent({ projectVisibility: 'public' }, { namespaces });
expect(findGlFormRadioGroup().vm.$attrs.checked).toBe('public');
expect(findVisibilityRadioGroup().vm.$attrs.checked).toBe('public');
fillForm({
name: 'three',
@ -291,7 +314,7 @@ describe('ForkForm component', () => {
{ namespaces },
);
await findGlFormRadioGroup().vm.$emit('input', 'internal');
await findVisibilityRadioGroup().vm.$emit('input', 'internal');
fillForm({
name: 'five',
id: 5,
@ -469,7 +492,7 @@ describe('ForkForm component', () => {
jest.spyOn(axios, 'post');
setupComponent();
await findGlFormRadioGroup().vm.$emit('input', null);
await findVisibilityRadioGroup().vm.$emit('input', null);
await nextTick();
@ -533,6 +556,7 @@ describe('ForkForm component', () => {
const url = `/api/${GON_API_VERSION}/projects/${projectId}/fork`;
const project = {
branches: '',
description: projectDescription,
id: projectId,
name: projectName,

View File

@ -131,5 +131,25 @@ describe('WorkItemTitle component', () => {
property: 'type_Task',
});
});
describe('when title has more than 255 characters', () => {
const title = new Array(257).join('a');
it('does not call a mutation', () => {
createComponent();
findItemTitle().vm.$emit('title-changed', title);
expect(mutationSuccessHandler).not.toHaveBeenCalled();
});
it('emits an error message', () => {
createComponent();
findItemTitle().vm.$emit('title-changed', title);
expect(wrapper.emitted('error')).toEqual([['Title cannot have more than 255 characters.']]);
});
});
});
});

View File

@ -11,6 +11,7 @@ RSpec.describe Admin::ComponentsHelper, feature_category: :database do
}
main[:ci] = { adapter_name: 'PostgreSQL', version: expected_version } if Gitlab::Database.has_config?(:ci)
main[:geo] = { adapter_name: 'PostgreSQL', version: expected_version } if Gitlab::Database.has_config?(:geo)
main[:jh] = { adapter_name: 'PostgreSQL', version: expected_version } if Gitlab::Database.has_config?(:jh)
main
end

View File

@ -10,9 +10,11 @@ RSpec.describe Gitlab::Diff::FileCollection::Compare do
let(:start_commit) { sample_image_commit }
let(:head_commit) { sample_commit }
let(:raw_compare) do
Gitlab::Git::Compare.new(project.repository.raw_repository,
start_commit.id,
head_commit.id)
Gitlab::Git::Compare.new(
project.repository.raw_repository,
start_commit.id,
head_commit.id
)
end
let(:diffable) { Compare.new(raw_compare, project) }

View File

@ -10,10 +10,7 @@ RSpec.describe Gitlab::Diff::FileCollection::MergeRequestDiffBatch, feature_cate
let(:diff_files_relation) { diffable.merge_request_diff_files }
subject do
described_class.new(diffable,
batch_page,
batch_size,
diff_options: nil)
described_class.new(diffable, batch_page, batch_size, diff_options: nil)
end
let(:diff_files) { subject.diff_files }
@ -87,10 +84,7 @@ RSpec.describe Gitlab::Diff::FileCollection::MergeRequestDiffBatch, feature_cate
context 'last page' do
it 'returns correct diff files' do
last_page = diff_files_relation.count - batch_size
collection = described_class.new(diffable,
last_page,
batch_size,
diff_options: nil)
collection = described_class.new(diffable, last_page, batch_size, diff_options: nil)
expected_batch_files = diff_files_relation.offset(last_page).limit(batch_size).map(&:new_path)
@ -101,10 +95,7 @@ RSpec.describe Gitlab::Diff::FileCollection::MergeRequestDiffBatch, feature_cate
it_behaves_like 'unfoldable diff' do
subject do
described_class.new(merge_request.merge_request_diff,
batch_page,
batch_size,
diff_options: nil)
described_class.new(merge_request.merge_request_diff, batch_page, batch_size, diff_options: nil)
end
end
@ -118,10 +109,7 @@ RSpec.describe Gitlab::Diff::FileCollection::MergeRequestDiffBatch, feature_cate
let(:stub_path) { '.gitignore' }
subject do
described_class.new(merge_request.merge_request_diff,
batch_page,
batch_size,
**collection_default_args)
described_class.new(merge_request.merge_request_diff, batch_page, batch_size, **collection_default_args)
end
end
@ -136,10 +124,7 @@ RSpec.describe Gitlab::Diff::FileCollection::MergeRequestDiffBatch, feature_cate
end
subject do
described_class.new(merge_request.merge_request_diff,
batch_page,
batch_size,
**collection_default_args)
described_class.new(merge_request.merge_request_diff, batch_page, batch_size, **collection_default_args)
end
end
end

View File

@ -11,9 +11,7 @@ RSpec.describe Gitlab::Diff::FileCollection::PaginatedMergeRequestDiff, feature_
let(:diff_files) { subject.diff_files }
subject do
described_class.new(diffable,
page,
per_page)
described_class.new(diffable, page, per_page)
end
describe '#diff_files' do
@ -79,9 +77,7 @@ RSpec.describe Gitlab::Diff::FileCollection::PaginatedMergeRequestDiff, feature_
context 'when last page' do
it 'returns correct diff files' do
last_page = diff_files_relation.count - per_page
collection = described_class.new(diffable,
last_page,
per_page)
collection = described_class.new(diffable, last_page, per_page)
expected_batch_files = diff_files_relation.page(last_page).per(per_page).map(&:new_path)
@ -92,9 +88,7 @@ RSpec.describe Gitlab::Diff::FileCollection::PaginatedMergeRequestDiff, feature_
it_behaves_like 'unfoldable diff' do
subject do
described_class.new(merge_request.merge_request_diff,
page,
per_page)
described_class.new(merge_request.merge_request_diff, page, per_page)
end
end
@ -106,9 +100,7 @@ RSpec.describe Gitlab::Diff::FileCollection::PaginatedMergeRequestDiff, feature_
let(:diffable) { merge_request.merge_request_diff }
subject do
described_class.new(merge_request.merge_request_diff,
page,
per_page)
described_class.new(merge_request.merge_request_diff, page, per_page)
end
end
end

View File

@ -407,10 +407,7 @@ RSpec.describe Gitlab::Diff::File do
context 'diff file stats' do
let(:diff_file) do
described_class.new(diff,
diff_refs: commit.diff_refs,
repository: project.repository,
stats: stats)
described_class.new(diff, diff_refs: commit.diff_refs, repository: project.repository, stats: stats)
end
let(:raw_diff) do

View File

@ -49,10 +49,12 @@ RSpec.describe Gitlab::Diff::HighlightCache, :clean_gitlab_redis_cache, feature_
let(:diff_file) do
diffs = merge_request.diffs
raw_diff = diffs.diffable.raw_diffs(diffs.diff_options.merge(paths: ['CHANGELOG'])).first
Gitlab::Diff::File.new(raw_diff,
repository: diffs.project.repository,
diff_refs: diffs.diff_refs,
fallback_diff_refs: diffs.fallback_diff_refs)
Gitlab::Diff::File.new(
raw_diff,
repository: diffs.project.repository,
diff_refs: diffs.diff_refs,
fallback_diff_refs: diffs.fallback_diff_refs
)
end
before do
@ -227,10 +229,12 @@ RSpec.describe Gitlab::Diff::HighlightCache, :clean_gitlab_redis_cache, feature_
let(:diff_file) do
diffs = merge_request.diffs
raw_diff = diffs.diffable.raw_diffs(diffs.diff_options.merge(paths: ['CHANGELOG'])).first
Gitlab::Diff::File.new(raw_diff,
repository: diffs.project.repository,
diff_refs: diffs.diff_refs,
fallback_diff_refs: diffs.fallback_diff_refs)
Gitlab::Diff::File.new(
raw_diff,
repository: diffs.project.repository,
diff_refs: diffs.diff_refs,
fallback_diff_refs: diffs.fallback_diff_refs
)
end
it "uses ActiveSupport::Gzip when reading from the cache" do

View File

@ -11,10 +11,16 @@ RSpec.describe Gitlab::Diff::Line do
end
let(:line) do
described_class.new('<input>', 'match', 0, 0, 1,
parent_file: double(:file),
line_code: double(:line_code),
rich_text: rich_text)
described_class.new(
'<input>',
'match',
0,
0,
1,
parent_file: double(:file),
line_code: double(:line_code),
rich_text: rich_text
)
end
let(:rich_text) { nil }

View File

@ -22,9 +22,7 @@ RSpec.describe Gitlab::Diff::SuggestionDiff do
end
let(:suggestion) do
instance_double(Suggestion, from_line: 12,
from_content: from_content,
to_content: to_content)
instance_double(Suggestion, from_line: 12, from_content: from_content, to_content: to_content)
end
subject { described_class.new(suggestion).diff_lines }
@ -56,9 +54,12 @@ RSpec.describe Gitlab::Diff::SuggestionDiff do
it 'returns a correct value if there is no newline at the end of the file' do
from_content = "One line test"
to_content = "Successful test!"
suggestion = instance_double(Suggestion, from_line: 1,
from_content: from_content,
to_content: to_content)
suggestion = instance_double(
Suggestion,
from_line: 1,
from_content: from_content,
to_content: to_content
)
diff_lines = described_class.new(suggestion).diff_lines

View File

@ -5,10 +5,12 @@ require 'spec_helper'
RSpec.describe Gitlab::Diff::Suggestion do
shared_examples 'correct suggestion raw content' do
it 'returns correct raw data' do
expect(suggestion.to_hash).to include(from_content: expected_lines.join,
to_content: "#{text}\n",
lines_above: above,
lines_below: below)
expect(suggestion.to_hash).to include(
from_content: expected_lines.join,
to_content: "#{text}\n",
lines_above: above,
lines_below: below
)
end
it 'returns diff lines with correct line numbers' do
@ -25,11 +27,13 @@ RSpec.describe Gitlab::Diff::Suggestion do
let(:merge_request) { create(:merge_request) }
let(:project) { merge_request.project }
let(:position) do
Gitlab::Diff::Position.new(old_path: "files/ruby/popen.rb",
new_path: "files/ruby/popen.rb",
old_line: nil,
new_line: 9,
diff_refs: merge_request.diff_refs)
Gitlab::Diff::Position.new(
old_path: "files/ruby/popen.rb",
new_path: "files/ruby/popen.rb",
old_line: nil,
new_line: 9,
diff_refs: merge_request.diff_refs
)
end
let(:diff_file) do

View File

@ -7,11 +7,13 @@ RSpec.describe Gitlab::Diff::SuggestionsParser do
let(:merge_request) { create(:merge_request) }
let(:project) { merge_request.project }
let(:position) do
Gitlab::Diff::Position.new(old_path: "files/ruby/popen.rb",
new_path: "files/ruby/popen.rb",
old_line: nil,
new_line: 9,
diff_refs: merge_request.diff_refs)
Gitlab::Diff::Position.new(
old_path: "files/ruby/popen.rb",
new_path: "files/ruby/popen.rb",
old_line: nil,
new_line: 9,
diff_refs: merge_request.diff_refs
)
end
let(:diff_file) do
@ -19,8 +21,7 @@ RSpec.describe Gitlab::Diff::SuggestionsParser do
end
subject do
described_class.parse(markdown, project: merge_request.project,
position: position)
described_class.parse(markdown, project: merge_request.project, position: position)
end
def blob_lines_data(from_line, to_line)
@ -59,15 +60,19 @@ RSpec.describe Gitlab::Diff::SuggestionsParser do
from_line = position.new_line
to_line = position.new_line
expect(subject.first.to_hash).to include(from_content: blob_lines_data(from_line, to_line),
to_content: " foo\n bar\n",
lines_above: 0,
lines_below: 0)
expect(subject.first.to_hash).to include(
from_content: blob_lines_data(from_line, to_line),
to_content: " foo\n bar\n",
lines_above: 0,
lines_below: 0
)
expect(subject.second.to_hash).to include(from_content: blob_lines_data(from_line, to_line),
to_content: " xpto\n baz\n",
lines_above: 0,
lines_below: 0)
expect(subject.second.to_hash).to include(
from_content: blob_lines_data(from_line, to_line),
to_content: " xpto\n baz\n",
lines_above: 0,
lines_below: 0
)
end
end
@ -105,30 +110,36 @@ RSpec.describe Gitlab::Diff::SuggestionsParser do
from_line = position.new_line - 2
to_line = position.new_line + 1
expect(subject.first.to_hash).to include(from_content: blob_lines_data(from_line, to_line),
to_content: " # above and below\n",
lines_above: 2,
lines_below: 1)
expect(subject.first.to_hash).to include(
from_content: blob_lines_data(from_line, to_line),
to_content: " # above and below\n",
lines_above: 2,
lines_below: 1
)
end
it 'suggestion with above param has correct data' do
from_line = position.new_line - 3
to_line = position.new_line
expect(subject.second.to_hash).to eq(from_content: blob_lines_data(from_line, to_line),
to_content: " # only above\n",
lines_above: 3,
lines_below: 0)
expect(subject.second.to_hash).to eq(
from_content: blob_lines_data(from_line, to_line),
to_content: " # only above\n",
lines_above: 3,
lines_below: 0
)
end
it 'suggestion with below param has correct data' do
from_line = position.new_line
to_line = position.new_line + 3
expect(subject.third.to_hash).to eq(from_content: blob_lines_data(from_line, to_line),
to_content: " # only below\n",
lines_above: 0,
lines_below: 3)
expect(subject.third.to_hash).to eq(
from_content: blob_lines_data(from_line, to_line),
to_content: " # only below\n",
lines_above: 0,
lines_below: 3
)
end
end
end

View File

@ -140,6 +140,44 @@ RSpec.describe Gitlab::GitalyClient::RepositoryService, feature_category: :gital
end
end
describe '#fork_repository' do
let(:source_repository) { Gitlab::Git::Repository.new('default', 'repo/path', '', 'group/project') }
context 'when branch is not provided' do
it 'sends a create_fork message' do
expected_request = gitaly_request_with_params(
source_repository: source_repository.gitaly_repository,
revision: ""
)
expect_any_instance_of(Gitaly::RepositoryService::Stub)
.to receive(:create_fork)
.with(expected_request, kind_of(Hash))
.and_return(double(value: true))
client.fork_repository(source_repository)
end
end
context 'when branch is provided' do
it 'sends a create_fork message including revision' do
branch = 'wip'
expected_request = gitaly_request_with_params(
source_repository: source_repository.gitaly_repository,
revision: "refs/heads/#{branch}"
)
expect_any_instance_of(Gitaly::RepositoryService::Stub)
.to receive(:create_fork)
.with(expected_request, kind_of(Hash))
.and_return(double(value: true))
client.fork_repository(source_repository, branch)
end
end
end
describe '#import_repository' do
let(:source) { 'https://example.com/git/repo.git' }

View File

@ -6023,12 +6023,10 @@ RSpec.describe MergeRequest, factory_default: :keep, feature_category: :code_rev
allow(merge_request_diff).to receive(:patch_id_sha).and_return(nil)
allow(merge_request).to receive(:diff_refs).and_return(diff_refs)
allow_next_instance_of(Repository) do |repo|
allow(repo)
.to receive(:get_patch_id)
.with(diff_refs.base_sha, diff_refs.head_sha)
.and_return(patch_id)
end
allow(merge_request.project.repository)
.to receive(:get_patch_id)
.with(diff_refs.base_sha, diff_refs.head_sha)
.and_return(patch_id)
end
it { is_expected.to eq(patch_id) }

View File

@ -510,6 +510,26 @@ RSpec.describe Projects::ForkService, feature_category: :source_code_management
end
end
describe '#valid_fork_branch?' do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project, :small_repo, creator_id: user.id) }
let_it_be(:branch) { nil }
subject { described_class.new(project, user).valid_fork_branch?(branch) }
context 'when branch exists' do
let(:branch) { project.default_branch_or_main }
it { is_expected.to be_truthy }
end
context 'when branch does not exist' do
let(:branch) { 'branch-that-does-not-exist' }
it { is_expected.to be_falsey }
end
end
describe '#valid_fork_target?' do
let(:project) { Project.new }
let(:params) { {} }

View File

@ -2,7 +2,7 @@
RSpec.shared_examples 'Prometheus Alert based health indicator' do
let(:schema) { :main }
let(:connection) { Gitlab::Database.database_base_models[schema].connection }
let(:connection) { Gitlab::Database.database_base_models_with_gitlab_shared[schema].connection }
around do |example|
Gitlab::Database::SharedModel.using_connection(connection) do
@ -124,7 +124,7 @@ RSpec.shared_examples 'Prometheus Alert based health indicator' do
end
end
Gitlab::Database.database_base_models.each do |database_base_model, connection|
Gitlab::Database.database_base_models_with_gitlab_shared.each do |database_base_model, connection|
next unless connection.present?
it_behaves_like 'Patroni Apdex Evaluator', database_base_model.to_sym

View File

@ -149,6 +149,7 @@ RSpec.describe 'gitlab:background_migrations namespace rake tasks', :suppress_gi
context 'with two connections sharing the same database' do
before do
skip_if_database_exists(:ci)
skip_if_database_exists(:jh)
end
it 'skips the shared database' do

View File

@ -579,6 +579,10 @@ RSpec.describe 'gitlab:db namespace rake task', :silence_stdout, feature_categor
allow(File).to receive(:open).with(Rails.root.join('ee/db/geo/structure.sql').to_s, any_args).and_yield(output)
allow(File).to receive(:open).with(Rails.root.join('ee/db/embedding/structure.sql').to_s, any_args).and_yield(output)
end
if Gitlab.jh?
allow(File).to receive(:open).with(Rails.root.join('jh/db/structure.sql').to_s, any_args).and_yield(output)
end
end
after do

View File

@ -19,11 +19,11 @@ RSpec.describe RepositoryForkWorker, feature_category: :source_code_management d
fork_project(project, forked_project.creator, target_project: forked_project, repository: true)
end
shared_examples 'RepositoryForkWorker performing' do
def expect_fork_repository(success:)
shared_examples 'RepositoryForkWorker performing' do |branch|
def expect_fork_repository(success:, branch:)
allow(::Gitlab::GitalyClient::RepositoryService).to receive(:new).and_call_original
expect_next_instance_of(::Gitlab::GitalyClient::RepositoryService, forked_project.repository.raw) do |svc|
exp = expect(svc).to receive(:fork_repository).with(project.repository.raw)
exp = expect(svc).to receive(:fork_repository).with(project.repository.raw, branch)
if success
exp.and_return(true)
@ -39,20 +39,20 @@ RSpec.describe RepositoryForkWorker, feature_category: :source_code_management d
it 'creates a new repository from a fork' do
allow(subject).to receive(:jid).and_return(jid)
expect_fork_repository(success: true)
expect_fork_repository(success: true, branch: branch)
perform!
end
end
it "creates a new repository from a fork" do
expect_fork_repository(success: true)
expect_fork_repository(success: true, branch: branch)
perform!
end
it 'protects the default branch' do
expect_fork_repository(success: true)
expect_fork_repository(success: true, branch: branch)
perform!
@ -60,7 +60,7 @@ RSpec.describe RepositoryForkWorker, feature_category: :source_code_management d
end
it 'flushes various caches' do
expect_fork_repository(success: true)
expect_fork_repository(success: true, branch: branch)
# Works around https://github.com/rspec/rspec-mocks/issues/910
expect(Project).to receive(:find).with(forked_project.id).and_return(forked_project)
@ -79,13 +79,13 @@ RSpec.describe RepositoryForkWorker, feature_category: :source_code_management d
it 'handles bad fork' do
error_message = "Unable to fork project #{forked_project.id} for repository #{project.disk_path} -> #{forked_project.disk_path}: Failed to create fork repository"
expect_fork_repository(success: false)
expect_fork_repository(success: false, branch: branch)
expect { perform! }.to raise_error(StandardError, error_message)
end
it 'calls Projects::LfsPointers::LfsLinkService#execute with OIDs of source project LFS objects' do
expect_fork_repository(success: true)
expect_fork_repository(success: true, branch: branch)
expect_next_instance_of(Projects::LfsPointers::LfsLinkService) do |service|
expect(service).to receive(:execute).with(project.lfs_objects_oids)
end
@ -96,7 +96,7 @@ RSpec.describe RepositoryForkWorker, feature_category: :source_code_management d
it "handles LFS objects link failure" do
error_message = "Unable to fork project #{forked_project.id} for repository #{project.disk_path} -> #{forked_project.disk_path}: Source project has too many LFS objects"
expect_fork_repository(success: true)
expect_fork_repository(success: true, branch: branch)
expect_next_instance_of(Projects::LfsPointers::LfsLinkService) do |service|
expect(service).to receive(:execute).and_raise(Projects::LfsPointers::LfsLinkService::TooManyOidsError)
end
@ -113,6 +113,16 @@ RSpec.describe RepositoryForkWorker, feature_category: :source_code_management d
it_behaves_like 'RepositoryForkWorker performing'
end
context 'when a specific branch is requested' do
def perform!
forked_project.create_import_data(data: { fork_branch: 'wip' })
subject.perform(forked_project.id)
end
it_behaves_like 'RepositoryForkWorker performing', 'wip'
end
context 'project ID, storage and repo paths passed' do
def perform!
subject.perform(forked_project.id, 'repos/path', project.disk_path)