diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-11-01 06:10:42 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-11-01 06:10:42 +0300 |
commit | 24ed1c84da7fb6df910f06552bc9e2e7fe5bcb59 (patch) | |
tree | 2e648cbac693d1fe3dd2720c9f608470998d6b03 | |
parent | 533fed8bd825f93b4b43bd41d41caa38cfc6ae55 (diff) |
Add latest changes from gitlab-org/gitlab@master
50 files changed, 438 insertions, 165 deletions
diff --git a/.rubocop_todo/layout/argument_alignment.yml b/.rubocop_todo/layout/argument_alignment.yml index 982304c0220..7b372bfd01a 100644 --- a/.rubocop_todo/layout/argument_alignment.yml +++ b/.rubocop_todo/layout/argument_alignment.yml @@ -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' diff --git a/app/assets/javascripts/pages/projects/forks/new/components/fork_form.vue b/app/assets/javascripts/pages/projects/forks/new/components/fork_form.vue index 9659c927fbf..e3d50e900ca 100644 --- a/app/assets/javascripts/pages/projects/forks/new/components/fork_form.vue +++ b/app/assets/javascripts/pages/projects/forks/new/components/fork_form.vue @@ -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')" diff --git a/app/assets/javascripts/pages/projects/forks/new/index.js b/app/assets/javascripts/pages/projects/forks/new/index.js index a31b8b1a1f4..694914e9154 100644 --- a/app/assets/javascripts/pages/projects/forks/new/index.js +++ b/app/assets/javascripts/pages/projects/forks/new/index.js @@ -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), }, diff --git a/app/assets/javascripts/work_items/components/work_item_title.vue b/app/assets/javascripts/work_items/components/work_item_title.vue index 966a72631c6..9b5803421dd 100644 --- a/app/assets/javascripts/work_items/components/work_item_title.vue +++ b/app/assets/javascripts/work_items/components/work_item_title.vue @@ -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, diff --git a/app/assets/javascripts/work_items/constants.js b/app/assets/javascripts/work_items/constants.js index e4fa277485a..9632165b8cb 100644 --- a/app/assets/javascripts/work_items/constants.js +++ b/app/assets/javascripts/work_items/constants.js @@ -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', ); diff --git a/app/models/project.rb b/app/models/project.rb index b8f02297ad7..bc6d2600d83 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -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 diff --git a/app/services/projects/fork_service.rb b/app/services/projects/fork_service.rb index aace8846afc..168420b17bf 100644 --- a/app/services/projects/fork_service.rb +++ b/app/services/projects/fork_service.rb @@ -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 diff --git a/app/views/admin/application_settings/_gitlab_shell_operation_limits.html.haml b/app/views/admin/application_settings/_gitlab_shell_operation_limits.html.haml index 8529accff8e..22372146ea1 100644 --- a/app/views/admin/application_settings/_gitlab_shell_operation_limits.html.haml +++ b/app/views/admin/application_settings/_gitlab_shell_operation_limits.html.haml @@ -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 diff --git a/app/views/admin/application_settings/_import_export_limits.html.haml b/app/views/admin/application_settings/_import_export_limits.html.haml index 8cb7915f847..269a1497324 100644 --- a/app/views/admin/application_settings/_import_export_limits.html.haml +++ b/app/views/admin/application_settings/_import_export_limits.html.haml @@ -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 diff --git a/app/views/admin/application_settings/_performance.html.haml b/app/views/admin/application_settings/_performance.html.haml index bfa548b70e5..14c785509bd 100644 --- a/app/views/admin/application_settings/_performance.html.haml +++ b/app/views/admin/application_settings/_performance.html.haml @@ -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 diff --git a/app/views/admin/application_settings/_projects_api_limits.html.haml b/app/views/admin/application_settings/_projects_api_limits.html.haml index d84df972c6d..c9eff76916a 100644 --- a/app/views/admin/application_settings/_projects_api_limits.html.haml +++ b/app/views/admin/application_settings/_projects_api_limits.html.haml @@ -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 diff --git a/app/views/projects/forks/new.html.haml b/app/views/projects/forks/new.html.haml index e9c6b3fcd22..1194a361753 100644 --- a/app/views/projects/forks/new.html.haml +++ b/app/views/projects/forks/new.html.haml @@ -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 } } diff --git a/app/workers/repository_fork_worker.rb b/app/workers/repository_fork_worker.rb index 5ec9ceaf004..f4a507246ac 100644 --- a/app/workers/repository_fork_worker.rb +++ b/app/workers/repository_fork_worker.rb @@ -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) diff --git a/db/docs/namespaces.yml b/db/docs/namespaces.yml index ba3d345d8c7..4010858ce5a 100644 --- a/db/docs/namespaces.yml +++ b/db/docs/namespaces.yml @@ -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 diff --git a/db/post_migrate/20231024015915_drop_index_namespaces_on_created_at_for_gitlab_com.rb b/db/post_migrate/20231024015915_drop_index_namespaces_on_created_at_for_gitlab_com.rb new file mode 100644 index 00000000000..8f2f8a4064c --- /dev/null +++ b/db/post_migrate/20231024015915_drop_index_namespaces_on_created_at_for_gitlab_com.rb @@ -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 diff --git a/db/post_migrate/20231026103346_drop_project_settings_jitsu_key.rb b/db/post_migrate/20231026103346_drop_project_settings_jitsu_key.rb new file mode 100644 index 00000000000..606648ca7fa --- /dev/null +++ b/db/post_migrate/20231026103346_drop_project_settings_jitsu_key.rb @@ -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 diff --git a/db/schema_migrations/20231024015915 b/db/schema_migrations/20231024015915 new file mode 100644 index 00000000000..7f6eac81c71 --- /dev/null +++ b/db/schema_migrations/20231024015915 @@ -0,0 +1 @@ +8ad5065584f72084ee929e479725593330d0d13542dc4939476d62f831c6f2e8
\ No newline at end of file diff --git a/db/schema_migrations/20231026103346 b/db/schema_migrations/20231026103346 new file mode 100644 index 00000000000..53f5520bcc4 --- /dev/null +++ b/db/schema_migrations/20231026103346 @@ -0,0 +1 @@ +dc0065c2caffdf5bbf79c1e94f8bdb6d415a836cc575109d25df8217423be0e1
\ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index 925db79d44c..a9e416c4c57 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -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)), diff --git a/doc/api/lint.md b/doc/api/lint.md index 7b288c34343..45ae739ef86 100644 --- a/doc/api/lint.md +++ b/doc/api/lint.md @@ -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: diff --git a/doc/api/projects.md b/doc/api/projects.md index f909f376fce..516418a387b 100644 --- a/doc/api/projects.md +++ b/doc/api/projects.md @@ -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 diff --git a/lib/api/projects.rb b/lib/api/projects.rb index 1f0b608b67c..d2e297f4213 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -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 diff --git a/lib/gitlab/ci/templates/Jobs/Build.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/Build.gitlab-ci.yml index 2d04c97b32e..9620a214792 100644 --- a/lib/gitlab/ci/templates/Jobs/Build.gitlab-ci.yml +++ b/lib/gitlab/ci/templates/Jobs/Build.gitlab-ci.yml @@ -1,5 +1,5 @@ variables: - AUTO_BUILD_IMAGE_VERSION: 'v1.44.0' + AUTO_BUILD_IMAGE_VERSION: 'v1.46.0' build: stage: build diff --git a/lib/gitlab/ci/templates/Jobs/Build.latest.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/Build.latest.gitlab-ci.yml index 2d04c97b32e..9620a214792 100644 --- a/lib/gitlab/ci/templates/Jobs/Build.latest.gitlab-ci.yml +++ b/lib/gitlab/ci/templates/Jobs/Build.latest.gitlab-ci.yml @@ -1,5 +1,5 @@ variables: - AUTO_BUILD_IMAGE_VERSION: 'v1.44.0' + AUTO_BUILD_IMAGE_VERSION: 'v1.46.0' build: stage: build diff --git a/lib/gitlab/database/gitlab_schema.rb b/lib/gitlab/database/gitlab_schema.rb index 31ceb898eee..e885df52dfd 100644 --- a/lib/gitlab/database/gitlab_schema.rb +++ b/lib/gitlab/database/gitlab_schema.rb @@ -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, diff --git a/lib/gitlab/database/tables_locker.rb b/lib/gitlab/database/tables_locker.rb index aa880b709fe..608dea9e3c5 100644 --- a/lib/gitlab/database/tables_locker.rb +++ b/lib/gitlab/database/tables_locker.rb @@ -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 diff --git a/lib/gitlab/database/tables_truncate.rb b/lib/gitlab/database/tables_truncate.rb index f91146fff3d..5394dee6fec 100644 --- a/lib/gitlab/database/tables_truncate.rb +++ b/lib/gitlab/database/tables_truncate.rb @@ -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 diff --git a/lib/gitlab/gitaly_client/repository_service.rb b/lib/gitlab/gitaly_client/repository_service.rb index d92bf5263f1..457380615f7 100644 --- a/lib/gitlab/gitaly_client/repository_service.rb +++ b/lib/gitlab/gitaly_client/repository_service.rb @@ -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( diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 0f2242baee3..3f68ca49f3c 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -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 "" diff --git a/rubocop/cop/migration/with_lock_retries_disallowed_method.rb b/rubocop/cop/migration/with_lock_retries_disallowed_method.rb index 471d98f5416..e019e5bd0cf 100644 --- a/rubocop/cop/migration/with_lock_retries_disallowed_method.rb +++ b/rubocop/cop/migration/with_lock_retries_disallowed_method.rb @@ -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 diff --git a/spec/db/docs_spec.rb b/spec/db/docs_spec.rb index 8d4cb3ac5ef..500d6881a2d 100644 --- a/spec/db/docs_spec.rb +++ b/spec/db/docs_spec.rb @@ -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] diff --git a/spec/frontend/pages/projects/forks/new/components/fork_form_spec.js b/spec/frontend/pages/projects/forks/new/components/fork_form_spec.js index 7bc4cd4d541..b0bfa4620c6 100644 --- a/spec/frontend/pages/projects/forks/new/components/fork_form_spec.js +++ b/spec/frontend/pages/projects/forks/new/components/fork_form_spec.js @@ -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, diff --git a/spec/frontend/work_items/components/work_item_title_spec.js b/spec/frontend/work_items/components/work_item_title_spec.js index 34391b74cf7..0f466bcf691 100644 --- a/spec/frontend/work_items/components/work_item_title_spec.js +++ b/spec/frontend/work_items/components/work_item_title_spec.js @@ -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.']]); + }); + }); }); }); diff --git a/spec/helpers/admin/components_helper_spec.rb b/spec/helpers/admin/components_helper_spec.rb index bb590d003ad..b2107f99a34 100644 --- a/spec/helpers/admin/components_helper_spec.rb +++ b/spec/helpers/admin/components_helper_spec.rb @@ -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 diff --git a/spec/lib/gitlab/diff/file_collection/compare_spec.rb b/spec/lib/gitlab/diff/file_collection/compare_spec.rb index c3f768db7f0..5469a43e46e 100644 --- a/spec/lib/gitlab/diff/file_collection/compare_spec.rb +++ b/spec/lib/gitlab/diff/file_collection/compare_spec.rb @@ -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) } diff --git a/spec/lib/gitlab/diff/file_collection/merge_request_diff_batch_spec.rb b/spec/lib/gitlab/diff/file_collection/merge_request_diff_batch_spec.rb index 8e14f48ae29..65e96f8e936 100644 --- a/spec/lib/gitlab/diff/file_collection/merge_request_diff_batch_spec.rb +++ b/spec/lib/gitlab/diff/file_collection/merge_request_diff_batch_spec.rb @@ -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 diff --git a/spec/lib/gitlab/diff/file_collection/paginated_merge_request_diff_spec.rb b/spec/lib/gitlab/diff/file_collection/paginated_merge_request_diff_spec.rb index ee956d04325..891336658ce 100644 --- a/spec/lib/gitlab/diff/file_collection/paginated_merge_request_diff_spec.rb +++ b/spec/lib/gitlab/diff/file_collection/paginated_merge_request_diff_spec.rb @@ -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 diff --git a/spec/lib/gitlab/diff/file_spec.rb b/spec/lib/gitlab/diff/file_spec.rb index ad2524e40c5..bc4fc49b1b7 100644 --- a/spec/lib/gitlab/diff/file_spec.rb +++ b/spec/lib/gitlab/diff/file_spec.rb @@ -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 diff --git a/spec/lib/gitlab/diff/highlight_cache_spec.rb b/spec/lib/gitlab/diff/highlight_cache_spec.rb index c51eaa4fa18..94a5d30283c 100644 --- a/spec/lib/gitlab/diff/highlight_cache_spec.rb +++ b/spec/lib/gitlab/diff/highlight_cache_spec.rb @@ -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 diff --git a/spec/lib/gitlab/diff/line_spec.rb b/spec/lib/gitlab/diff/line_spec.rb index 949def599ae..b23ba3a0f00 100644 --- a/spec/lib/gitlab/diff/line_spec.rb +++ b/spec/lib/gitlab/diff/line_spec.rb @@ -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 } diff --git a/spec/lib/gitlab/diff/suggestion_diff_spec.rb b/spec/lib/gitlab/diff/suggestion_diff_spec.rb index 9546c581112..f9d56662753 100644 --- a/spec/lib/gitlab/diff/suggestion_diff_spec.rb +++ b/spec/lib/gitlab/diff/suggestion_diff_spec.rb @@ -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 diff --git a/spec/lib/gitlab/diff/suggestion_spec.rb b/spec/lib/gitlab/diff/suggestion_spec.rb index 40779faf917..9f654c44852 100644 --- a/spec/lib/gitlab/diff/suggestion_spec.rb +++ b/spec/lib/gitlab/diff/suggestion_spec.rb @@ -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 diff --git a/spec/lib/gitlab/diff/suggestions_parser_spec.rb b/spec/lib/gitlab/diff/suggestions_parser_spec.rb index a00c55d4fb2..ef845dbdc4c 100644 --- a/spec/lib/gitlab/diff/suggestions_parser_spec.rb +++ b/spec/lib/gitlab/diff/suggestions_parser_spec.rb @@ -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.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.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 + ) 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 diff --git a/spec/lib/gitlab/gitaly_client/repository_service_spec.rb b/spec/lib/gitlab/gitaly_client/repository_service_spec.rb index 283a9cb45dc..727bf494ee6 100644 --- a/spec/lib/gitlab/gitaly_client/repository_service_spec.rb +++ b/spec/lib/gitlab/gitaly_client/repository_service_spec.rb @@ -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' } diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index 6598cafeba0..04d0226ac22 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -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) } diff --git a/spec/services/projects/fork_service_spec.rb b/spec/services/projects/fork_service_spec.rb index 4d55f310974..ceb060445ad 100644 --- a/spec/services/projects/fork_service_spec.rb +++ b/spec/services/projects/fork_service_spec.rb @@ -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) { {} } diff --git a/spec/support/shared_examples/database_health_status_indicators/prometheus_alert_based_shared_examples.rb b/spec/support/shared_examples/database_health_status_indicators/prometheus_alert_based_shared_examples.rb index 109a349a652..ddc438cb652 100644 --- a/spec/support/shared_examples/database_health_status_indicators/prometheus_alert_based_shared_examples.rb +++ b/spec/support/shared_examples/database_health_status_indicators/prometheus_alert_based_shared_examples.rb @@ -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 diff --git a/spec/tasks/gitlab/background_migrations_rake_spec.rb b/spec/tasks/gitlab/background_migrations_rake_spec.rb index ba5618e2700..5c61f0eff38 100644 --- a/spec/tasks/gitlab/background_migrations_rake_spec.rb +++ b/spec/tasks/gitlab/background_migrations_rake_spec.rb @@ -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 diff --git a/spec/tasks/gitlab/db_rake_spec.rb b/spec/tasks/gitlab/db_rake_spec.rb index 7dd8adae04d..ba266168627 100644 --- a/spec/tasks/gitlab/db_rake_spec.rb +++ b/spec/tasks/gitlab/db_rake_spec.rb @@ -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 diff --git a/spec/workers/repository_fork_worker_spec.rb b/spec/workers/repository_fork_worker_spec.rb index 3a5528b6a04..bd452c21d9a 100644 --- a/spec/workers/repository_fork_worker_spec.rb +++ b/spec/workers/repository_fork_worker_spec.rb @@ -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) |