diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-03-15 21:14:36 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-03-15 21:14:36 +0000 |
commit | 885275c832d7c76b7290b38190a6cf31438d3898 (patch) | |
tree | 7d5de8a98dfa50003440c7e2a6c7e1504a926d90 | |
parent | f6b58d14904a1413a5442d13f361671e59ab3ded (diff) | |
download | gitlab-ce-885275c832d7c76b7290b38190a6cf31438d3898.tar.gz |
Add latest changes from gitlab-org/gitlab@master
87 files changed, 892 insertions, 551 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 79f99211bb1..c3087716b13 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -106,28 +106,28 @@ workflow: # For tags, create a pipeline. - if: '$CI_COMMIT_TAG' variables: - <<: *ruby2-variables - PIPELINE_NAME: 'Ruby 2 $CI_COMMIT_TAG tag pipeline' + <<: *ruby3-variables + PIPELINE_NAME: 'Ruby 3 $CI_COMMIT_TAG tag pipeline' # If `$GITLAB_INTERNAL` isn't set, don't create a pipeline. - if: '$GITLAB_INTERNAL == null' when: never # For stable, auto-deploy, and security branches, create a pipeline. - if: '$CI_COMMIT_BRANCH =~ /^[\d-]+-stable(-ee)?$/' variables: - <<: *ruby2-variables + <<: *ruby3-variables NOTIFY_PIPELINE_FAILURE_CHANNEL: "releases" - PIPELINE_NAME: 'Ruby 2 $CI_COMMIT_BRANCH branch pipeline' + PIPELINE_NAME: 'Ruby 3 $CI_COMMIT_BRANCH branch pipeline' CREATE_INCIDENT_FOR_PIPELINE_FAILURE: "true" BROKEN_BRANCH_INCIDENTS_PROJECT: "gitlab-org/release/tasks" BROKEN_BRANCH_INCIDENTS_PROJECT_TOKEN: "${BROKEN_STABLE_INCIDENTS_PROJECT_TOKEN}" - if: '$CI_COMMIT_BRANCH =~ /^\d+-\d+-auto-deploy-\d+$/' variables: - <<: *ruby2-variables - PIPELINE_NAME: 'Ruby 2 $CI_COMMIT_BRANCH branch pipeline' + <<: *ruby3-variables + PIPELINE_NAME: 'Ruby 3 $CI_COMMIT_BRANCH branch pipeline' - if: '$CI_COMMIT_BRANCH =~ /^security\//' variables: - <<: *ruby2-variables - PIPELINE_NAME: 'Ruby 2 $CI_COMMIT_BRANCH branch pipeline' + <<: *ruby3-variables + PIPELINE_NAME: 'Ruby 3 $CI_COMMIT_BRANCH branch pipeline' variables: PG_VERSION: "12" diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION index 2d5269488e5..97fadac1f9d 100644 --- a/GITALY_SERVER_VERSION +++ b/GITALY_SERVER_VERSION @@ -1 +1 @@ -71dbaa115c10ae08292a7df74d3f8297ab38f208 +705e00092a936f0233fe16339aba3a1c65db36b0 diff --git a/app/assets/javascripts/header_search/store/getters.js b/app/assets/javascripts/header_search/store/getters.js index 3da9d2cd961..3dec857930d 100644 --- a/app/assets/javascripts/header_search/store/getters.js +++ b/app/assets/javascripts/header_search/store/getters.js @@ -36,6 +36,10 @@ export const searchQuery = (state) => { }; export const scopedIssuesPath = (state) => { + if (state.searchContext?.project?.id && !state.searchContext?.project_metadata?.issues_path) { + return false; + } + return ( state.searchContext?.project_metadata?.issues_path || state.searchContext?.group_metadata?.issues_path || @@ -54,7 +58,7 @@ export const scopedMRPath = (state) => { export const defaultSearchOptions = (state, getters) => { const userName = gon.current_username; - return [ + const issues = [ { html_id: 'default-issues-assigned', title: MSG_ISSUES_ASSIGNED_TO_ME, @@ -65,6 +69,9 @@ export const defaultSearchOptions = (state, getters) => { title: MSG_ISSUES_IVE_CREATED, url: `${getters.scopedIssuesPath}/?author_username=${userName}`, }, + ]; + + const mergeRequests = [ { html_id: 'default-mrs-assigned', title: MSG_MR_ASSIGNED_TO_ME, @@ -81,6 +88,7 @@ export const defaultSearchOptions = (state, getters) => { url: `${getters.scopedMRPath}/?author_username=${userName}`, }, ]; + return [...(getters.scopedIssuesPath ? issues : []), ...mergeRequests]; }; export const projectUrl = (state) => { diff --git a/app/assets/javascripts/import_entities/import_groups/components/import_actions_cell.vue b/app/assets/javascripts/import_entities/import_groups/components/import_actions_cell.vue index ed7c9e7abe9..d91f314a86c 100644 --- a/app/assets/javascripts/import_entities/import_groups/components/import_actions_cell.vue +++ b/app/assets/javascripts/import_entities/import_groups/components/import_actions_cell.vue @@ -1,16 +1,9 @@ <script> -import { - GlButton, - GlDropdown, - GlDropdownItem, - GlIcon, - GlTooltipDirective as GlTooltip, -} from '@gitlab/ui'; +import { GlDropdown, GlDropdownItem, GlIcon, GlTooltipDirective as GlTooltip } from '@gitlab/ui'; export default { components: { GlIcon, - GlButton, GlDropdown, GlDropdownItem, }, @@ -18,10 +11,6 @@ export default { GlTooltip, }, props: { - isProjectsImportEnabled: { - type: Boolean, - required: true, - }, isFinished: { type: Boolean, required: true, @@ -46,7 +35,7 @@ export default { <template> <span class="gl-white-space-nowrap gl-inline-flex gl-align-items-center"> <gl-dropdown - v-if="isProjectsImportEnabled && (isAvailableForImport || isFinished)" + v-if="isAvailableForImport || isFinished" :text="isFinished ? __('Re-import with projects') : __('Import with projects')" :disabled="isInvalid" variant="confirm" @@ -59,16 +48,6 @@ export default { isFinished ? __('Re-import without projects') : __('Import without projects') }}</gl-dropdown-item> </gl-dropdown> - <gl-button - v-else-if="isAvailableForImport || isFinished" - :disabled="isInvalid" - variant="confirm" - category="secondary" - data-qa-selector="import_group_button" - @click="$emit('import-group')" - > - {{ isFinished ? __('Re-import') : __('Import') }} - </gl-button> <gl-icon v-if="isFinished" v-gl-tooltip diff --git a/app/assets/javascripts/import_entities/import_groups/components/import_table.vue b/app/assets/javascripts/import_entities/import_groups/components/import_table.vue index c9d1d1c56ee..2e6e7cddf8f 100644 --- a/app/assets/javascripts/import_entities/import_groups/components/import_table.vue +++ b/app/assets/javascripts/import_entities/import_groups/components/import_table.vue @@ -1,7 +1,6 @@ <script> import { GlAlert, - GlButton, GlDropdown, GlDropdownItem, GlEmptyState, @@ -50,7 +49,6 @@ const DEFAULT_TD_CLASSES = 'gl-vertical-align-top!'; export default { components: { GlAlert, - GlButton, GlDropdown, GlDropdownItem, GlEmptyState, @@ -165,10 +163,6 @@ export default { ], computed: { - isProjectsImportEnabled() { - return Boolean(this.glFeatures.bulkImportProjects); - }, - groups() { return this.bulkImportSourceGroups?.nodes ?? []; }, @@ -707,11 +701,11 @@ export default { </gl-sprintf> </span> <gl-dropdown - v-if="isProjectsImportEnabled" :text="s__('BulkImport|Import with projects')" :disabled="!hasSelectedGroups" variant="confirm" category="primary" + data-testid="import-selected-groups-dropdown" class="gl-ml-4" split @click="importSelectedGroups({ migrateProjects: true })" @@ -720,15 +714,6 @@ export default { {{ s__('BulkImport|Import without projects') }} </gl-dropdown-item> </gl-dropdown> - <gl-button - v-else - category="primary" - variant="confirm" - class="gl-ml-4" - :disabled="!hasSelectedGroups" - @click="importSelectedGroups" - >{{ s__('BulkImport|Import selected') }}</gl-button - > <span class="gl-ml-3"> <gl-icon name="information-o" :size="12" class="gl-text-blue-600" /> <gl-sprintf @@ -804,7 +789,6 @@ export default { </template> <template #cell(actions)="{ item: group, index }"> <import-actions-cell - :is-projects-import-enabled="isProjectsImportEnabled" :is-finished="group.flags.isFinished" :is-available-for-import="group.flags.isAvailableForImport" :is-invalid="group.flags.isInvalid" diff --git a/app/assets/javascripts/issues/related_merge_requests/components/related_merge_requests.vue b/app/assets/javascripts/issues/related_merge_requests/components/related_merge_requests.vue index af06884bbb4..92d1a2ffc22 100644 --- a/app/assets/javascripts/issues/related_merge_requests/components/related_merge_requests.vue +++ b/app/assets/javascripts/issues/related_merge_requests/components/related_merge_requests.vue @@ -68,7 +68,7 @@ export default { <div class="card card-slim gl-mt-5 gl-mb-0 gl-bg-gray-10"> <div class="card-header gl-px-5 gl-py-4 gl-bg-white"> <div - class="card-title gl-relative gl-display-flex gl-align-items-center gl-line-height-20 gl-font-weight-bold gl-m-0" + class="card-title gl-relative gl-display-flex gl-flex-wrap gl-align-items-center gl-line-height-20 gl-font-weight-bold gl-m-0" > <gl-link class="anchor gl-absolute gl-text-decoration-none" @@ -82,6 +82,12 @@ export default { <gl-icon name="merge-request" class="gl-ml-3 gl-mr-2 gl-text-gray-500" /> <span data-testid="count" class="gl-text-gray-500">{{ totalCount }}</span> </template> + <p + v-if="hasClosingMergeRequest && !isFetchingMergeRequests" + class="gl-font-sm gl-font-weight-normal gl-flex-basis-full gl-mb-0 gl-text-gray-500" + > + {{ closingMergeRequestsText }} + </p> </div> </div> <gl-loading-icon @@ -110,11 +116,5 @@ export default { </li> </ul> </div> - <div - v-if="hasClosingMergeRequest && !isFetchingMergeRequests" - class="issue-closed-by-widget second-block gl-mt-3" - > - {{ closingMergeRequestsText }} - </div> </div> </template> diff --git a/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/tags_list.vue b/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/tags_list.vue index f128e77da62..863d1c2629b 100644 --- a/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/tags_list.vue +++ b/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/tags_list.vue @@ -87,6 +87,9 @@ export default { tags() { return this.containerRepository?.tags?.nodes || []; }, + hideBulkDelete() { + return !(this.containerRepository?.canDelete || false); + }, tagsPageInfo() { return this.containerRepository?.tags?.pageInfo; }, @@ -98,9 +101,6 @@ export default { sort: this.sort, }; }, - showMultiDeleteButton() { - return this.tags.some((tag) => tag.canDelete) && !this.isMobile; - }, hasNoTags() { return this.tags.length === 0; }, @@ -186,6 +186,7 @@ export default { /> <template v-else> <registry-list + :hidden-delete="hideBulkDelete" :title="listTitle" :pagination="tagsPageInfo" :items="tags" diff --git a/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/tags_list_row.vue b/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/tags_list_row.vue index 38b601ac3ec..8e89128a382 100644 --- a/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/tags_list_row.vue +++ b/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/tags_list_row.vue @@ -109,9 +109,6 @@ export default { isInvalidTag() { return !this.tag.digest; }, - isDeleteDisabled() { - return this.disabled || !this.tag.canDelete; - }, }, }; </script> @@ -179,16 +176,16 @@ export default { </gl-sprintf> </span> </template> - <template #right-action> + <template v-if="tag.canDelete" #right-action> <gl-dropdown - :disabled="isDeleteDisabled" + :disabled="disabled" icon="ellipsis_v" :text="$options.i18n.MORE_ACTIONS_TEXT" :text-sr-only="true" category="tertiary" no-caret right - :class="{ 'gl-opacity-0 gl-pointer-events-none': isDeleteDisabled }" + :class="{ 'gl-opacity-0 gl-pointer-events-none': disabled }" data-testid="additional-actions" data-qa-selector="more_actions_menu" > diff --git a/app/assets/javascripts/packages_and_registries/container_registry/explorer/graphql/queries/get_container_repository_tags.query.graphql b/app/assets/javascripts/packages_and_registries/container_registry/explorer/graphql/queries/get_container_repository_tags.query.graphql index e57ac2a9efe..a0a80600603 100644 --- a/app/assets/javascripts/packages_and_registries/container_registry/explorer/graphql/queries/get_container_repository_tags.query.graphql +++ b/app/assets/javascripts/packages_and_registries/container_registry/explorer/graphql/queries/get_container_repository_tags.query.graphql @@ -12,6 +12,7 @@ query getContainerRepositoryTags( containerRepository(id: $id) { id tagsCount + canDelete tags(after: $after, before: $before, first: $first, last: $last, name: $name, sort: $sort) { nodes { digest diff --git a/app/assets/javascripts/packages_and_registries/package_registry/components/details/package_versions_list.vue b/app/assets/javascripts/packages_and_registries/package_registry/components/details/package_versions_list.vue index a06b2cadd6e..3d5ac528920 100644 --- a/app/assets/javascripts/packages_and_registries/package_registry/components/details/package_versions_list.vue +++ b/app/assets/javascripts/packages_and_registries/package_registry/components/details/package_versions_list.vue @@ -122,11 +122,8 @@ export default { @next-page="$emit('next-page')" > <template #default="{ first, item, isSelected, selectItem }"> - <!-- `first` prop is used to decide whether to show the top border - for the first element. We want to show the top border only when - user has permission to bulk delete versions. --> <version-row - :first="canDestroy && first" + :first="first" :package-entity="item" :selected="isSelected(item)" @delete="setItemToBeDeleted(item)" diff --git a/app/assets/javascripts/packages_and_registries/shared/components/registry_list.vue b/app/assets/javascripts/packages_and_registries/shared/components/registry_list.vue index 7485f8282ee..1c8f80972df 100644 --- a/app/assets/javascripts/packages_and_registries/shared/components/registry_list.vue +++ b/app/assets/javascripts/packages_and_registries/shared/components/registry_list.vue @@ -125,7 +125,7 @@ export default { :select-item="selectItem" :is-selected="isSelected" :item="item" - :first="index === 0" + :first="!hiddenDelete && index === 0" ></slot> </div> diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb index ca5436ff019..d62dc038388 100644 --- a/app/helpers/search_helper.rb +++ b/app/helpers/search_helper.rb @@ -204,7 +204,9 @@ module SearchHelper if search_has_project? hash[:project] = { id: @project.id, name: @project.name } - hash[:project_metadata] = { issues_path: project_issues_path(@project), mr_path: project_merge_requests_path(@project) } + hash[:project_metadata] = { mr_path: project_merge_requests_path(@project) } + hash[:project_metadata][:issues_path] = project_issues_path(@project) if @project.feature_available?(:issues, current_user) + hash[:code_search] = search_scope.nil? hash[:ref] = @ref if @ref && can?(current_user, :read_code, @project) end diff --git a/app/models/concerns/has_user_type.rb b/app/models/concerns/has_user_type.rb index 752be378ab0..0b1c6780db8 100644 --- a/app/models/concerns/has_user_type.rb +++ b/app/models/concerns/has_user_type.rb @@ -14,6 +14,7 @@ module HasUserType migration_bot: 7, security_bot: 8, automation_bot: 9, + security_policy_bot: 10, # Currently not in use. See https://gitlab.com/gitlab-org/gitlab/-/issues/384174 admin_bot: 11, suggested_reviewers_bot: 12, service_account: 13 @@ -27,6 +28,7 @@ module HasUserType migration_bot security_bot automation_bot + security_policy_bot admin_bot suggested_reviewers_bot service_account diff --git a/app/views/admin/application_settings/_realtime.html.haml b/app/views/admin/application_settings/_realtime.html.haml index 6a7ec05d206..2b8b023baea 100644 --- a/app/views/admin/application_settings/_realtime.html.haml +++ b/app/views/admin/application_settings/_realtime.html.haml @@ -1,4 +1,4 @@ -= form_for @application_setting, url: preferences_admin_application_settings_path(anchor: 'js-realtime-settings'), html: { class: 'fieldset-form' } do |f| += gitlab_ui_form_for @application_setting, url: preferences_admin_application_settings_path(anchor: 'js-realtime-settings'), html: { class: 'fieldset-form' } do |f| = form_errors(@application_setting) %fieldset @@ -8,4 +8,4 @@ .form-text.text-muted = _('Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1.') - = f.submit _('Save changes'), class: "gl-button btn btn-confirm" + = f.submit _('Save changes'), pajamas_button: true diff --git a/app/views/devise/confirmations/new.html.haml b/app/views/devise/confirmations/new.html.haml index d3bd1d58d21..4b586b2f580 100644 --- a/app/views/devise/confirmations/new.html.haml +++ b/app/views/devise/confirmations/new.html.haml @@ -1,7 +1,7 @@ = render 'devise/shared/tab_single', tab_title: 'Resend confirmation instructions' .login-box.gl-p-5 .login-body - = form_for(resource, as: resource_name, url: confirmation_path(resource_name), html: { method: :post, class: 'gl-show-field-errors' }) do |f| + = gitlab_ui_form_for(resource, as: resource_name, url: confirmation_path(resource_name), html: { method: :post, class: 'gl-show-field-errors' }) do |f| .devise-errors = render "devise/shared/error_messages", resource: resource .form-group @@ -13,7 +13,8 @@ = recaptcha_tags nonce: content_security_policy_nonce .gl-mt-5 - = f.submit _("Resend"), class: 'gl-button btn btn-confirm' + = render Pajamas::ButtonComponent.new(block: true, type: :submit, variant: :confirm) do + = _("Resend") .clearfix.prepend-top-20 = render 'devise/shared/sign_in_link' diff --git a/app/views/projects/feature_flags/index.html.haml b/app/views/projects/feature_flags/index.html.haml index 53fe30422ca..a6eaeacc61f 100644 --- a/app/views/projects/feature_flags/index.html.haml +++ b/app/views/projects/feature_flags/index.html.haml @@ -6,7 +6,7 @@ "error-state-svg-path" => image_path('illustrations/feature_flag.svg'), "feature-flags-help-page-path" => help_page_path("operations/feature_flags"), "feature-flags-client-libraries-help-page-path" => help_page_path("operations/feature_flags", anchor: "choose-a-client-library"), - "feature-flags-client-example-help-page-path" => help_page_path("operations/feature_flags", anchor: "golang-application-example"), + "feature-flags-client-example-help-page-path" => help_page_path("operations/feature_flags", anchor: "go-application-example"), "feature-flags-limit-exceeded" => @project.actual_limits.exceeded?(:project_feature_flags, @project.operations_feature_flags.count), "feature-flags-limit" => @project.actual_limits.project_feature_flags, "unleash-api-url" => (unleash_api_url(@project) if can?(current_user, :admin_feature_flag, @project)), diff --git a/app/views/projects/pages/_pages_settings.html.haml b/app/views/projects/pages/_pages_settings.html.haml index e60cdf754da..11e105d349d 100644 --- a/app/views/projects/pages/_pages_settings.html.haml +++ b/app/views/projects/pages/_pages_settings.html.haml @@ -27,4 +27,4 @@ = s_("GitLabPages|When enabled, a unique domain is generated to access pages.").html_safe .gl-mt-3 - = f.submit s_('GitLabPages|Save changes'), class: 'btn btn-confirm gl-button' + = f.submit s_('GitLabPages|Save changes'), pajamas_button: true diff --git a/app/views/registrations/welcome/show.html.haml b/app/views/registrations/welcome/show.html.haml index f4e9a597fe2..2796f0c0a7e 100644 --- a/app/views/registrations/welcome/show.html.haml +++ b/app/views/registrations/welcome/show.html.haml @@ -38,4 +38,5 @@ - if partial_exists? "registrations/welcome/button" = render "registrations/welcome/button" - else - = f.submit _('Get started!'), class: 'btn-confirm gl-button btn btn-block gl-mb-0 gl-p-3', data: { qa_selector: 'get_started_button' } + = render Pajamas::ButtonComponent.new(block: true, type: :submit, variant: :confirm, button_options: { class: 'gl-mb-0', data: { qa_selector: 'get_started_button' }}) do + = _('Get started!') diff --git a/config/feature_flags/development/cache_client_with_metrics.yml b/config/feature_flags/development/cache_client_with_metrics.yml deleted file mode 100644 index 433b9729df4..00000000000 --- a/config/feature_flags/development/cache_client_with_metrics.yml +++ /dev/null @@ -1,8 +0,0 @@ ---- -name: cache_client_with_metrics -introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/111210 -rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/392622 -milestone: '15.10' -type: development -group: group::source code -default_enabled: false diff --git a/db/post_migrate/20230118144623_schedule_migration_for_remediation.rb b/db/post_migrate/20230118144623_schedule_migration_for_remediation.rb index af9b7d65a55..ed95ecfaad3 100644 --- a/db/post_migrate/20230118144623_schedule_migration_for_remediation.rb +++ b/db/post_migrate/20230118144623_schedule_migration_for_remediation.rb @@ -9,17 +9,10 @@ class ScheduleMigrationForRemediation < Gitlab::Database::Migration[2.1] BATCH_SIZE = 5000 def up - queue_batched_background_migration( - MIGRATION, - :vulnerability_occurrences, - :id, - job_interval: DELAY_INTERVAL, - batch_size: BATCH_SIZE, - sub_batch_size: SUB_BATCH_SIZE - ) + # no-op as described in https://docs.gitlab.com/ee/development/database/batched_background_migrations.html end def down - delete_batched_background_migration(MIGRATION, :vulnerability_occurrences, :id, []) + # no-op as described in https://docs.gitlab.com/ee/development/database/batched_background_migrations.html end end diff --git a/db/post_migrate/20230214181633_finalize_ci_build_needs_big_int_conversion.rb b/db/post_migrate/20230214181633_finalize_ci_build_needs_big_int_conversion.rb index 1ac7b447457..63b6148df6b 100644 --- a/db/post_migrate/20230214181633_finalize_ci_build_needs_big_int_conversion.rb +++ b/db/post_migrate/20230214181633_finalize_ci_build_needs_big_int_conversion.rb @@ -8,6 +8,8 @@ class FinalizeCiBuildNeedsBigIntConversion < Gitlab::Database::Migration[2.1] TABLE_NAME = 'ci_build_needs' def up + return unless should_run? + ensure_batched_background_migration_is_finished( job_class_name: 'CopyColumnUsingBackgroundMigrationJob', table_name: TABLE_NAME, @@ -17,4 +19,10 @@ class FinalizeCiBuildNeedsBigIntConversion < Gitlab::Database::Migration[2.1] end def down; end + + private + + def should_run? + !Gitlab.jh? && (Gitlab.com? || Gitlab.dev_or_test_env?) + end end diff --git a/db/post_migrate/20230220102212_swap_columns_ci_build_needs_big_int_conversion.rb b/db/post_migrate/20230220102212_swap_columns_ci_build_needs_big_int_conversion.rb new file mode 100644 index 00000000000..de98847fad4 --- /dev/null +++ b/db/post_migrate/20230220102212_swap_columns_ci_build_needs_big_int_conversion.rb @@ -0,0 +1,57 @@ +# frozen_string_literal: true + +class SwapColumnsCiBuildNeedsBigIntConversion < Gitlab::Database::Migration[2.1] + disable_ddl_transaction! + + TABLE_NAME = 'ci_build_needs' + + def up + return unless should_run? + + swap + end + + def down + return unless should_run? + + swap + end + + private + + def should_run? + !Gitlab.jh? && (Gitlab.com? || Gitlab.dev_or_test_env?) + end + + def swap + add_concurrent_index TABLE_NAME, :id_convert_to_bigint, unique: true, name: + 'index_ci_build_needs_on_id_convert_to_bigint' + + with_lock_retries(raise_on_exhaustion: true) do + execute "LOCK TABLE #{TABLE_NAME} IN ACCESS EXCLUSIVE MODE" + + id_name = quote_column_name(:id) + temp_name = quote_column_name('id_tmp') + id_convert_to_bigint_name = quote_column_name(:id_convert_to_bigint) + + execute "ALTER TABLE #{TABLE_NAME} RENAME COLUMN #{id_name} TO #{temp_name}" + execute "ALTER TABLE #{TABLE_NAME} RENAME COLUMN #{id_convert_to_bigint_name} TO #{id_name}" + execute "ALTER TABLE #{TABLE_NAME} RENAME COLUMN #{temp_name} TO #{id_convert_to_bigint_name}" + + function_name = Gitlab::Database::UnidirectionalCopyTrigger.on_table( + TABLE_NAME, connection: Ci::ApplicationRecord.connection + ).name( + :id, :id_convert_to_bigint + ) + execute "ALTER FUNCTION #{quote_table_name(function_name)} RESET ALL" + + execute "ALTER SEQUENCE ci_build_needs_id_seq OWNED BY #{TABLE_NAME}.id" + change_column_default TABLE_NAME, :id, -> { "nextval('ci_build_needs_id_seq'::regclass)" } + change_column_default TABLE_NAME, :id_convert_to_bigint, 0 + + execute "ALTER TABLE #{TABLE_NAME} DROP CONSTRAINT ci_build_needs_pkey CASCADE" + rename_index TABLE_NAME, 'index_ci_build_needs_on_id_convert_to_bigint', 'ci_build_needs_pkey' + execute "ALTER TABLE #{TABLE_NAME} ADD CONSTRAINT ci_build_needs_pkey PRIMARY KEY USING INDEX ci_build_needs_pkey" + end + end +end diff --git a/db/post_migrate/20230309071242_delete_security_policy_bot_users.rb b/db/post_migrate/20230309071242_delete_security_policy_bot_users.rb new file mode 100644 index 00000000000..0a9ace2574c --- /dev/null +++ b/db/post_migrate/20230309071242_delete_security_policy_bot_users.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +class DeleteSecurityPolicyBotUsers < Gitlab::Database::Migration[2.1] + restrict_gitlab_migration gitlab_schema: :gitlab_main + + class User < MigrationRecord + self.table_name = 'users' + + enum user_type: { security_policy_bot: 10 } + end + + def up + User.where(user_type: :security_policy_bot).delete_all + end + + def down + # no-op + + # Deleted records can't be restored + end +end diff --git a/db/post_migrate/20230313150531_reschedule_migration_for_remediation.rb b/db/post_migrate/20230313150531_reschedule_migration_for_remediation.rb new file mode 100644 index 00000000000..ebb6e53341f --- /dev/null +++ b/db/post_migrate/20230313150531_reschedule_migration_for_remediation.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +# rubocop: disable BackgroundMigration/MissingDictionaryFile + +class RescheduleMigrationForRemediation < Gitlab::Database::Migration[2.1] + MIGRATION = 'MigrateRemediationsForVulnerabilityFindings' + DELAY_INTERVAL = 2.minutes + SUB_BATCH_SIZE = 500 + BATCH_SIZE = 5000 + + disable_ddl_transaction! + + restrict_gitlab_migration gitlab_schema: :gitlab_main + + def up + delete_batched_background_migration(MIGRATION, :vulnerability_occurrences, :id, []) + + queue_batched_background_migration( + MIGRATION, + :vulnerability_occurrences, + :id, + job_interval: DELAY_INTERVAL, + batch_size: BATCH_SIZE, + sub_batch_size: SUB_BATCH_SIZE + ) + end + + def down + delete_batched_background_migration(MIGRATION, :vulnerability_occurrences, :id, []) + end +end +# rubocop: enable BackgroundMigration/MissingDictionaryFile diff --git a/db/schema_migrations/20230220102212 b/db/schema_migrations/20230220102212 new file mode 100644 index 00000000000..a4432c7b517 --- /dev/null +++ b/db/schema_migrations/20230220102212 @@ -0,0 +1 @@ +7df50689f7e9311ee8e5bd2513f4361be0fceef3962344d2d16bf511132c7a33
\ No newline at end of file diff --git a/db/schema_migrations/20230309071242 b/db/schema_migrations/20230309071242 new file mode 100644 index 00000000000..dd29a8006b1 --- /dev/null +++ b/db/schema_migrations/20230309071242 @@ -0,0 +1 @@ +094eb5044e841050288c7362cc58c1b63ce4a349fe49a4c5ebee6b83a05feb56
\ No newline at end of file diff --git a/db/schema_migrations/20230313150531 b/db/schema_migrations/20230313150531 new file mode 100644 index 00000000000..94625561f6b --- /dev/null +++ b/db/schema_migrations/20230313150531 @@ -0,0 +1 @@ +e2f19bbc322127e439fffc4c1e2718288538aa6cb2d50a5248f12470b1c9491e
\ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index 49f713c691d..64b05803829 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -12896,13 +12896,13 @@ CREATE SEQUENCE chat_teams_id_seq ALTER SEQUENCE chat_teams_id_seq OWNED BY chat_teams.id; CREATE TABLE ci_build_needs ( - id integer NOT NULL, + id_convert_to_bigint integer DEFAULT 0 NOT NULL, name text NOT NULL, artifacts boolean DEFAULT true NOT NULL, optional boolean DEFAULT false NOT NULL, build_id bigint NOT NULL, partition_id bigint DEFAULT 100 NOT NULL, - id_convert_to_bigint bigint DEFAULT 0 NOT NULL + id bigint NOT NULL ); CREATE SEQUENCE ci_build_needs_id_seq diff --git a/doc/.vale/gitlab/CodeblockFences.yml b/doc/.vale/gitlab/CodeblockFences.yml index 9d5efe7f60a..27159f7e72e 100644 --- a/doc/.vale/gitlab/CodeblockFences.yml +++ b/doc/.vale/gitlab/CodeblockFences.yml @@ -5,9 +5,9 @@ # # For a list of all options, see https://vale.sh/docs/topics/styles/ extends: existence -message: "Instead of '%s' for the code block, use yaml, ruby, plaintext, markdown, javascript, shell, golang, python, dockerfile, or typescript." +message: "Instead of '%s' for the code block, use yaml, ruby, plaintext, markdown, javascript, shell, go, python, dockerfile, or typescript." link: https://docs.gitlab.com/ee/development/documentation/styleguide/index.html#code-blocks level: error scope: raw raw: - - '\`\`\`(yml|rb|text|md|bash|sh\n|js\n|go\n|py\n|docker\n|ts)' + - '\`\`\`(yml|rb|text|md|bash|sh\n|js\n|golang\n|py\n|docker\n|ts)' diff --git a/doc/.vale/gitlab/Substitutions.yml b/doc/.vale/gitlab/Substitutions.yml index 675abc6ef6d..225e4e74880 100644 --- a/doc/.vale/gitlab/Substitutions.yml +++ b/doc/.vale/gitlab/Substitutions.yml @@ -23,6 +23,7 @@ swap: params: parameters pg: PostgreSQL 'postgres$': PostgreSQL + golang: Go raketask: Rake task raketasks: Rake tasks rspec: RSpec diff --git a/doc/administration/gitaly/troubleshooting.md b/doc/administration/gitaly/troubleshooting.md index 52d307790be..596348a3177 100644 --- a/doc/administration/gitaly/troubleshooting.md +++ b/doc/administration/gitaly/troubleshooting.md @@ -720,7 +720,7 @@ This error occurs when `praefect['database_port']` or `praefect['database_direct ## Profiling Gitaly -Gitaly exposes several of the Golang built-in performance profiling tools on the Prometheus listen port. For example, if Prometheus is listening +Gitaly exposes several of the Go built-in performance profiling tools on the Prometheus listen port. For example, if Prometheus is listening on port `9236` of the GitLab server: - Get a list of running `goroutines` and their backtraces: diff --git a/doc/administration/pages/index.md b/doc/administration/pages/index.md index 609862dba83..efeb19a8d5e 100644 --- a/doc/administration/pages/index.md +++ b/doc/administration/pages/index.md @@ -863,7 +863,7 @@ Incorrect configuration of these values may result in intermittent or persistent errors, or the Pages Daemon serving old content. NOTE: -Expiry, interval and timeout flags use [Golang's duration formatting](https://pkg.go.dev/time#ParseDuration). +Expiry, interval and timeout flags use [Go duration formatting](https://pkg.go.dev/time#ParseDuration). A duration string is a possibly signed sequence of decimal numbers, each with optional fraction and a unit suffix, such as `300ms`, `1.5h` or `2h45m`. Valid time units are `ns`, `us` (or `µs`), `ms`, `s`, `m`, `h`. diff --git a/doc/api/license.md b/doc/api/license.md index ca9d9cf386d..39da6af30d4 100644 --- a/doc/api/license.md +++ b/doc/api/license.md @@ -233,3 +233,35 @@ Returns: - `204 No Content` if the license is successfully deleted. - `403 Forbidden` if the current user in not permitted to delete the license. - `404 Not Found` if the license to delete could not be found. + +## Trigger recalculation of billable users + +```plaintext +PUT /license/:id/refresh_billable_users +``` + +| Attribute | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `id` | integer | yes | ID of the GitLab license. | + +```shell +curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/license/:id/refresh_billable_users" +``` + +Example response: + +```json +{ + "success": true +} +``` + +Returns: + +- `202 Accepted` if the request to refresh billable users is successfully initiated. +- `403 Forbidden` if the current user in not permitted to refresh billable users for the license. +- `404 Not Found` if the license could not be found. + +| Attribute | Type | Description | +|:-----------------------------|:--------------|:------------------------------------------| +| `success` | boolean | Whether the request succeeded or not. | diff --git a/doc/architecture/blueprints/gitlab_observability_backend/metrics/index.md b/doc/architecture/blueprints/gitlab_observability_backend/metrics/index.md index c5bd2440b0c..82d1596bc90 100644 --- a/doc/architecture/blueprints/gitlab_observability_backend/metrics/index.md +++ b/doc/architecture/blueprints/gitlab_observability_backend/metrics/index.md @@ -93,9 +93,9 @@ Additionally, since we intend to ingest data via Prometheus `remote_write` API, We also need to make sure to avoid writing a lot of small writes into Clickhouse, therefore it’d be prudent to batch data before writing it into Clickhouse. -We must also make sure ingestion remains decoupled with `Storage` so as to reduce undue dependence on a given storage implementation. While we do intend to use Clickhouse as our backing storage for any foreseeable future, this ensures we do not tie ourselves in into Clickhouse too much should future business requirements warrant the usage of a different backend/technology. A good way to implement this in Golang would be our implementations adhering to a standard interface, the following for example: +We must also make sure ingestion remains decoupled with `Storage` so as to reduce undue dependence on a given storage implementation. While we do intend to use Clickhouse as our backing storage for any foreseeable future, this ensures we do not tie ourselves in into Clickhouse too much should future business requirements warrant the usage of a different backend/technology. A good way to implement this in Go would be our implementations adhering to a standard interface, the following for example: -```golang +```go type Storage interface { Read( ctx context.Context, diff --git a/doc/architecture/blueprints/object_storage/index.md b/doc/architecture/blueprints/object_storage/index.md index 4a8eeaf86a9..6718705a7c8 100644 --- a/doc/architecture/blueprints/object_storage/index.md +++ b/doc/architecture/blueprints/object_storage/index.md @@ -53,7 +53,7 @@ This has led to increased complexity across the board, from development [we no longer recommend](../../../administration/nfs.md) to our users and is no longer in use on GitLab.com. - Understanding all the moving parts and the flow is extremely - complicated: we have CarrierWave, Fog, Golang S3/Azure SDKs, all + complicated: we have CarrierWave, Fog, Go S3/Azure SDKs, all being used, and that complicates testing as well. - Fog and CarrierWave are not maintained to the level of the native SDKs (for example, AWS S3 SDK), so we have to maintain or monkey diff --git a/doc/architecture/blueprints/rate_limiting/index.md b/doc/architecture/blueprints/rate_limiting/index.md index b466a54e922..92364040962 100644 --- a/doc/architecture/blueprints/rate_limiting/index.md +++ b/doc/architecture/blueprints/rate_limiting/index.md @@ -375,7 +375,7 @@ hierarchy. Choosing a proper solution will require a thoughtful research. - Implementing a separate Go library which uses the same backend (for example, Redis) for rate limiting. 1. **SDK for Satellite Services (Owning Team)** - - Build Golang SDK. + - Build Go SDK. - Create examples showcasing usage of the new rate limits SDK. 1. **Team fan out for Satellite Services (Stage Groups)** diff --git a/doc/ci/examples/index.md b/doc/ci/examples/index.md index 6738c55b6fa..b05c872d624 100644 --- a/doc/ci/examples/index.md +++ b/doc/ci/examples/index.md @@ -76,7 +76,7 @@ choose one of these templates: - [dotNET Core (`dotNET-Core.gitlab-ci.yml`)](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/dotNET-Core.gitlab-ci.yml) - [Elixir (`Elixir.gitlab-ci.yml`)](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Elixir.gitlab-ci.yml) - [Flutter (`Flutter.gitlab-ci.yml`)](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Flutter.gitlab-ci.yml) -- [Golang (`Go.gitlab-ci.yml`)](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Go.gitlab-ci.yml) +- [Go (`Go.gitlab-ci.yml`)](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Go.gitlab-ci.yml) - [Gradle (`Gradle.gitlab-ci.yml`)](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Gradle.gitlab-ci.yml) - [Grails (`Grails.gitlab-ci.yml`)](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Grails.gitlab-ci.yml) - [iOS with fastlane (`iOS-Fastlane.gitlab-ci.yml`)](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/iOS-Fastlane.gitlab-ci.yml) diff --git a/doc/ci/testing/test_coverage_visualization.md b/doc/ci/testing/test_coverage_visualization.md index a54b1f2a610..1b29304d1af 100644 --- a/doc/ci/testing/test_coverage_visualization.md +++ b/doc/ci/testing/test_coverage_visualization.md @@ -33,7 +33,7 @@ This format was originally developed for Java, but most coverage analysis framew for other languages have plugins to add support for it, like: - [simplecov-cobertura](https://rubygems.org/gems/simplecov-cobertura) (Ruby) -- [gocover-cobertura](https://github.com/boumenot/gocover-cobertura) (Golang) +- [gocover-cobertura](https://github.com/boumenot/gocover-cobertura) (Go) Other coverage analysis frameworks support the format out of the box, for example: diff --git a/doc/development/backend/create_source_code_be/gitaly_touch_points.md b/doc/development/backend/create_source_code_be/gitaly_touch_points.md index 6ee2c7f0e51..c689af2f150 100644 --- a/doc/development/backend/create_source_code_be/gitaly_touch_points.md +++ b/doc/development/backend/create_source_code_be/gitaly_touch_points.md @@ -8,7 +8,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w ## RPCs -Gitaly is a wrapper around the `git` binary, running in a [Gitaly Cluster](../../../administration/gitaly/index.md). It provides managed access to the file system housing the `git` repositories, via Golang Remote Procedure Calls (RPCs). Other functions are access optimization, caching, and a form of pagination against the file system. +Gitaly is a wrapper around the `git` binary, running in a [Gitaly Cluster](../../../administration/gitaly/index.md). It provides managed access to the file system housing the `git` repositories, using Go Remote Procedure Calls (RPCs). Other functions are access optimization, caching, and a form of pagination against the file system. The comprehensive [Beginner's guide to Gitaly contributions](https://gitlab.com/gitlab-org/gitaly/-/blob/master/doc/beginners_guide.md) is focused on making updates to Gitaly, and offers many insights into how to understand the Gitaly code. diff --git a/doc/development/backend/create_source_code_be/index.md b/doc/development/backend/create_source_code_be/index.md index ba0ed2a2867..d894a14b006 100644 --- a/doc/development/backend/create_source_code_be/index.md +++ b/doc/development/backend/create_source_code_be/index.md @@ -39,7 +39,7 @@ To learn about the reasoning behind our creation of `gitlab-sshd`, read the blog ### Gitaly touch points -Gitaly is a Golang RPC service which handles all the `git` calls made by GitLab. +Gitaly is a Go RPC service which handles all the `git` calls made by GitLab. GitLab is not exposed directly, and all traffic comes through Create: Source Code. For more information, read [Gitaly touch points](gitaly_touch_points.md). diff --git a/doc/development/documentation/styleguide/word_list.md b/doc/development/documentation/styleguide/word_list.md index d6096b32795..1ea95367d01 100644 --- a/doc/development/documentation/styleguide/word_list.md +++ b/doc/development/documentation/styleguide/word_list.md @@ -741,7 +741,7 @@ Do not use **limitations**. Use **known issues** instead. ## log in, log on -Do not use **log in** or **log on**. Use [sign in](#sign-in) instead. If the user interface has **Log in**, you can use it. +Do not use **log in** or **log on**. Use [sign in](#sign-in-sign-in) instead. If the user interface has **Log in**, you can use it. ## logged-in user, logged in user @@ -1154,14 +1154,17 @@ Use **setup** as a noun, and **set up** as a verb. For example: - Your remote office setup is amazing. - To set up your remote office correctly, consider the ergonomics of your work area. -## sign in +## sign in, sign-in -Use **sign in** or **sign in to**. +Use **sign in** or **sign in to** as a verb to describe the action of signing in. Do not use **sign on** or **sign into**, or **log on**, **log in**, or **log into**. If the user interface has different words, use those. +You can use **sign-in** as a noun or adjective. For example, **sign-in page** or +**sign-in restrictions**. + You can use **single sign-on**. ## sign up diff --git a/doc/development/fips_compliance.md b/doc/development/fips_compliance.md index 45668b6be0c..f0634107ba5 100644 --- a/doc/development/fips_compliance.md +++ b/doc/development/fips_compliance.md @@ -446,7 +446,7 @@ irb(main):001:0> require 'openssl'; OpenSSL.fips_mode ### Go -Google maintains a [`dev.boringcrypto` branch](https://github.com/golang/go/tree/dev.boringcrypto) in the Golang compiler +Google maintains a [`dev.boringcrypto` branch](https://github.com/golang/go/tree/dev.boringcrypto) in the Go compiler that makes it possible to statically link BoringSSL, a FIPS-validated module forked from OpenSSL. However, BoringSSL is not intended for public use. diff --git a/doc/development/gitaly.md b/doc/development/gitaly.md index e7d04a6677e..addab512f89 100644 --- a/doc/development/gitaly.md +++ b/doc/development/gitaly.md @@ -257,13 +257,13 @@ Here are the steps to gate a new feature in Gitaly behind a feature flag. 1. Create a package scoped flag name: - ```golang + ```go var findAllTagsFeatureFlag = "go-find-all-tags" ``` 1. Create a switch in the code using the `featureflag` package: - ```golang + ```go if featureflag.IsEnabled(ctx, findAllTagsFeatureFlag) { // go implementation } else { @@ -273,7 +273,7 @@ Here are the steps to gate a new feature in Gitaly behind a feature flag. 1. Create Prometheus metrics: - ```golang + ```go var findAllTagsRequests = prometheus.NewCounterVec( prometheus.CounterOpts{ Name: "gitaly_find_all_tags_requests_total", @@ -297,7 +297,7 @@ Here are the steps to gate a new feature in Gitaly behind a feature flag. 1. Set headers in tests: - ```golang + ```go import ( "google.golang.org/grpc/metadata" diff --git a/doc/development/gitlab_shell/index.md b/doc/development/gitlab_shell/index.md index 9dc8d8e01c5..3a1af0fc9e9 100644 --- a/doc/development/gitlab_shell/index.md +++ b/doc/development/gitlab_shell/index.md @@ -21,8 +21,8 @@ Ruby to build and test, but not to run. GitLab Shell runs on `port 22` on an Omnibus installation. To use a regular SSH service, configure it on an alternative port. -Download and install the current version of Go from [golang.org](https://go.dev/dl/). -We follow the [Golang Release Policy](https://golang.org/doc/devel/release.html#policy) +Download and install the [current version of Go](https://go.dev/dl/). +We follow the [Go Release Policy](https://go.dev/doc/devel/release#policy) and support: - The current stable version. diff --git a/doc/development/go_guide/go_upgrade.md b/doc/development/go_guide/go_upgrade.md index b3ec0a15c37..f71fe7b8dac 100644 --- a/doc/development/go_guide/go_upgrade.md +++ b/doc/development/go_guide/go_upgrade.md @@ -26,7 +26,7 @@ by Distribution: ## Supporting multiple Go versions -Individual Golang projects need to support multiple Go versions because: +Individual Go projects need to support multiple Go versions because: - When a new version of Go is released, we should start integrating it into the CI pipelines to verify compatibility with the new compiler. - We must support the [official Omnibus GitLab Go version](#updating-go-version), which may be behind the latest minor release. diff --git a/doc/development/go_guide/index.md b/doc/development/go_guide/index.md index b1e37ddbde8..6092a05afff 100644 --- a/doc/development/go_guide/index.md +++ b/doc/development/go_guide/index.md @@ -216,7 +216,7 @@ When comparing expected and actual values in tests, use and others to improve readability when comparing structs, errors, large portions of text, or JSON documents: -```golang +```go type TestData struct { // ... } @@ -291,7 +291,7 @@ easier to debug. For example: -```golang +```go // Wrap the error return nil, fmt.Errorf("get cache %s: %w", f.Name, err) @@ -462,7 +462,7 @@ allocations. **Don't:** -```golang +```go var s2 []string for _, val := range s1 { s2 = append(s2, val) @@ -471,7 +471,7 @@ for _, val := range s1 { **Do:** -```golang +```go s2 := make([]string, 0, len(s1)) for _, val := range s1 { s2 = append(s2, val) @@ -494,7 +494,7 @@ If the scanner report is small, less than 35 lines, then feel free to [inline th The [go-cmp](https://github.com/google/go-cmp) package should be used when comparing large structs in tests. It makes it possible to output a specific diff where the two structs differ, rather than seeing the whole of both structs printed out in the test logs. Here is a small example: -```golang +```go package main import ( diff --git a/doc/development/secure_coding_guidelines.md b/doc/development/secure_coding_guidelines.md index d41f1d76994..4f644dd018e 100644 --- a/doc/development/secure_coding_guidelines.md +++ b/doc/development/secure_coding_guidelines.md @@ -542,11 +542,11 @@ print(p.join('log', '/etc/passwd', '')) # renders the path to "/etc/passwd", which is not what we expect! ``` -#### Golang +#### Go -Golang has similar behavior with [`path.Clean`](https://pkg.go.dev/path#example-Clean). Remember that with many file systems, using `../../../../` traverses up to the root directory. Any remaining `../` are ignored. This example may give an attacker access to `/etc/passwd`: +Go has similar behavior with [`path.Clean`](https://pkg.go.dev/path#example-Clean). Remember that with many file systems, using `../../../../` traverses up to the root directory. Any remaining `../` are ignored. This example may give an attacker access to `/etc/passwd`: -```golang +```go path.Clean("/../../etc/passwd") // renders the path to "etc/passwd"; the file path is relative to whatever the current directory is path.Clean("../../etc/passwd") @@ -601,7 +601,7 @@ Go has built-in protections that usually prevent an attacker from successfully i Consider the following example: -```golang +```go package main import ( @@ -620,7 +620,7 @@ This echoes `"1; cat /etc/passwd"`. **Do not** use `sh`, as it bypasses internal protections: -```golang +```go out, _ = exec.Command("sh", "-c", "echo 1 | cat /etc/passwd").Output() ``` @@ -646,15 +646,15 @@ And the following cipher suites (according to the [RFC 8446](https://datatracker - `TLS_AES_128_GCM_SHA256` - `TLS_AES_256_GCM_SHA384` -*Note*: **Golang** does [not support](https://github.com/golang/go/blob/go1.17/src/crypto/tls/cipher_suites.go#L676) all cipher suites with TLS 1.3. +*Note*: **Go** does [not support](https://github.com/golang/go/blob/go1.17/src/crypto/tls/cipher_suites.go#L676) all cipher suites with TLS 1.3. ##### Implementation examples ##### TLS 1.3 -For TLS 1.3, **Golang** only supports [3 cipher suites](https://github.com/golang/go/blob/go1.17/src/crypto/tls/cipher_suites.go#L676), as such we only need to set the TLS version: +For TLS 1.3, **Go** only supports [3 cipher suites](https://github.com/golang/go/blob/go1.17/src/crypto/tls/cipher_suites.go#L676), as such we only need to set the TLS version: -```golang +```go cfg := &tls.Config{ MinVersion: tls.VersionTLS13, } @@ -678,9 +678,9 @@ response = GitLab::HTTP.perform_request(Net::HTTP::Get, 'https://gitlab.com', ss ##### TLS 1.2 -**Golang** does support multiple cipher suites that we do not want to use with TLS 1.2. We need to explicitly list authorized ciphers: +**Go** does support multiple cipher suites that we do not want to use with TLS 1.2. We need to explicitly list authorized ciphers: -```golang +```go func secureCipherSuites() []uint16 { return []uint16{ tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, @@ -692,7 +692,7 @@ func secureCipherSuites() []uint16 { And then use `secureCipherSuites()` in `tls.Config`: -```golang +```go tls.Config{ (...), CipherSuites: secureCipherSuites(), @@ -920,7 +920,7 @@ end #### Go -```golang +```go // unzip INSECURELY extracts source zip file to destination. func unzip(src, dest string) error { r, err := zip.OpenReader(src) @@ -1016,7 +1016,7 @@ end You are encouraged to use the secure archive utilities provided by [LabSec](https://gitlab.com/gitlab-com/gl-security/appsec/labsec) which will handle Zip Slip and other types of vulnerabilities for you. The LabSec utilities are also context aware which makes it possible to cancel or timeout extractions: -```golang +```go package main import "gitlab-com/gl-security/appsec/labsec/archive/zip" @@ -1041,7 +1041,7 @@ func main() { In case the LabSec utilities do not fit your needs, here is an example for extracting a zip file with protection against Zip Slip attacks: -```golang +```go // unzip extracts source zip file to destination with protection against Zip Slip attacks. func unzip(src, dest string) error { r, err := zip.OpenReader(src) @@ -1118,7 +1118,7 @@ end #### Go -```golang +```go // printZipContents INSECURELY prints contents of files in a zip file. func printZipContents(src string) error { r, err := zip.OpenReader(src) @@ -1186,7 +1186,7 @@ You are encouraged to use the secure archive utilities provided by [LabSec](http In case the LabSec utilities do not fit your needs, here is an example for extracting a zip file with protection against symlink attacks: -```golang +```go // printZipContents prints contents of files in a zip file with protection against symlink attacks. func printZipContents(src string) error { r, err := zip.OpenReader(src) diff --git a/doc/development/uploads/working_with_uploads.md b/doc/development/uploads/working_with_uploads.md index 6955f9c31cd..5575297ad6b 100644 --- a/doc/development/uploads/working_with_uploads.md +++ b/doc/development/uploads/working_with_uploads.md @@ -95,7 +95,7 @@ They consist of: Example: -```golang +```go u.route("PUT", apiProjectPattern+`packages/nuget/`, mimeMultipartUploader), ``` diff --git a/doc/integration/advanced_search/elasticsearch.md b/doc/integration/advanced_search/elasticsearch.md index 0b97bfd945a..389c79a281c 100644 --- a/doc/integration/advanced_search/elasticsearch.md +++ b/doc/integration/advanced_search/elasticsearch.md @@ -227,8 +227,8 @@ The following Elasticsearch settings are available: | `AWS Secret Access Key` | The AWS secret access key. | | `Maximum file size indexed` | See [the explanation in instance limits.](../../administration/instance_limits.md#maximum-file-size-indexed). | | `Maximum field length` | See [the explanation in instance limits.](../../administration/instance_limits.md#maximum-field-length). | -| `Maximum bulk request size (MiB)` | Used by the GitLab Ruby and Golang-based indexer processes. This setting indicates how much data must be collected (and stored in memory) in a given indexing process before submitting the payload to the Elasticsearch Bulk API. For the GitLab Golang-based indexer, you should use this setting with `Bulk request concurrency`. `Maximum bulk request size (MiB)` must accommodate the resource constraints of both the Elasticsearch hosts and the hosts running the GitLab Golang-based indexer from either the `gitlab-rake` command or the Sidekiq tasks. | -| `Bulk request concurrency` | The Bulk request concurrency indicates how many of the GitLab Golang-based indexer processes (or threads) can run in parallel to collect data to subsequently submit to the Elasticsearch Bulk API. This increases indexing performance, but fills the Elasticsearch bulk requests queue faster. This setting should be used together with the Maximum bulk request size setting (see above) and needs to accommodate the resource constraints of both the Elasticsearch hosts and the hosts running the GitLab Golang-based indexer either from the `gitlab-rake` command or the Sidekiq tasks. | +| `Maximum bulk request size (MiB)` | Used by the GitLab Ruby and Go-based indexer processes. This setting indicates how much data must be collected (and stored in memory) in a given indexing process before submitting the payload to the Elasticsearch Bulk API. For the GitLab Go-based indexer, you should use this setting with `Bulk request concurrency`. `Maximum bulk request size (MiB)` must accommodate the resource constraints of both the Elasticsearch hosts and the hosts running the GitLab Go-based indexer from either the `gitlab-rake` command or the Sidekiq tasks. | +| `Bulk request concurrency` | The Bulk request concurrency indicates how many of the GitLab Go-based indexer processes (or threads) can run in parallel to collect data to subsequently submit to the Elasticsearch Bulk API. This increases indexing performance, but fills the Elasticsearch bulk requests queue faster. This setting should be used together with the Maximum bulk request size setting (see above) and needs to accommodate the resource constraints of both the Elasticsearch hosts and the hosts running the GitLab Go-based indexer either from the `gitlab-rake` command or the Sidekiq tasks. | | `Client request timeout` | Elasticsearch HTTP client request timeout value in seconds. `0` means using the system default timeout value, which depends on the libraries that GitLab application is built upon. | WARNING: diff --git a/doc/operations/feature_flags.md b/doc/operations/feature_flags.md index 8c7033f318d..968649e94b2 100644 --- a/doc/operations/feature_flags.md +++ b/doc/operations/feature_flags.md @@ -297,11 +297,11 @@ For API content, see: - [Feature flags API](../api/feature_flags.md) - [Feature flag user lists API](../api/feature_flag_user_lists.md) -### Golang application example +### Go application example -Here's an example of how to integrate feature flags in a Golang application: +Here's an example of how to integrate feature flags in a Go application: -```golang +```go package main import ( diff --git a/doc/user/application_security/coverage_fuzzing/index.md b/doc/user/application_security/coverage_fuzzing/index.md index eb00764f002..4731e09474c 100644 --- a/doc/user/application_security/coverage_fuzzing/index.md +++ b/doc/user/application_security/coverage_fuzzing/index.md @@ -40,7 +40,7 @@ You can use the following fuzzing engines to test the specified languages. | Language | Fuzzing Engine | Example | |---------------------------------------------|------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------| | C/C++ | [libFuzzer](https://llvm.org/docs/LibFuzzer.html) | [c-cpp-example](https://gitlab.com/gitlab-org/security-products/demos/coverage-fuzzing/c-cpp-fuzzing-example) | -| GoLang | [go-fuzz (libFuzzer support)](https://github.com/dvyukov/go-fuzz) | [go-fuzzing-example](https://gitlab.com/gitlab-org/security-products/demos/coverage-fuzzing/go-fuzzing-example) | +| Go | [go-fuzz (libFuzzer support)](https://github.com/dvyukov/go-fuzz) | [go-fuzzing-example](https://gitlab.com/gitlab-org/security-products/demos/coverage-fuzzing/go-fuzzing-example) | | Swift | [libFuzzer](https://github.com/apple/swift/blob/master/docs/libFuzzerIntegration.md) | [swift-fuzzing-example](https://gitlab.com/gitlab-org/security-products/demos/coverage-fuzzing/swift-fuzzing-example) | | Rust | [cargo-fuzz (libFuzzer support)](https://github.com/rust-fuzz/cargo-fuzz) | [rust-fuzzing-example](https://gitlab.com/gitlab-org/security-products/demos/coverage-fuzzing/rust-fuzzing-example) | | Java | [Javafuzz](https://gitlab.com/gitlab-org/security-products/analyzers/fuzzers/javafuzz) (recommended) | [javafuzz-fuzzing-example](https://gitlab.com/gitlab-org/security-products/demos/coverage-fuzzing/javafuzz-fuzzing-example) | diff --git a/doc/user/packages/container_registry/reduce_container_registry_storage.md b/doc/user/packages/container_registry/reduce_container_registry_storage.md index 7a991d384ac..9419451fd5d 100644 --- a/doc/user/packages/container_registry/reduce_container_registry_storage.md +++ b/doc/user/packages/container_registry/reduce_container_registry_storage.md @@ -281,7 +281,7 @@ Here are some other options you can use to reduce the Container Registry storage If you see this error message, check the regex patterns to ensure they are valid. -GitLab uses [RE2 syntax](https://github.com/google/re2/wiki/Syntax) for regular expressions in the cleanup policy. You can test them with the [regex101 regex tester](https://regex101.com/) using the Golang flavor. +GitLab uses [RE2 syntax](https://github.com/google/re2/wiki/Syntax) for regular expressions in the cleanup policy. You can test them with the [regex101 regex tester](https://regex101.com/) using the `Golang` flavor. View some common [regex pattern examples](#regex-pattern-examples). ### The cleanup policy doesn't delete any tags diff --git a/doc/user/packages/go_proxy/index.md b/doc/user/packages/go_proxy/index.md index 1a089cd82be..f0e10d73d08 100644 --- a/doc/user/packages/go_proxy/index.md +++ b/doc/user/packages/go_proxy/index.md @@ -74,7 +74,7 @@ go env -w GOPROXY='https://gitlab.example.com/api/v4/projects/1234/packages/go,h With this configuration, Go fetches dependencies in this order: 1. Go attempts to fetch from the project-specific Go proxy. -1. Go attempts to fetch from [proxy.golang.org](https://proxy.golang.org). +1. Go attempts to fetch from [`proxy.golang.org`](https://proxy.golang.org). 1. Go fetches directly with version control system operations (like `git clone`, `svn checkout`, and so on). diff --git a/doc/user/profile/img/saved_replies_dropdown_v15_10.png b/doc/user/profile/img/saved_replies_dropdown_v15_10.png Binary files differnew file mode 100644 index 00000000000..50313f71f4a --- /dev/null +++ b/doc/user/profile/img/saved_replies_dropdown_v15_10.png diff --git a/doc/user/profile/saved_replies.md b/doc/user/profile/saved_replies.md new file mode 100644 index 00000000000..302daceb31d --- /dev/null +++ b/doc/user/profile/saved_replies.md @@ -0,0 +1,61 @@ +--- +stage: Create +group: Code Review +info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments +type: howto +--- + +# Saved replies **(FREE)** + +> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/352956) in GitLab 14.9 [with a flag](../../administration/feature_flags.md) named `saved_replies`. Disabled by default. + +With saved replies, create and reuse text for any text area in: + +- Merge requests, including diffs. +- Issues, including design management comments. +- Epics. +- Work items. + +Saved replies can be small, like approving a merge request and unassigning yourself from it, +or large, like chunks of boilerplate text you use frequently: + +![Saved replies dropdown list](img/saved_replies_dropdown_v15_10.png) + +## Use saved replies in a text area + +To include the text of a saved reply in your comment: + +1. In the editor toolbar for your comment, select **Saved replies** (**{symlink}**). +1. Select your desired saved reply. + +## Create saved replies + +To create a saved reply for future use: + +1. On the top bar, in the upper-right corner, select your avatar. +1. From the dropdown list, select **Preferences**. +1. On the left sidebar, select **Saved replies** (**{symlink}**). +1. Provide a **Name** for your saved reply. +1. Enter the **Content** of your reply. You can use any formatting you use in + other GitLab text areas. +1. Select **Save**, and the page reloads with your saved reply shown. + +## View your saved replies + +To go to your saved replies: + +1. On the top bar, in the upper-right corner, select your avatar. +1. From the dropdown list, select **Preferences**. +1. On the left sidebar, select **Saved replies** (**{symlink}**). +1. Scroll to **My saved replies**. + +## Edit or delete saved replies + +To edit or delete a previously saved reply: + +1. On the top bar, in the upper-right corner, select your avatar. +1. From the dropdown list, select **Preferences**. +1. On the left sidebar, select **Saved replies** (**{symlink}**). +1. Scroll to **My saved replies**, and identify the saved reply you want to edit. +1. To edit, select **Edit** (**{pencil}**). +1. To delete, select **Delete** (**{remove}**), then select **Delete** again from the modal window. diff --git a/lib/api/files.rb b/lib/api/files.rb index 06f3b55b742..1850413caa6 100644 --- a/lib/api/files.rb +++ b/lib/api/files.rb @@ -57,15 +57,11 @@ module API end def cache_client - if Feature.enabled?(:cache_client_with_metrics, user_project) - Gitlab::Cache::Client.build_with_metadata( - cache_identifier: 'API::Files#content_sha', - feature_category: :source_code_management, - backing_resource: :gitaly - ) - else - Rails.cache - end + Gitlab::Cache::Client.build_with_metadata( + cache_identifier: 'API::Files#content_sha', + feature_category: :source_code_management, + backing_resource: :gitaly + ) end def fetch_blame_range(blame_params) diff --git a/lib/gitlab/background_migration/migrate_remediations_for_vulnerability_findings.rb b/lib/gitlab/background_migration/migrate_remediations_for_vulnerability_findings.rb index 7a2f4dab742..9eadef96db6 100644 --- a/lib/gitlab/background_migration/migrate_remediations_for_vulnerability_findings.rb +++ b/lib/gitlab/background_migration/migrate_remediations_for_vulnerability_findings.rb @@ -150,7 +150,7 @@ module Gitlab return [] unless parsed_metadata['remediations'] parsed_metadata['remediations'].filter_map do |remediation| - next unless remediation + next unless remediation && remediation['diff'].present? remediation.merge('checksum' => DiffFile.checksum(remediation['diff'])) end.compact.uniq diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 9fc511d0d17..c3123b0c1e1 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -7732,9 +7732,6 @@ msgstr "" msgid "BulkImport|Import is finished. Pick another name for re-import" msgstr "" -msgid "BulkImport|Import selected" -msgstr "" - msgid "BulkImport|Import with projects" msgstr "" diff --git a/package.json b/package.json index 32c436fce74..5f2c81e591d 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,7 @@ "@gitlab/favicon-overlay": "2.0.0", "@gitlab/fonts": "^1.2.0", "@gitlab/svgs": "3.24.0", - "@gitlab/ui": "56.4.0", + "@gitlab/ui": "56.4.1", "@gitlab/visual-review-tools": "1.7.3", "@gitlab/web-ide": "0.0.1-dev-20230223005157", "@mattiasbuelens/web-streams-adapter": "^0.1.0", diff --git a/spec/frontend/header_search/store/getters_spec.js b/spec/frontend/header_search/store/getters_spec.js index a1d9481b5cc..7a7a00178f1 100644 --- a/spec/frontend/header_search/store/getters_spec.js +++ b/spec/frontend/header_search/store/getters_spec.js @@ -241,6 +241,13 @@ describe('Header Search Store Getters', () => { MOCK_DEFAULT_SEARCH_OPTIONS, ); }); + + it('returns the correct array if issues path is false', () => { + mockGetters.scopedIssuesPath = undefined; + expect(getters.defaultSearchOptions(state, mockGetters)).toStrictEqual( + MOCK_DEFAULT_SEARCH_OPTIONS.slice(2, MOCK_DEFAULT_SEARCH_OPTIONS.length), + ); + }); }); describe('scopedSearchOptions', () => { diff --git a/spec/frontend/import_entities/import_groups/components/import_actions_cell_spec.js b/spec/frontend/import_entities/import_groups/components/import_actions_cell_spec.js index e813c9eab11..1a52485f779 100644 --- a/spec/frontend/import_entities/import_groups/components/import_actions_cell_spec.js +++ b/spec/frontend/import_entities/import_groups/components/import_actions_cell_spec.js @@ -1,4 +1,4 @@ -import { GlButton, GlIcon, GlDropdown, GlDropdownItem } from '@gitlab/ui'; +import { GlDropdown, GlIcon, GlDropdownItem } from '@gitlab/ui'; import { shallowMount } from '@vue/test-utils'; import ImportActionsCell from '~/import_entities/import_groups/components/import_actions_cell.vue'; @@ -8,7 +8,6 @@ describe('import actions cell', () => { const createComponent = (props) => { wrapper = shallowMount(ImportActionsCell, { propsData: { - isProjectsImportEnabled: false, isFinished: false, isAvailableForImport: false, isInvalid: false, @@ -22,10 +21,10 @@ describe('import actions cell', () => { createComponent({ isAvailableForImport: true }); }); - it('renders import button', () => { - const button = wrapper.findComponent(GlButton); - expect(button.exists()).toBe(true); - expect(button.text()).toBe('Import'); + it('renders import dropdown', () => { + const dropdown = wrapper.findComponent(GlDropdown); + expect(dropdown.exists()).toBe(true); + expect(dropdown.props('text')).toBe('Import with projects'); }); it('does not render icon with a hint', () => { @@ -38,10 +37,10 @@ describe('import actions cell', () => { createComponent({ isAvailableForImport: false, isFinished: true }); }); - it('renders re-import button', () => { - const button = wrapper.findComponent(GlButton); - expect(button.exists()).toBe(true); - expect(button.text()).toBe('Re-import'); + it('renders re-import dropdown', () => { + const dropdown = wrapper.findComponent(GlDropdown); + expect(dropdown.exists()).toBe(true); + expect(dropdown.props('text')).toBe('Re-import with projects'); }); it('renders icon with a hint', () => { @@ -53,25 +52,25 @@ describe('import actions cell', () => { }); }); - it('does not render import button when group is not available for import', () => { + it('does not render import dropdown when group is not available for import', () => { createComponent({ isAvailableForImport: false }); - const button = wrapper.findComponent(GlButton); - expect(button.exists()).toBe(false); + const dropdown = wrapper.findComponent(GlDropdown); + expect(dropdown.exists()).toBe(false); }); - it('renders import button as disabled when group is invalid', () => { + it('renders import dropdown as disabled when group is invalid', () => { createComponent({ isInvalid: true, isAvailableForImport: true }); - const button = wrapper.findComponent(GlButton); - expect(button.props().disabled).toBe(true); + const dropdown = wrapper.findComponent(GlDropdown); + expect(dropdown.props().disabled).toBe(true); }); it('emits import-group event when import button is clicked', () => { createComponent({ isAvailableForImport: true }); - const button = wrapper.findComponent(GlButton); - button.vm.$emit('click'); + const dropdown = wrapper.findComponent(GlDropdown); + dropdown.vm.$emit('click'); expect(wrapper.emitted('import-group')).toHaveLength(1); }); @@ -81,10 +80,10 @@ describe('import actions cell', () => { ${false} | ${'Import'} ${true} | ${'Re-import'} `( - 'when import projects is enabled, group is available for import and finish status is $status', + 'group is available for import and finish status is $isFinished', ({ isFinished, expectedAction }) => { beforeEach(() => { - createComponent({ isProjectsImportEnabled: true, isAvailableForImport: true, isFinished }); + createComponent({ isAvailableForImport: true, isFinished }); }); it('render import dropdown', () => { diff --git a/spec/frontend/import_entities/import_groups/components/import_table_spec.js b/spec/frontend/import_entities/import_groups/components/import_table_spec.js index f664f4a4fe7..205218fdabd 100644 --- a/spec/frontend/import_entities/import_groups/components/import_table_spec.js +++ b/spec/frontend/import_entities/import_groups/components/import_table_spec.js @@ -49,12 +49,12 @@ describe('import table', () => { }, }; - const findImportSelectedButton = () => - wrapper.findAll('button').wrappers.find((w) => w.text() === 'Import selected'); const findImportSelectedDropdown = () => - wrapper.findAll('.gl-dropdown').wrappers.find((w) => w.text().includes('Import with projects')); - const findImportButtons = () => - wrapper.findAll('button').wrappers.filter((w) => w.text() === 'Import'); + wrapper.find('[data-testid="import-selected-groups-dropdown"]'); + const findRowImportDropdownAtIndex = (idx) => + wrapper.findAll('tbody td button').wrappers.filter((w) => w.text() === 'Import with projects')[ + idx + ]; const findPaginationDropdown = () => wrapper.find('[data-testid="page-size"]'); const findTargetNamespaceDropdown = (rowWrapper) => rowWrapper.find('[data-testid="target-namespace-selector"]'); @@ -70,12 +70,7 @@ describe('import table', () => { const findRowCheckbox = (idx) => wrapper.findAll('tbody td input[type=checkbox]').at(idx); const selectRow = (idx) => findRowCheckbox(idx).setChecked(true); - const createComponent = ({ - bulkImportSourceGroups, - importGroups, - defaultTargetNamespace, - glFeatures = {}, - }) => { + const createComponent = ({ bulkImportSourceGroups, importGroups, defaultTargetNamespace }) => { apolloProvider = createMockApollo( [ [ @@ -104,9 +99,6 @@ describe('import table', () => { directives: { GlTooltip: createMockDirective('gl-tooltip'), }, - provide: { - glFeatures, - }, apolloProvider, }); }; @@ -130,7 +122,7 @@ describe('import table', () => { expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(true); }); - it('does not renders loading icon when request is completed', async () => { + it('does not render loading icon when request is completed', async () => { createComponent({ bulkImportSourceGroups: () => [], }); @@ -241,12 +233,13 @@ describe('import table', () => { await waitForPromises(); - await findImportButtons()[0].trigger('click'); + await findRowImportDropdownAtIndex(0).trigger('click'); expect(apolloProvider.defaultClient.mutate).toHaveBeenCalledWith({ mutation: importGroupsMutation, variables: { importRequests: [ { + migrateProjects: true, newName: FAKE_GROUP.lastImportTarget.newName, sourceGroupId: FAKE_GROUP.id, targetNamespace: AVAILABLE_NAMESPACES[0].fullPath, @@ -269,7 +262,7 @@ describe('import table', () => { }); await waitForPromises(); - await findImportButtons()[0].trigger('click'); + await findRowImportDropdownAtIndex(0).trigger('click'); await waitForPromises(); expect(createAlert).toHaveBeenCalledWith( @@ -294,7 +287,7 @@ describe('import table', () => { }); await waitForPromises(); - await findImportButtons()[0].trigger('click'); + await findRowImportDropdownAtIndex(0).trigger('click'); await waitForPromises(); expect(createAlert).not.toHaveBeenCalled(); @@ -472,7 +465,7 @@ describe('import table', () => { }); await waitForPromises(); - expect(findImportSelectedButton().props().disabled).toBe(true); + expect(findImportSelectedDropdown().props().disabled).toBe(true); }); it('import selected button is enabled when groups were selected for import', async () => { @@ -487,7 +480,7 @@ describe('import table', () => { await selectRow(0); - expect(findImportSelectedButton().props().disabled).toBe(false); + expect(findImportSelectedDropdown().props().disabled).toBe(false); }); it('does not allow selecting already started groups', async () => { @@ -505,7 +498,7 @@ describe('import table', () => { await selectRow(0); await nextTick(); - expect(findImportSelectedButton().props().disabled).toBe(true); + expect(findImportSelectedDropdown().props().disabled).toBe(true); }); it('does not allow selecting groups with validation errors', async () => { @@ -530,10 +523,10 @@ describe('import table', () => { await selectRow(0); await nextTick(); - expect(findImportSelectedButton().props().disabled).toBe(true); + expect(findImportSelectedDropdown().props().disabled).toBe(true); }); - it('invokes importGroups mutation when import selected button is clicked', async () => { + it('invokes importGroups mutation when import selected dropdown is clicked', async () => { const NEW_GROUPS = [ generateFakeEntry({ id: 1, status: STATUSES.NONE }), generateFakeEntry({ id: 2, status: STATUSES.NONE }), @@ -554,7 +547,7 @@ describe('import table', () => { await selectRow(1); await nextTick(); - await findImportSelectedButton().trigger('click'); + await findImportSelectedDropdown().find('button').trigger('click'); expect(apolloProvider.defaultClient.mutate).toHaveBeenCalledWith({ mutation: importGroupsMutation, @@ -675,7 +668,7 @@ describe('import table', () => { }); }); - describe('when import projects is enabled', () => { + describe('importing projects', () => { const NEW_GROUPS = [ generateFakeEntry({ id: 1, status: STATUSES.NONE }), generateFakeEntry({ id: 2, status: STATUSES.NONE }), @@ -689,9 +682,6 @@ describe('import table', () => { pageInfo: FAKE_PAGE_INFO, versionValidation: FAKE_VERSION_VALIDATION, }), - glFeatures: { - bulkImportProjects: true, - }, }); jest.spyOn(apolloProvider.defaultClient, 'mutate'); return waitForPromises(); diff --git a/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/tags_list_row_spec.js b/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/tags_list_row_spec.js index 2d08cba5f7c..bfefe46c09b 100644 --- a/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/tags_list_row_spec.js +++ b/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/tags_list_row_spec.js @@ -278,26 +278,30 @@ describe('tags list row', () => { textSrOnly: true, category: 'tertiary', right: true, + disabled: false, }); }); - it.each` - canDelete | digest | disabled | buttonDisabled - ${true} | ${null} | ${true} | ${true} - ${false} | ${'foo'} | ${true} | ${true} - ${false} | ${null} | ${true} | ${true} - ${true} | ${'foo'} | ${true} | ${true} - ${true} | ${'foo'} | ${false} | ${false} - `( - 'is $visible that is visible when canDelete is $canDelete and digest is $digest and disabled is $disabled', - ({ canDelete, digest, disabled, buttonDisabled }) => { - mountComponent({ ...defaultProps, tag: { ...tag, canDelete, digest }, disabled }); + it('has the correct classes', () => { + mountComponent(); - expect(findAdditionalActionsMenu().props('disabled')).toBe(buttonDisabled); - expect(findAdditionalActionsMenu().classes('gl-opacity-0')).toBe(buttonDisabled); - expect(findAdditionalActionsMenu().classes('gl-pointer-events-none')).toBe(buttonDisabled); - }, - ); + expect(findAdditionalActionsMenu().classes('gl-opacity-0')).toBe(false); + expect(findAdditionalActionsMenu().classes('gl-pointer-events-none')).toBe(false); + }); + + it('is not rendered when tag.canDelete is false', () => { + mountComponent({ ...defaultProps, tag: { ...tag, canDelete: false } }); + + expect(findAdditionalActionsMenu().exists()).toBe(false); + }); + + it('is hidden when disabled prop is set to true', () => { + mountComponent({ ...defaultProps, disabled: true }); + + expect(findAdditionalActionsMenu().props('disabled')).toBe(true); + expect(findAdditionalActionsMenu().classes('gl-opacity-0')).toBe(true); + expect(findAdditionalActionsMenu().classes('gl-pointer-events-none')).toBe(true); + }); describe('delete button', () => { it('exists and has the correct attrs', () => { diff --git a/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/tags_list_spec.js b/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/tags_list_spec.js index 8501cbc2bae..09d0370efbf 100644 --- a/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/tags_list_spec.js +++ b/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/tags_list_spec.js @@ -69,10 +69,10 @@ describe('Tags List', () => { }); describe('registry list', () => { - beforeEach(() => { + beforeEach(async () => { mountComponent(); fireFirstSortUpdate(); - return waitForApolloRequestRender(); + await waitForApolloRequestRender(); }); it('has a persisted search', () => { @@ -94,6 +94,7 @@ describe('Tags List', () => { pagination: tagsPageInfo, items: tags, idProperty: 'name', + hiddenDelete: false, }); }); @@ -182,12 +183,23 @@ describe('Tags List', () => { }); }); + describe('when user does not have permission to delete list rows', () => { + it('sets registry list hiddenDelete prop to true', async () => { + resolver = jest.fn().mockResolvedValue(imageTagsMock({ canDelete: false })); + mountComponent(); + fireFirstSortUpdate(); + await waitForApolloRequestRender(); + + expect(findRegistryList().props('hiddenDelete')).toBe(true); + }); + }); + describe('when the list of tags is empty', () => { - beforeEach(() => { - resolver = jest.fn().mockResolvedValue(imageTagsMock([])); + beforeEach(async () => { + resolver = jest.fn().mockResolvedValue(imageTagsMock({ nodes: [] })); mountComponent(); fireFirstSortUpdate(); - return waitForApolloRequestRender(); + await waitForApolloRequestRender(); }); it('does not show the loader', () => { diff --git a/spec/frontend/packages_and_registries/container_registry/explorer/mock_data.js b/spec/frontend/packages_and_registries/container_registry/explorer/mock_data.js index e5b99f15e8c..cd54b856c97 100644 --- a/spec/frontend/packages_and_registries/container_registry/explorer/mock_data.js +++ b/spec/frontend/packages_and_registries/container_registry/explorer/mock_data.js @@ -177,11 +177,12 @@ export const tagsMock = [ }, ]; -export const imageTagsMock = (nodes = tagsMock) => ({ +export const imageTagsMock = ({ nodes = tagsMock, canDelete = true } = {}) => ({ data: { containerRepository: { id: containerRepositoryMock.id, tagsCount: nodes.length, + canDelete, tags: { nodes, pageInfo: { ...tagsPageInfo }, diff --git a/spec/frontend/packages_and_registries/shared/components/registry_list_spec.js b/spec/frontend/packages_and_registries/shared/components/registry_list_spec.js index b821352922f..a4e0d267023 100644 --- a/spec/frontend/packages_and_registries/shared/components/registry_list_spec.js +++ b/spec/frontend/packages_and_registries/shared/components/registry_list_spec.js @@ -107,10 +107,21 @@ describe('Registry List', () => { expect(findDeleteSelected().text()).toBe(component.i18n.deleteSelected); }); - it('is hidden when hiddenDelete is true', () => { - mountComponent({ propsData: { ...defaultPropsData, hiddenDelete: true } }); + describe('when hiddenDelete is true', () => { + beforeEach(() => { + mountComponent({ propsData: { ...defaultPropsData, hiddenDelete: true } }); + }); + + it('is hidden', () => { + expect(findDeleteSelected().exists()).toBe(false); + }); - expect(findDeleteSelected().exists()).toBe(false); + it('populates the first slot prop correctly', async () => { + expect(findScopedSlots().at(0).exists()).toBe(true); + + // it's the first slot + expect(findScopedSlotFirstValue(0).text()).toBe('false'); + }); }); it('is disabled when isLoading is true', () => { diff --git a/spec/helpers/search_helper_spec.rb b/spec/helpers/search_helper_spec.rb index c7afe0bf391..ba703914049 100644 --- a/spec/helpers/search_helper_spec.rb +++ b/spec/helpers/search_helper_spec.rb @@ -829,6 +829,21 @@ RSpec.describe SearchHelper, feature_category: :global_search do expect(header_search_context[:project_metadata]).to eq(project_metadata) end + context 'feature issues is not available' do + let(:feature_available) { false } + let(:project_metadata) { { mr_path: project_merge_requests_path(project) } } + + before do + allow(project).to receive(:feature_available?).and_call_original + allow(project).to receive(:feature_available?).with(:issues, current_user).and_return(feature_available) + end + + it 'adds the :project and :project-metadata correctly to hash' do + expect(header_search_context[:project]).to eq({ id: project.id, name: project.name }) + expect(header_search_context[:project_metadata]).to eq(project_metadata) + end + end + context 'with scope' do let(:scope) { 'issues' } diff --git a/spec/lib/gitlab/background_migration/migrate_remediations_for_vulnerability_findings_spec.rb b/spec/lib/gitlab/background_migration/migrate_remediations_for_vulnerability_findings_spec.rb index 84259505683..b75c0e61b19 100644 --- a/spec/lib/gitlab/background_migration/migrate_remediations_for_vulnerability_findings_spec.rb +++ b/spec/lib/gitlab/background_migration/migrate_remediations_for_vulnerability_findings_spec.rb @@ -57,6 +57,18 @@ RSpec.describe Gitlab::BackgroundMigration::MigrateRemediationsForVulnerabilityF end end + context 'with remediation with empty string as the diff key' do + let!(:finding) do + create_finding!(project1.id, scanner1.id, { remediations: [{ summary: 'summary', diff: '' }] }) + end + + it 'does not create any remediation' do + expect(Gitlab::AppLogger).not_to receive(:error) + + expect { perform_migration }.not_to change { vulnerability_remediations.count } + end + end + context 'with remediation equals to an array of duplicated elements' do let!(:finding) do create_finding!(project1.id, scanner1.id, { remediations: [remediation_hash, remediation_hash] }) diff --git a/spec/migrations/20230118144623_schedule_migration_for_remediation_spec.rb b/spec/migrations/20230118144623_schedule_migration_for_remediation_spec.rb index d22aeeaa254..f6d0f32b87c 100644 --- a/spec/migrations/20230118144623_schedule_migration_for_remediation_spec.rb +++ b/spec/migrations/20230118144623_schedule_migration_for_remediation_spec.rb @@ -10,13 +10,7 @@ RSpec.describe ScheduleMigrationForRemediation, :migration, feature_category: :v it 'schedules a batched background migration' do migrate! - expect(migration).to have_scheduled_batched_migration( - table_name: :vulnerability_occurrences, - column_name: :id, - interval: described_class::DELAY_INTERVAL, - batch_size: described_class::BATCH_SIZE, - sub_batch_size: described_class::SUB_BATCH_SIZE - ) + expect(migration).not_to have_scheduled_batched_migration end end diff --git a/spec/migrations/20230214181633_finalize_ci_build_needs_big_int_conversion_spec.rb b/spec/migrations/20230214181633_finalize_ci_build_needs_big_int_conversion_spec.rb new file mode 100644 index 00000000000..638fe2a12d5 --- /dev/null +++ b/spec/migrations/20230214181633_finalize_ci_build_needs_big_int_conversion_spec.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe FinalizeCiBuildNeedsBigIntConversion, migration: :gitlab_ci, feature_category: :continuous_integration do + describe '#up' do + using RSpec::Parameterized::TableSyntax + + where(:dot_com, :dev_or_test, :jh, :expectation) do + true | true | true | :not_to + true | false | true | :not_to + false | true | true | :not_to + false | false | true | :not_to + true | true | false | :to + true | false | false | :to + false | true | false | :to + false | false | false | :not_to + end + + with_them do + it 'ensures the migration is completed for GitLab.com, dev, or test' do + allow(Gitlab).to receive(:com?).and_return(dot_com) + allow(Gitlab).to receive(:dev_or_test_env?).and_return(dev_or_test) + allow(Gitlab).to receive(:jh?).and_return(jh) + + migration_arguments = { + job_class_name: 'CopyColumnUsingBackgroundMigrationJob', + table_name: 'ci_build_needs', + column_name: 'id', + job_arguments: [['id'], ['id_convert_to_bigint']] + } + + expect(described_class).send( + expectation, + ensure_batched_background_migration_is_finished_for(migration_arguments) + ) + + migrate! + end + end + end +end diff --git a/spec/migrations/20230220102212_swap_columns_ci_build_needs_big_int_conversion_spec.rb b/spec/migrations/20230220102212_swap_columns_ci_build_needs_big_int_conversion_spec.rb new file mode 100644 index 00000000000..1c21047c0c3 --- /dev/null +++ b/spec/migrations/20230220102212_swap_columns_ci_build_needs_big_int_conversion_spec.rb @@ -0,0 +1,60 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe SwapColumnsCiBuildNeedsBigIntConversion, feature_category: :continuous_integration do + describe '#up' do + using RSpec::Parameterized::TableSyntax + + where(:dot_com, :dev_or_test, :jh, :swap) do + true | true | true | false + true | false | true | false + false | true | true | false + false | false | true | false + true | true | false | true + true | false | false | true + false | true | false | true + false | false | false | false + end + + with_them do + before do + connection = described_class.new.connection + connection.execute('ALTER TABLE ci_build_needs ALTER COLUMN id TYPE integer') + connection.execute('ALTER TABLE ci_build_needs ALTER COLUMN id_convert_to_bigint TYPE bigint') + end + + it 'swaps the integer and bigint columns for GitLab.com, dev, or test' do + allow(Gitlab).to receive(:com?).and_return(dot_com) + allow(Gitlab).to receive(:dev_or_test_env?).and_return(dev_or_test) + allow(Gitlab).to receive(:jh?).and_return(jh) + + ci_build_needs = table(:ci_build_needs) + + disable_migrations_output do + reversible_migration do |migration| + migration.before -> { + ci_build_needs.reset_column_information + + expect(ci_build_needs.columns.find { |c| c.name == 'id' }.sql_type).to eq('integer') + expect(ci_build_needs.columns.find { |c| c.name == 'id_convert_to_bigint' }.sql_type).to eq('bigint') + } + + migration.after -> { + ci_build_needs.reset_column_information + + if swap + expect(ci_build_needs.columns.find { |c| c.name == 'id' }.sql_type).to eq('bigint') + expect(ci_build_needs.columns.find { |c| c.name == 'id_convert_to_bigint' }.sql_type).to eq('integer') + else + expect(ci_build_needs.columns.find { |c| c.name == 'id' }.sql_type).to eq('integer') + expect(ci_build_needs.columns.find { |c| c.name == 'id_convert_to_bigint' }.sql_type).to eq('bigint') + end + } + end + end + end + end + end +end diff --git a/spec/migrations/20230309071242_delete_security_policy_bot_users_spec.rb b/spec/migrations/20230309071242_delete_security_policy_bot_users_spec.rb new file mode 100644 index 00000000000..4dd44cad158 --- /dev/null +++ b/spec/migrations/20230309071242_delete_security_policy_bot_users_spec.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe DeleteSecurityPolicyBotUsers, feature_category: :security_policy_management do + let(:users) { table(:users) } + + before do + users.create!(user_type: 10, projects_limit: 0, email: 'security_policy_bot@example.com') + users.create!(user_type: 1, projects_limit: 0, email: 'support_bot@example.com') + users.create!(projects_limit: 0, email: 'human@example.com') + end + + describe '#up' do + it 'deletes security_policy_bot users' do + expect { migrate! }.to change { users.count }.by(-1) + + expect(users.where(user_type: 10).count).to eq(0) + expect(users.where(user_type: 1).count).to eq(1) + expect(users.where(user_type: nil).count).to eq(1) + end + end +end diff --git a/spec/migrations/20230313150531_reschedule_migration_for_remediation_spec.rb b/spec/migrations/20230313150531_reschedule_migration_for_remediation_spec.rb new file mode 100644 index 00000000000..00f0836285b --- /dev/null +++ b/spec/migrations/20230313150531_reschedule_migration_for_remediation_spec.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe RescheduleMigrationForRemediation, :migration, feature_category: :vulnerability_management do + let(:migration) { described_class::MIGRATION } + + describe '#up' do + it 'schedules a batched background migration' do + migrate! + + expect(migration).to have_scheduled_batched_migration( + table_name: :vulnerability_occurrences, + column_name: :id, + interval: described_class::DELAY_INTERVAL, + batch_size: described_class::BATCH_SIZE, + sub_batch_size: described_class::SUB_BATCH_SIZE + ) + end + end + + describe '#down' do + it 'deletes all batched migration records' do + migrate! + schema_migrate_down! + + expect(migration).not_to have_scheduled_batched_migration + end + end +end diff --git a/spec/models/concerns/has_user_type_spec.rb b/spec/models/concerns/has_user_type_spec.rb index 87dacc71ca3..03d2c267098 100644 --- a/spec/models/concerns/has_user_type_spec.rb +++ b/spec/models/concerns/has_user_type_spec.rb @@ -6,7 +6,7 @@ RSpec.describe User, feature_category: :system_access do specify 'types consistency checks', :aggregate_failures do expect(described_class::USER_TYPES.keys) .to match_array(%w[human ghost alert_bot project_bot support_bot service_user security_bot visual_review_bot - migration_bot automation_bot admin_bot suggested_reviewers_bot service_account]) + migration_bot automation_bot security_policy_bot admin_bot suggested_reviewers_bot service_account]) expect(described_class::USER_TYPES).to include(*described_class::BOT_USER_TYPES) expect(described_class::USER_TYPES).to include(*described_class::NON_INTERNAL_USER_TYPES) expect(described_class::USER_TYPES).to include(*described_class::INTERNAL_USER_TYPES) diff --git a/spec/requests/api/files_spec.rb b/spec/requests/api/files_spec.rb index c9341934ec9..ed84e3e5f48 100644 --- a/spec/requests/api/files_spec.rb +++ b/spec/requests/api/files_spec.rb @@ -157,27 +157,6 @@ RSpec.describe API::Files, feature_category: :source_code_management do head api(route(file_path), current_user, **options), params: params end - context 'when feature flag "cache_client_with_metrics" is disabled' do - before do - stub_feature_flags(cache_client_with_metrics: false) - end - - it 'caches sha256 of the content', :use_clean_rails_redis_caching do - head api(route(file_path), current_user, **options), params: params - - expect(Gitlab::Cache::Client).not_to receive(:build_with_metadata) - - expect(Rails.cache.fetch("blob_content_sha256:#{project.full_path}:#{response.headers['X-Gitlab-Blob-Id']}")) - .to eq(content_sha256) - - expect_next_instance_of(Gitlab::Git::Blob) do |instance| - expect(instance).not_to receive(:load_all_data!) - end - - head api(route(file_path), current_user, **options), params: params - end - end - it 'returns file by commit sha' do # This file is deleted on HEAD file_path = 'files%2Fjs%2Fcommit%2Ejs%2Ecoffee' diff --git a/spec/requests/api/issues/get_group_issues_spec.rb b/spec/requests/api/issues/get_group_issues_spec.rb index 0641c2135c1..eaa3c46d0ca 100644 --- a/spec/requests/api/issues/get_group_issues_spec.rb +++ b/spec/requests/api/issues/get_group_issues_spec.rb @@ -74,7 +74,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do let(:base_url) { "/groups/#{group.id}/issues" } shared_examples 'group issues statistics' do - it 'returns issues statistics' do + it 'returns issues statistics', :aggregate_failures do get api("/groups/#{group.id}/issues_statistics", user), params: params expect(response).to have_gitlab_http_status(:ok) @@ -346,7 +346,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do group_project.add_reporter(user) end - it 'exposes known attributes' do + it 'exposes known attributes', :aggregate_failures do get api(base_url, admin) expect(response).to have_gitlab_http_status(:ok) @@ -355,7 +355,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do end it 'returns all group issues (including opened and closed)' do - get api(base_url, admin) + get api(base_url, admin, admin_mode: true) expect_paginated_array_response([group_closed_issue.id, group_confidential_issue.id, group_issue.id]) end @@ -385,7 +385,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do end it 'returns group confidential issues for admin' do - get api(base_url, admin), params: { state: :opened } + get api(base_url, admin, admin_mode: true), params: { state: :opened } expect_paginated_array_response([group_confidential_issue.id, group_issue.id]) end @@ -403,7 +403,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do end context 'labels parameter' do - it 'returns an array of labeled group issues' do + it 'returns an array of labeled group issues', :aggregate_failures do get api(base_url, user), params: { labels: group_label.title } expect_paginated_array_response(group_issue.id) @@ -486,7 +486,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do end end - it 'returns an array of issues found by iids' do + it 'returns an array of issues found by iids', :aggregate_failures do get api(base_url, user), params: { iids: [group_issue.iid] } expect_paginated_array_response(group_issue.id) @@ -505,14 +505,14 @@ RSpec.describe API::Issues, feature_category: :team_planning do expect_paginated_array_response([]) end - it 'returns an array of group issues with any label' do + it 'returns an array of group issues with any label', :aggregate_failures do get api(base_url, user), params: { labels: IssuableFinder::Params::FILTER_ANY } expect_paginated_array_response(group_issue.id) expect(json_response.first['id']).to eq(group_issue.id) end - it 'returns an array of group issues with any label with labels param as array' do + it 'returns an array of group issues with any label with labels param as array', :aggregate_failures do get api(base_url, user), params: { labels: [IssuableFinder::Params::FILTER_ANY] } expect_paginated_array_response(group_issue.id) @@ -555,7 +555,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do expect_paginated_array_response(group_closed_issue.id) end - it 'returns an array of issues with no milestone' do + it 'returns an array of issues with no milestone', :aggregate_failures do get api(base_url, user), params: { milestone: no_milestone_title } expect(response).to have_gitlab_http_status(:ok) @@ -688,28 +688,28 @@ RSpec.describe API::Issues, feature_category: :team_planning do let!(:issue2) { create(:issue, author: user2, project: group_project, created_at: 2.days.ago) } let!(:issue3) { create(:issue, author: user2, assignees: [assignee, another_assignee], project: group_project, created_at: 1.day.ago) } - it 'returns issues with by assignee_username' do + it 'returns issues with by assignee_username', :aggregate_failures do get api(base_url, user), params: { assignee_username: [assignee.username], scope: 'all' } expect(issue3.reload.assignees.pluck(:id)).to match_array([assignee.id, another_assignee.id]) expect_paginated_array_response([issue3.id, group_confidential_issue.id]) end - it 'returns issues by assignee_username as string' do + it 'returns issues by assignee_username as string', :aggregate_failures do get api(base_url, user), params: { assignee_username: assignee.username, scope: 'all' } expect(issue3.reload.assignees.pluck(:id)).to match_array([assignee.id, another_assignee.id]) expect_paginated_array_response([issue3.id, group_confidential_issue.id]) end - it 'returns error when multiple assignees are passed' do + it 'returns error when multiple assignees are passed', :aggregate_failures do get api(base_url, user), params: { assignee_username: [assignee.username, another_assignee.username], scope: 'all' } expect(response).to have_gitlab_http_status(:bad_request) expect(json_response["error"]).to include("allows one value, but found 2") end - it 'returns error when assignee_username and assignee_id are passed together' do + it 'returns error when assignee_username and assignee_id are passed together', :aggregate_failures do get api(base_url, user), params: { assignee_username: [assignee.username], assignee_id: another_assignee.id, scope: 'all' } expect(response).to have_gitlab_http_status(:bad_request) @@ -719,7 +719,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do end describe "#to_reference" do - it 'exposes reference path in context of group' do + it 'exposes reference path in context of group', :aggregate_failures do get api(base_url, user) expect(json_response.first['references']['short']).to eq("##{group_closed_issue.iid}") @@ -735,7 +735,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do group_closed_issue.reload end - it 'exposes reference path in context of parent group' do + it 'exposes reference path in context of parent group', :aggregate_failures do get api("/groups/#{parent_group.id}/issues") expect(json_response.first['references']['short']).to eq("##{group_closed_issue.iid}") diff --git a/spec/requests/api/issues/get_project_issues_spec.rb b/spec/requests/api/issues/get_project_issues_spec.rb index 6fc3903103b..915b8fff75e 100644 --- a/spec/requests/api/issues/get_project_issues_spec.rb +++ b/spec/requests/api/issues/get_project_issues_spec.rb @@ -99,7 +99,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do end shared_examples 'project issues statistics' do - it 'returns project issues statistics' do + it 'returns project issues statistics', :aggregate_failures do get api("/projects/#{project.id}/issues_statistics", current_user), params: params expect(response).to have_gitlab_http_status(:ok) @@ -317,7 +317,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do end it 'returns project confidential issues for admin' do - get api("#{base_url}/issues", admin) + get api("#{base_url}/issues", admin, admin_mode: true) expect_paginated_array_response([issue.id, confidential_issue.id, closed_issue.id]) end @@ -526,7 +526,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do expect_paginated_array_response([closed_issue.id, confidential_issue.id, issue.id]) end - it 'exposes known attributes' do + it 'exposes known attributes', :aggregate_failures do get api("#{base_url}/issues", user) expect(response).to have_gitlab_http_status(:ok) @@ -607,28 +607,28 @@ RSpec.describe API::Issues, feature_category: :team_planning do let!(:issue2) { create(:issue, author: user2, project: project, created_at: 2.days.ago) } let!(:issue3) { create(:issue, author: user2, assignees: [assignee, another_assignee], project: project, created_at: 1.day.ago) } - it 'returns issues by assignee_username' do + it 'returns issues by assignee_username', :aggregate_failures do get api("/issues", user), params: { assignee_username: [assignee.username], scope: 'all' } expect(issue3.reload.assignees.pluck(:id)).to match_array([assignee.id, another_assignee.id]) expect_paginated_array_response([confidential_issue.id, issue3.id]) end - it 'returns issues by assignee_username as string' do + it 'returns issues by assignee_username as string', :aggregate_failures do get api("/issues", user), params: { assignee_username: assignee.username, scope: 'all' } expect(issue3.reload.assignees.pluck(:id)).to match_array([assignee.id, another_assignee.id]) expect_paginated_array_response([confidential_issue.id, issue3.id]) end - it 'returns error when multiple assignees are passed' do + it 'returns error when multiple assignees are passed', :aggregate_failures do get api("/issues", user), params: { assignee_username: [assignee.username, another_assignee.username], scope: 'all' } expect(response).to have_gitlab_http_status(:bad_request) expect(json_response["error"]).to include("allows one value, but found 2") end - it 'returns error when assignee_username and assignee_id are passed together' do + it 'returns error when assignee_username and assignee_id are passed together', :aggregate_failures do get api("/issues", user), params: { assignee_username: [assignee.username], assignee_id: another_assignee.id, scope: 'all' } expect(response).to have_gitlab_http_status(:bad_request) @@ -646,7 +646,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do end end - it 'exposes known attributes' do + it 'exposes known attributes', :aggregate_failures do get api("/projects/#{project.id}/issues/#{issue.iid}", user) expect(response).to have_gitlab_http_status(:ok) @@ -686,7 +686,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do end end - it 'exposes the closed_at attribute' do + it 'exposes the closed_at attribute', :aggregate_failures do get api("/projects/#{project.id}/issues/#{closed_issue.iid}", user) expect(response).to have_gitlab_http_status(:ok) @@ -694,7 +694,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do end context 'links exposure' do - it 'exposes related resources full URIs' do + it 'exposes related resources full URIs', :aggregate_failures do get api("/projects/#{project.id}/issues/#{issue.iid}", user) links = json_response['_links'] @@ -706,7 +706,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do end end - it 'returns a project issue by internal id' do + it 'returns a project issue by internal id', :aggregate_failures do get api("/projects/#{project.id}/issues/#{issue.iid}", user) expect(response).to have_gitlab_http_status(:ok) @@ -738,7 +738,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do expect(response).to have_gitlab_http_status(:not_found) end - it 'returns confidential issue for project members' do + it 'returns confidential issue for project members', :aggregate_failures do get api("/projects/#{project.id}/issues/#{confidential_issue.iid}", user) expect(response).to have_gitlab_http_status(:ok) @@ -746,7 +746,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do expect(json_response['iid']).to eq(confidential_issue.iid) end - it 'returns confidential issue for author' do + it 'returns confidential issue for author', :aggregate_failures do get api("/projects/#{project.id}/issues/#{confidential_issue.iid}", author) expect(response).to have_gitlab_http_status(:ok) @@ -754,7 +754,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do expect(json_response['iid']).to eq(confidential_issue.iid) end - it 'returns confidential issue for assignee' do + it 'returns confidential issue for assignee', :aggregate_failures do get api("/projects/#{project.id}/issues/#{confidential_issue.iid}", assignee) expect(response).to have_gitlab_http_status(:ok) @@ -762,8 +762,8 @@ RSpec.describe API::Issues, feature_category: :team_planning do expect(json_response['iid']).to eq(confidential_issue.iid) end - it 'returns confidential issue for admin' do - get api("/projects/#{project.id}/issues/#{confidential_issue.iid}", admin) + it 'returns confidential issue for admin', :aggregate_failures do + get api("/projects/#{project.id}/issues/#{confidential_issue.iid}", admin, admin_mode: true) expect(response).to have_gitlab_http_status(:ok) expect(json_response['title']).to eq(confidential_issue.title) @@ -829,7 +829,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do let!(:related_mr) { create_referencing_mr(user, project, issue) } context 'when unauthenticated' do - it 'return list of referenced merge requests from issue' do + it 'return list of referenced merge requests from issue', :aggregate_failures do get_related_merge_requests(project.id, issue.iid) expect_paginated_array_response(related_mr.id) @@ -898,8 +898,8 @@ RSpec.describe API::Issues, feature_category: :team_planning do end end - it 'exposes known attributes' do - get api("/projects/#{project.id}/issues/#{issue.iid}/user_agent_detail", admin) + it 'exposes known attributes', :aggregate_failures do + get api("/projects/#{project.id}/issues/#{issue.iid}/user_agent_detail", admin, admin_mode: true) expect(response).to have_gitlab_http_status(:ok) expect(json_response['user_agent']).to eq(user_agent_detail.user_agent) @@ -936,7 +936,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do ) end - it 'returns a full list of participants' do + it 'returns a full list of participants', :aggregate_failures do get api("/projects/#{project.id}/issues/#{issue.iid}/participants", user) expect(response).to have_gitlab_http_status(:ok) @@ -945,7 +945,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do end context 'when user cannot see a confidential note' do - it 'returns a limited list of participants' do + it 'returns a limited list of participants', :aggregate_failures do get api("/projects/#{project.id}/issues/#{issue.iid}/participants", create(:user)) expect(response).to have_gitlab_http_status(:ok) diff --git a/spec/requests/api/issues/issues_spec.rb b/spec/requests/api/issues/issues_spec.rb index 078f00334c3..33f49cefc69 100644 --- a/spec/requests/api/issues/issues_spec.rb +++ b/spec/requests/api/issues/issues_spec.rb @@ -78,7 +78,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do end shared_examples 'issues statistics' do - it 'returns issues statistics' do + it 'returns issues statistics', :aggregate_failures do get api("/issues_statistics", user), params: params expect(response).to have_gitlab_http_status(:ok) @@ -109,8 +109,8 @@ RSpec.describe API::Issues, feature_category: :team_planning do context 'as an admin' do context 'when issue exists' do - it 'returns the issue' do - get api("/issues/#{issue.id}", admin) + it 'returns the issue', :aggregate_failures do + get api("/issues/#{issue.id}", admin, admin_mode: true) expect(response).to have_gitlab_http_status(:ok) expect(json_response.dig('author', 'id')).to eq(issue.author.id) @@ -121,7 +121,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do context 'when issue does not exist' do it 'returns 404' do - get api("/issues/0", admin) + get api("/issues/0", admin, admin_mode: true) expect(response).to have_gitlab_http_status(:not_found) end @@ -132,7 +132,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do describe 'GET /issues' do context 'when unauthenticated' do - it 'returns an array of all issues' do + it 'returns an array of all issues', :aggregate_failures do get api('/issues'), params: { scope: 'all' } expect(response).to have_gitlab_http_status(:ok) @@ -162,14 +162,14 @@ RSpec.describe API::Issues, feature_category: :team_planning do expect(response).to have_gitlab_http_status(:unauthorized) end - it 'returns an array of issues matching state in milestone' do + it 'returns an array of issues matching state in milestone', :aggregate_failures do get api('/issues'), params: { milestone: 'foo', scope: 'all' } expect(response).to have_gitlab_http_status(:ok) expect_paginated_array_response([]) end - it 'returns an array of issues matching state in milestone' do + it 'returns an array of issues matching state in milestone', :aggregate_failures do get api('/issues'), params: { milestone: milestone.title, scope: 'all' } expect(response).to have_gitlab_http_status(:ok) @@ -273,7 +273,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do end context 'when authenticated' do - it 'returns an array of issues' do + it 'returns an array of issues', :aggregate_failures do get api('/issues', user) expect_paginated_array_response([issue.id, closed_issue.id]) @@ -532,7 +532,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do context 'with incident issues' do let_it_be(:incident) { create(:incident, project: project) } - it 'avoids N+1 queries' do + it 'avoids N+1 queries', :aggregate_failures do get api('/issues', user) # warm up control = ActiveRecord::QueryRecorder.new do @@ -553,7 +553,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do context 'with issues closed as duplicates' do let_it_be(:dup_issue_1) { create(:issue, :closed_as_duplicate, project: project) } - it 'avoids N+1 queries' do + it 'avoids N+1 queries', :aggregate_failures do get api('/issues', user) # warm up control = ActiveRecord::QueryRecorder.new do @@ -639,7 +639,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do expect_paginated_array_response([]) end - it 'returns an array of labeled issues matching given state' do + it 'returns an array of labeled issues matching given state', :aggregate_failures do get api('/issues', user), params: { labels: label.title, state: :opened } expect_paginated_array_response(issue.id) @@ -647,7 +647,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do expect(json_response.first['state']).to eq('opened') end - it 'returns an array of labeled issues matching given state with labels param as array' do + it 'returns an array of labeled issues matching given state with labels param as array', :aggregate_failures do get api('/issues', user), params: { labels: [label.title], state: :opened } expect_paginated_array_response(issue.id) @@ -917,14 +917,14 @@ RSpec.describe API::Issues, feature_category: :team_planning do end end - it 'matches V4 response schema' do + it 'matches V4 response schema', :aggregate_failures do get api('/issues', user) expect(response).to have_gitlab_http_status(:ok) expect(response).to match_response_schema('public_api/v4/issues') end - it 'returns a related merge request count of 0 if there are no related merge requests' do + it 'returns a related merge request count of 0 if there are no related merge requests', :aggregate_failures do get api('/issues', user) expect(response).to have_gitlab_http_status(:ok) @@ -932,7 +932,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do expect(json_response.first).to include('merge_requests_count' => 0) end - it 'returns a related merge request count > 0 if there are related merge requests' do + it 'returns a related merge request count > 0 if there are related merge requests', :aggregate_failures do create(:merge_requests_closing_issues, issue: issue) get api('/issues', user) @@ -1013,28 +1013,28 @@ RSpec.describe API::Issues, feature_category: :team_planning do let!(:issue2) { create(:issue, author: user2, project: project, created_at: 2.days.ago) } let!(:issue3) { create(:issue, author: user2, assignees: [assignee, another_assignee], project: project, created_at: 1.day.ago) } - it 'returns issues with by assignee_username' do + it 'returns issues with by assignee_username', :aggregate_failures do get api("/issues", user), params: { assignee_username: [assignee.username], scope: 'all' } expect(issue3.reload.assignees.pluck(:id)).to match_array([assignee.id, another_assignee.id]) expect_paginated_array_response([confidential_issue.id, issue3.id]) end - it 'returns issues by assignee_username as string' do + it 'returns issues by assignee_username as string', :aggregate_failures do get api("/issues", user), params: { assignee_username: assignee.username, scope: 'all' } expect(issue3.reload.assignees.pluck(:id)).to match_array([assignee.id, another_assignee.id]) expect_paginated_array_response([confidential_issue.id, issue3.id]) end - it 'returns error when multiple assignees are passed' do + it 'returns error when multiple assignees are passed', :aggregate_failures do get api("/issues", user), params: { assignee_username: [assignee.username, another_assignee.username], scope: 'all' } expect(response).to have_gitlab_http_status(:bad_request) expect(json_response["error"]).to include("allows one value, but found 2") end - it 'returns error when assignee_username and assignee_id are passed together' do + it 'returns error when assignee_username and assignee_id are passed together', :aggregate_failures do get api("/issues", user), params: { assignee_username: [assignee.username], assignee_id: another_assignee.id, scope: 'all' } expect(response).to have_gitlab_http_status(:bad_request) @@ -1088,7 +1088,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do end describe 'GET /projects/:id/issues/:issue_iid' do - it 'exposes full reference path' do + it 'exposes full reference path', :aggregate_failures do get api("/projects/#{project.id}/issues/#{issue.iid}", user) expect(response).to have_gitlab_http_status(:ok) @@ -1106,7 +1106,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do end context 'user does not have permission to view new issue' do - it 'does not return the issue as closed_as_duplicate_of' do + it 'does not return the issue as closed_as_duplicate_of', :aggregate_failures do get api("/projects/#{project.id}/issues/#{issue_closed_as_dup.iid}", user) expect(response).to have_gitlab_http_status(:ok) @@ -1119,7 +1119,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do new_issue.project.add_guest(user) end - it 'returns the issue as closed_as_duplicate_of' do + it 'returns the issue as closed_as_duplicate_of', :aggregate_failures do get api("/projects/#{project.id}/issues/#{issue_closed_as_dup.iid}", user) expect(response).to have_gitlab_http_status(:ok) @@ -1131,7 +1131,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do end describe "POST /projects/:id/issues" do - it 'creates a new project issue' do + it 'creates a new project issue', :aggregate_failures do post api("/projects/#{project.id}/issues", user), params: { title: 'new issue' } expect(response).to have_gitlab_http_status(:created) @@ -1140,7 +1140,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do end context 'when confidential is null' do - it 'responds with 400 error' do + it 'responds with 400 error', :aggregate_failures do post api("/projects/#{project.id}/issues", user), params: { title: 'issue', confidential: nil } expect(response).to have_gitlab_http_status(:bad_request) @@ -1155,7 +1155,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do end end - it 'returns and error message and status code from the service' do + it 'returns and error message and status code from the service', :aggregate_failures do post api("/projects/#{project.id}/issues", user), params: { title: 'new issue' } expect(response).to have_gitlab_http_status(:forbidden) @@ -1177,15 +1177,15 @@ RSpec.describe API::Issues, feature_category: :team_planning do travel_to fixed_time end - it 'allows admins to set the timestamp' do - put api("/projects/#{project.id}/issues/#{issue.iid}", admin), params: { labels: 'label1', updated_at: updated_at } + it 'allows admins to set the timestamp', :aggregate_failures do + put api("/projects/#{project.id}/issues/#{issue.iid}", admin, admin_mode: true), params: { labels: 'label1', updated_at: updated_at } expect(response).to have_gitlab_http_status(:ok) expect(Time.parse(json_response['updated_at'])).to be_like_time(updated_at) expect(ResourceLabelEvent.last.created_at).to be_like_time(updated_at) end - it 'does not allow other users to set the timestamp' do + it 'does not allow other users to set the timestamp', :aggregate_failures do reporter = create(:user) project.add_developer(reporter) @@ -1268,7 +1268,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do end context 'with valid params' do - it 'reorders issues and returns a successful 200 response' do + it 'reorders issues and returns a successful 200 response', :aggregate_failures do put api("/projects/#{project.id}/issues/#{issue1.iid}/reorder", user), params: { move_after_id: issue2.id, move_before_id: issue3.id } expect(response).to have_gitlab_http_status(:ok) @@ -1295,7 +1295,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do let(:other_project) { create(:project, group: group) } let(:other_issue) { create(:issue, project: other_project, relative_position: 80) } - it 'reorders issues and returns a successful 200 response' do + it 'reorders issues and returns a successful 200 response', :aggregate_failures do put api("/projects/#{other_project.id}/issues/#{other_issue.iid}/reorder", user), params: { move_after_id: issue2.id, move_before_id: issue3.id } expect(response).to have_gitlab_http_status(:ok) diff --git a/spec/requests/api/issues/post_projects_issues_spec.rb b/spec/requests/api/issues/post_projects_issues_spec.rb index 265091fa698..a17c1389e83 100644 --- a/spec/requests/api/issues/post_projects_issues_spec.rb +++ b/spec/requests/api/issues/post_projects_issues_spec.rb @@ -75,7 +75,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do describe 'POST /projects/:id/issues' do context 'support for deprecated assignee_id' do - it 'creates a new project issue' do + it 'creates a new project issue', :aggregate_failures do post api("/projects/#{project.id}/issues", user), params: { title: 'new issue', assignee_id: user2.id } @@ -85,7 +85,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do expect(json_response['assignees'].first['name']).to eq(user2.name) end - it 'creates a new project issue when assignee_id is empty' do + it 'creates a new project issue when assignee_id is empty', :aggregate_failures do post api("/projects/#{project.id}/issues", user), params: { title: 'new issue', assignee_id: '' } @@ -96,7 +96,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do end context 'single assignee restrictions' do - it 'creates a new project issue with no more than one assignee' do + it 'creates a new project issue with no more than one assignee', :aggregate_failures do post api("/projects/#{project.id}/issues", user), params: { title: 'new issue', assignee_ids: [user2.id, guest.id] } @@ -122,8 +122,8 @@ RSpec.describe API::Issues, feature_category: :team_planning do context 'an internal ID is provided' do context 'by an admin' do - it 'sets the internal ID on the new issue' do - post api("/projects/#{project.id}/issues", admin), + it 'sets the internal ID on the new issue', :aggregate_failures do + post api("/projects/#{project.id}/issues", admin, admin_mode: true), params: { title: 'new issue', iid: 9001 } expect(response).to have_gitlab_http_status(:created) @@ -132,7 +132,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do end context 'by an owner' do - it 'sets the internal ID on the new issue' do + it 'sets the internal ID on the new issue', :aggregate_failures do post api("/projects/#{project.id}/issues", user), params: { title: 'new issue', iid: 9001 } @@ -145,7 +145,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do let(:group) { create(:group) } let(:group_project) { create(:project, :public, namespace: group) } - it 'sets the internal ID on the new issue' do + it 'sets the internal ID on the new issue', :aggregate_failures do group.add_owner(user2) post api("/projects/#{group_project.id}/issues", user2), params: { title: 'new issue', iid: 9001 } @@ -156,7 +156,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do end context 'by another user' do - it 'ignores the given internal ID' do + it 'ignores the given internal ID', :aggregate_failures do post api("/projects/#{project.id}/issues", user2), params: { title: 'new issue', iid: 9001 } @@ -166,8 +166,8 @@ RSpec.describe API::Issues, feature_category: :team_planning do end context 'when an issue with the same IID exists on database' do - it 'returns 409' do - post api("/projects/#{project.id}/issues", admin), + it 'returns 409', :aggregate_failures do + post api("/projects/#{project.id}/issues", admin, admin_mode: true), params: { title: 'new issue', iid: issue.iid } expect(response).to have_gitlab_http_status(:conflict) @@ -176,7 +176,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do end end - it 'creates a new project issue' do + it 'creates a new project issue', :aggregate_failures do post api("/projects/#{project.id}/issues", user), params: { title: 'new issue', labels: 'label, label2', weight: 3, assignee_ids: [user2.id] } @@ -189,7 +189,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do expect(json_response['assignees'].first['name']).to eq(user2.name) end - it 'creates a new project issue with labels param as array' do + it 'creates a new project issue with labels param as array', :aggregate_failures do post api("/projects/#{project.id}/issues", user), params: { title: 'new issue', labels: %w(label label2), weight: 3, assignee_ids: [user2.id] } @@ -202,7 +202,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do expect(json_response['assignees'].first['name']).to eq(user2.name) end - it 'creates a new confidential project issue' do + it 'creates a new confidential project issue', :aggregate_failures do post api("/projects/#{project.id}/issues", user), params: { title: 'new issue', confidential: true } @@ -211,7 +211,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do expect(json_response['confidential']).to be_truthy end - it 'creates a new confidential project issue with a different param' do + it 'creates a new confidential project issue with a different param', :aggregate_failures do post api("/projects/#{project.id}/issues", user), params: { title: 'new issue', confidential: 'y' } @@ -220,7 +220,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do expect(json_response['confidential']).to be_truthy end - it 'creates a public issue when confidential param is false' do + it 'creates a public issue when confidential param is false', :aggregate_failures do post api("/projects/#{project.id}/issues", user), params: { title: 'new issue', confidential: false } @@ -229,7 +229,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do expect(json_response['confidential']).to be_falsy end - it 'creates a public issue when confidential param is invalid' do + it 'creates a public issue when confidential param is invalid', :aggregate_failures do post api("/projects/#{project.id}/issues", user), params: { title: 'new issue', confidential: 'foo' } @@ -242,7 +242,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do expect(response).to have_gitlab_http_status(:bad_request) end - it 'allows special label names' do + it 'allows special label names', :aggregate_failures do post api("/projects/#{project.id}/issues", user), params: { title: 'new issue', @@ -256,7 +256,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do expect(json_response['labels']).to include '&' end - it 'allows special label names with labels param as array' do + it 'allows special label names with labels param as array', :aggregate_failures do post api("/projects/#{project.id}/issues", user), params: { title: 'new issue', @@ -270,7 +270,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do expect(json_response['labels']).to include '&' end - it 'returns 400 if title is too long' do + it 'returns 400 if title is too long', :aggregate_failures do post api("/projects/#{project.id}/issues", user), params: { title: 'g' * 256 } expect(response).to have_gitlab_http_status(:bad_request) @@ -313,7 +313,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do end context 'with due date' do - it 'creates a new project issue' do + it 'creates a new project issue', :aggregate_failures do due_date = 2.weeks.from_now.strftime('%Y-%m-%d') post api("/projects/#{project.id}/issues", user), @@ -336,8 +336,8 @@ RSpec.describe API::Issues, feature_category: :team_planning do end context 'by an admin' do - it 'sets the creation time on the new issue' do - post api("/projects/#{project.id}/issues", admin), params: params + it 'sets the creation time on the new issue', :aggregate_failures do + post api("/projects/#{project.id}/issues", admin, admin_mode: true), params: params expect(response).to have_gitlab_http_status(:created) expect(Time.parse(json_response['created_at'])).to be_like_time(creation_time) @@ -346,7 +346,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do end context 'by a project owner' do - it 'sets the creation time on the new issue' do + it 'sets the creation time on the new issue', :aggregate_failures do post api("/projects/#{project.id}/issues", user), params: params expect(response).to have_gitlab_http_status(:created) @@ -356,7 +356,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do end context 'by a group owner' do - it 'sets the creation time on the new issue' do + it 'sets the creation time on the new issue', :aggregate_failures do group = create(:group) group_project = create(:project, :public, namespace: group) group.add_owner(user2) @@ -370,7 +370,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do end context 'by another user' do - it 'ignores the given creation time' do + it 'ignores the given creation time', :aggregate_failures do project.add_developer(user2) post api("/projects/#{project.id}/issues", user2), params: params @@ -397,7 +397,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do end context 'when request exceeds the rate limit' do - it 'prevents users from creating more issues' do + it 'prevents users from creating more issues', :aggregate_failures do allow(::Gitlab::ApplicationRateLimiter).to receive(:throttled?).and_return(true) post api("/projects/#{project.id}/issues", user), @@ -437,7 +437,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do expect { post_issue }.not_to change(Issue, :count) end - it 'returns correct status and message' do + it 'returns correct status and message', :aggregate_failures do post_issue expect(response).to have_gitlab_http_status(:bad_request) @@ -476,7 +476,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do let!(:target_project) { create(:project, creator_id: user.id, namespace: user.namespace) } let!(:target_project2) { create(:project, creator_id: non_member.id, namespace: non_member.namespace) } - it 'moves an issue' do + it 'moves an issue', :aggregate_failures do post api("/projects/#{project.id}/issues/#{issue.iid}/move", user), params: { to_project_id: target_project.id } @@ -485,7 +485,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do end context 'when source and target projects are the same' do - it 'returns 400 when trying to move an issue' do + it 'returns 400 when trying to move an issue', :aggregate_failures do post api("/projects/#{project.id}/issues/#{issue.iid}/move", user), params: { to_project_id: project.id } @@ -495,7 +495,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do end context 'when the user does not have the permission to move issues' do - it 'returns 400 when trying to move an issue' do + it 'returns 400 when trying to move an issue', :aggregate_failures do post api("/projects/#{project.id}/issues/#{issue.iid}/move", user), params: { to_project_id: target_project2.id } @@ -504,8 +504,8 @@ RSpec.describe API::Issues, feature_category: :team_planning do end end - it 'moves the issue to another namespace if I am admin' do - post api("/projects/#{project.id}/issues/#{issue.iid}/move", admin), + it 'moves the issue to another namespace if I am admin', :aggregate_failures do + post api("/projects/#{project.id}/issues/#{issue.iid}/move", admin, admin_mode: true), params: { to_project_id: target_project2.id } expect(response).to have_gitlab_http_status(:created) @@ -513,7 +513,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do end context 'when using the issue ID instead of iid' do - it 'returns 404 when trying to move an issue', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/341520' do + it 'returns 404 when trying to move an issue', :aggregate_failures, quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/341520' do post api("/projects/#{project.id}/issues/#{issue.id}/move", user), params: { to_project_id: target_project.id } @@ -523,7 +523,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do end context 'when issue does not exist' do - it 'returns 404 when trying to move an issue' do + it 'returns 404 when trying to move an issue', :aggregate_failures do post api("/projects/#{project.id}/issues/123/move", user), params: { to_project_id: target_project.id } @@ -533,7 +533,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do end context 'when source project does not exist' do - it 'returns 404 when trying to move an issue' do + it 'returns 404 when trying to move an issue', :aggregate_failures do post api("/projects/0/issues/#{issue.iid}/move", user), params: { to_project_id: target_project.id } @@ -562,7 +562,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do context 'when user can admin the issue' do context 'when the user can admin the target project' do - it 'clones the issue' do + it 'clones the issue', :aggregate_failures do expect do post_clone_issue(user, issue, valid_target_project) end.to change { valid_target_project.issues.count }.by(1) @@ -577,7 +577,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do end context 'when target project is the same source project' do - it 'clones the issue' do + it 'clones the issue', :aggregate_failures do expect do post_clone_issue(user, issue, issue.project) end.to change { issue.reset.project.issues.count }.by(1) @@ -595,7 +595,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do end context 'when the user does not have the permission to clone issues' do - it 'returns 400' do + it 'returns 400', :aggregate_failures do post api("/projects/#{project.id}/issues/#{issue.iid}/clone", user), params: { to_project_id: invalid_target_project.id } @@ -605,7 +605,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do end context 'when using the issue ID instead of iid' do - it 'returns 404', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/341520' do + it 'returns 404', :aggregate_failures, quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/341520' do post api("/projects/#{project.id}/issues/#{issue.id}/clone", user), params: { to_project_id: valid_target_project.id } @@ -615,7 +615,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do end context 'when issue does not exist' do - it 'returns 404' do + it 'returns 404', :aggregate_failures do post api("/projects/#{project.id}/issues/12300/clone", user), params: { to_project_id: valid_target_project.id } @@ -625,7 +625,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do end context 'when source project does not exist' do - it 'returns 404' do + it 'returns 404', :aggregate_failures do post api("/projects/0/issues/#{issue.iid}/clone", user), params: { to_project_id: valid_target_project.id } @@ -635,7 +635,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do end context 'when target project does not exist' do - it 'returns 404' do + it 'returns 404', :aggregate_failures do post api("/projects/#{project.id}/issues/#{issue.iid}/clone", user), params: { to_project_id: 0 } @@ -644,7 +644,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do end end - it 'clones the issue with notes when with_notes is true' do + it 'clones the issue with notes when with_notes is true', :aggregate_failures do expect do post api("/projects/#{project.id}/issues/#{issue.iid}/clone", user), params: { to_project_id: valid_target_project.id, with_notes: true } @@ -661,7 +661,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do end describe 'POST :id/issues/:issue_iid/subscribe' do - it 'subscribes to an issue' do + it 'subscribes to an issue', :aggregate_failures do post api("/projects/#{project.id}/issues/#{issue.iid}/subscribe", user2) expect(response).to have_gitlab_http_status(:created) @@ -694,7 +694,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do end describe 'POST :id/issues/:issue_id/unsubscribe' do - it 'unsubscribes from an issue' do + it 'unsubscribes from an issue', :aggregate_failures do post api("/projects/#{project.id}/issues/#{issue.iid}/unsubscribe", user) expect(response).to have_gitlab_http_status(:created) diff --git a/spec/requests/api/issues/put_projects_issues_spec.rb b/spec/requests/api/issues/put_projects_issues_spec.rb index f0d174c9e78..6cc639c0bcc 100644 --- a/spec/requests/api/issues/put_projects_issues_spec.rb +++ b/spec/requests/api/issues/put_projects_issues_spec.rb @@ -80,7 +80,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do end describe 'PUT /projects/:id/issues/:issue_iid to update only title' do - it 'updates a project issue' do + it 'updates a project issue', :aggregate_failures do put api_for_user, params: { title: updated_title } expect(response).to have_gitlab_http_status(:ok) @@ -109,7 +109,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do expect(response).to have_gitlab_http_status(:ok) end - it 'allows special label names with labels param as array' do + it 'allows special label names with labels param as array', :aggregate_failures do put api_for_user, params: { title: updated_title, @@ -135,42 +135,42 @@ RSpec.describe API::Issues, feature_category: :team_planning do expect(response).to have_gitlab_http_status(:forbidden) end - it 'updates a confidential issue for project members' do + it 'updates a confidential issue for project members', :aggregate_failures do put api(confidential_issue_path, user), params: { title: updated_title } expect(response).to have_gitlab_http_status(:ok) expect(json_response['title']).to eq(updated_title) end - it 'updates a confidential issue for author' do + it 'updates a confidential issue for author', :aggregate_failures do put api(confidential_issue_path, author), params: { title: updated_title } expect(response).to have_gitlab_http_status(:ok) expect(json_response['title']).to eq(updated_title) end - it 'updates a confidential issue for admin' do - put api(confidential_issue_path, admin), params: { title: updated_title } + it 'updates a confidential issue for admin', :aggregate_failures do + put api(confidential_issue_path, admin, admin_mode: true), params: { title: updated_title } expect(response).to have_gitlab_http_status(:ok) expect(json_response['title']).to eq(updated_title) end - it 'sets an issue to confidential' do + it 'sets an issue to confidential', :aggregate_failures do put api_for_user, params: { confidential: true } expect(response).to have_gitlab_http_status(:ok) expect(json_response['confidential']).to be_truthy end - it 'makes a confidential issue public' do + it 'makes a confidential issue public', :aggregate_failures do put api(confidential_issue_path, user), params: { confidential: false } expect(response).to have_gitlab_http_status(:ok) expect(json_response['confidential']).to be_falsy end - it 'does not update a confidential issue with wrong confidential flag' do + it 'does not update a confidential issue with wrong confidential flag', :aggregate_failures do put api(confidential_issue_path, user), params: { confidential: 'foo' } expect(response).to have_gitlab_http_status(:bad_request) @@ -209,7 +209,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do expect { update_issue }.not_to change { issue.reload.title } end - it 'returns correct status and message' do + it 'returns correct status and message', :aggregate_failures do update_issue expect(response).to have_gitlab_http_status(:bad_request) @@ -246,14 +246,14 @@ RSpec.describe API::Issues, feature_category: :team_planning do describe 'PUT /projects/:id/issues/:issue_iid to update assignee' do context 'support for deprecated assignee_id' do - it 'removes assignee' do + it 'removes assignee', :aggregate_failures do put api_for_user, params: { assignee_id: 0 } expect(response).to have_gitlab_http_status(:ok) expect(json_response['assignee']).to be_nil end - it 'updates an issue with new assignee' do + it 'updates an issue with new assignee', :aggregate_failures do put api_for_user, params: { assignee_id: user2.id } expect(response).to have_gitlab_http_status(:ok) @@ -261,21 +261,21 @@ RSpec.describe API::Issues, feature_category: :team_planning do end end - it 'removes assignee' do + it 'removes assignee', :aggregate_failures do put api_for_user, params: { assignee_ids: [0] } expect(response).to have_gitlab_http_status(:ok) expect(json_response['assignees']).to be_empty end - it 'updates an issue with new assignee' do + it 'updates an issue with new assignee', :aggregate_failures do put api_for_user, params: { assignee_ids: [user2.id] } expect(response).to have_gitlab_http_status(:ok) expect(json_response['assignees'].first['name']).to eq(user2.name) end - context 'single assignee restrictions' do + context 'single assignee restrictions', :aggregate_failures do it 'updates an issue with several assignees but only one has been applied' do put api_for_user, params: { assignee_ids: [user2.id, guest.id] } @@ -289,7 +289,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do let!(:label) { create(:label, title: 'dummy', project: project) } let!(:label_link) { create(:label_link, label: label, target: issue) } - it 'adds relevant labels' do + it 'adds relevant labels', :aggregate_failures do put api_for_user, params: { add_labels: '1, 2' } expect(response).to have_gitlab_http_status(:ok) @@ -300,14 +300,14 @@ RSpec.describe API::Issues, feature_category: :team_planning do let!(:label2) { create(:label, title: 'a-label', project: project) } let!(:label_link2) { create(:label_link, label: label2, target: issue) } - it 'removes relevant labels' do + it 'removes relevant labels', :aggregate_failures do put api_for_user, params: { remove_labels: label2.title } expect(response).to have_gitlab_http_status(:ok) expect(json_response['labels']).to eq([label.title]) end - it 'removes all labels' do + it 'removes all labels', :aggregate_failures do put api_for_user, params: { remove_labels: "#{label.title}, #{label2.title}" } expect(response).to have_gitlab_http_status(:ok) @@ -315,14 +315,14 @@ RSpec.describe API::Issues, feature_category: :team_planning do end end - it 'does not update labels if not present' do + it 'does not update labels if not present', :aggregate_failures do put api_for_user, params: { title: updated_title } expect(response).to have_gitlab_http_status(:ok) expect(json_response['labels']).to eq([label.title]) end - it 'removes all labels and touches the record' do + it 'removes all labels and touches the record', :aggregate_failures do travel_to(2.minutes.from_now) do put api_for_user, params: { labels: '' } end @@ -332,7 +332,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do expect(json_response['updated_at']).to be > Time.current end - it 'removes all labels and touches the record with labels param as array' do + it 'removes all labels and touches the record with labels param as array', :aggregate_failures do travel_to(2.minutes.from_now) do put api_for_user, params: { labels: [''] } end @@ -342,7 +342,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do expect(json_response['updated_at']).to be > Time.current end - it 'updates labels and touches the record' do + it 'updates labels and touches the record', :aggregate_failures do travel_to(2.minutes.from_now) do put api_for_user, params: { labels: 'foo,bar' } end @@ -352,7 +352,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do expect(json_response['updated_at']).to be > Time.current end - it 'updates labels and touches the record with labels param as array' do + it 'updates labels and touches the record with labels param as array', :aggregate_failures do travel_to(2.minutes.from_now) do put api_for_user, params: { labels: %w(foo bar) } end @@ -363,21 +363,21 @@ RSpec.describe API::Issues, feature_category: :team_planning do expect(json_response['updated_at']).to be > Time.current end - it 'allows special label names' do + it 'allows special label names', :aggregate_failures do put api_for_user, params: { labels: 'label:foo, label-bar,label_bar,label/bar,label?bar,label&bar,?,&' } expect(response).to have_gitlab_http_status(:ok) expect(json_response['labels']).to contain_exactly('label:foo', 'label-bar', 'label_bar', 'label/bar', 'label?bar', 'label&bar', '?', '&') end - it 'allows special label names with labels param as array' do + it 'allows special label names with labels param as array', :aggregate_failures do put api_for_user, params: { labels: ['label:foo', 'label-bar', 'label_bar', 'label/bar,label?bar,label&bar,?,&'] } expect(response).to have_gitlab_http_status(:ok) expect(json_response['labels']).to contain_exactly('label:foo', 'label-bar', 'label_bar', 'label/bar', 'label?bar', 'label&bar', '?', '&') end - it 'returns 400 if title is too long' do + it 'returns 400 if title is too long', :aggregate_failures do put api_for_user, params: { title: 'g' * 256 } expect(response).to have_gitlab_http_status(:bad_request) @@ -386,7 +386,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do end describe 'PUT /projects/:id/issues/:issue_iid to update state and label' do - it 'updates a project issue' do + it 'updates a project issue', :aggregate_failures do put api_for_user, params: { labels: 'label2', state_event: 'close' } expect(response).to have_gitlab_http_status(:ok) @@ -394,7 +394,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do expect(json_response['state']).to eq 'closed' end - it 'reopens a project isssue' do + it 'reopens a project isssue', :aggregate_failures do put api(issue_path, user), params: { state_event: 'reopen' } expect(response).to have_gitlab_http_status(:ok) @@ -404,7 +404,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do describe 'PUT /projects/:id/issues/:issue_iid to update updated_at param' do context 'when reporter makes request' do - it 'accepts the update date to be set' do + it 'accepts the update date to be set', :aggregate_failures do update_time = 2.weeks.ago put api_for_user, params: { title: 'some new title', updated_at: update_time } @@ -436,7 +436,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do expect(response).to have_gitlab_http_status(:bad_request) end - it 'accepts the update date to be set' do + it 'accepts the update date to be set', :aggregate_failures do update_time = 2.weeks.ago put api_for_owner, params: { title: 'some new title', updated_at: update_time } @@ -448,7 +448,7 @@ RSpec.describe API::Issues, feature_category: :team_planning do end describe 'PUT /projects/:id/issues/:issue_iid to update due date' do - it 'creates a new project issue' do + it 'creates a new project issue', :aggregate_failures do due_date = 2.weeks.from_now.strftime('%Y-%m-%d') put api_for_user, params: { due_date: due_date } diff --git a/spec/requests/api/pages/internal_access_spec.rb b/spec/requests/api/pages/internal_access_spec.rb index fdc25ecdcd3..3e7837866ae 100644 --- a/spec/requests/api/pages/internal_access_spec.rb +++ b/spec/requests/api/pages/internal_access_spec.rb @@ -35,39 +35,39 @@ RSpec.describe "Internal Project Pages Access", feature_category: :pages do describe "GET /projects/:id/pages_access" do context 'access depends on the level' do - where(:pages_access_level, :with_user, :expected_result) do - ProjectFeature::DISABLED | "admin" | 403 - ProjectFeature::DISABLED | "owner" | 403 - ProjectFeature::DISABLED | "master" | 403 - ProjectFeature::DISABLED | "developer" | 403 - ProjectFeature::DISABLED | "reporter" | 403 - ProjectFeature::DISABLED | "guest" | 403 - ProjectFeature::DISABLED | "user" | 403 - ProjectFeature::DISABLED | nil | 404 - ProjectFeature::PUBLIC | "admin" | 200 - ProjectFeature::PUBLIC | "owner" | 200 - ProjectFeature::PUBLIC | "master" | 200 - ProjectFeature::PUBLIC | "developer" | 200 - ProjectFeature::PUBLIC | "reporter" | 200 - ProjectFeature::PUBLIC | "guest" | 200 - ProjectFeature::PUBLIC | "user" | 200 - ProjectFeature::PUBLIC | nil | 404 - ProjectFeature::ENABLED | "admin" | 200 - ProjectFeature::ENABLED | "owner" | 200 - ProjectFeature::ENABLED | "master" | 200 - ProjectFeature::ENABLED | "developer" | 200 - ProjectFeature::ENABLED | "reporter" | 200 - ProjectFeature::ENABLED | "guest" | 200 - ProjectFeature::ENABLED | "user" | 200 - ProjectFeature::ENABLED | nil | 404 - ProjectFeature::PRIVATE | "admin" | 200 - ProjectFeature::PRIVATE | "owner" | 200 - ProjectFeature::PRIVATE | "master" | 200 - ProjectFeature::PRIVATE | "developer" | 200 - ProjectFeature::PRIVATE | "reporter" | 200 - ProjectFeature::PRIVATE | "guest" | 200 - ProjectFeature::PRIVATE | "user" | 403 - ProjectFeature::PRIVATE | nil | 404 + where(:pages_access_level, :with_user, :admin_mode, :expected_result) do + ProjectFeature::DISABLED | "admin" | true | 403 + ProjectFeature::DISABLED | "owner" | false | 403 + ProjectFeature::DISABLED | "master" | false | 403 + ProjectFeature::DISABLED | "developer" | false | 403 + ProjectFeature::DISABLED | "reporter" | false | 403 + ProjectFeature::DISABLED | "guest" | false | 403 + ProjectFeature::DISABLED | "user" | false | 403 + ProjectFeature::DISABLED | nil | false | 404 + ProjectFeature::PUBLIC | "admin" | false | 200 + ProjectFeature::PUBLIC | "owner" | false | 200 + ProjectFeature::PUBLIC | "master" | false | 200 + ProjectFeature::PUBLIC | "developer" | false | 200 + ProjectFeature::PUBLIC | "reporter" | false | 200 + ProjectFeature::PUBLIC | "guest" | false | 200 + ProjectFeature::PUBLIC | "user" | false | 200 + ProjectFeature::PUBLIC | nil | false | 404 + ProjectFeature::ENABLED | "admin" | false | 200 + ProjectFeature::ENABLED | "owner" | false | 200 + ProjectFeature::ENABLED | "master" | false | 200 + ProjectFeature::ENABLED | "developer" | false | 200 + ProjectFeature::ENABLED | "reporter" | false | 200 + ProjectFeature::ENABLED | "guest" | false | 200 + ProjectFeature::ENABLED | "user" | false | 200 + ProjectFeature::ENABLED | nil | false | 404 + ProjectFeature::PRIVATE | "admin" | true | 200 + ProjectFeature::PRIVATE | "owner" | false | 200 + ProjectFeature::PRIVATE | "master" | false | 200 + ProjectFeature::PRIVATE | "developer" | false | 200 + ProjectFeature::PRIVATE | "reporter" | false | 200 + ProjectFeature::PRIVATE | "guest" | false | 200 + ProjectFeature::PRIVATE | "user" | false | 403 + ProjectFeature::PRIVATE | nil | false | 404 end with_them do @@ -77,7 +77,7 @@ RSpec.describe "Internal Project Pages Access", feature_category: :pages do it "correct return value" do if !with_user.nil? user = public_send(with_user) - get api("/projects/#{project.id}/pages_access", user) + get api("/projects/#{project.id}/pages_access", user, admin_mode: admin_mode) else get api("/projects/#{project.id}/pages_access") end diff --git a/spec/requests/api/pages/pages_spec.rb b/spec/requests/api/pages/pages_spec.rb index c426f2a433c..0f6675799ad 100644 --- a/spec/requests/api/pages/pages_spec.rb +++ b/spec/requests/api/pages/pages_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' RSpec.describe API::Pages, feature_category: :pages do - let_it_be(:project) { create(:project, path: 'my.project', pages_https_only: false) } + let_it_be_with_reload(:project) { create(:project, path: 'my.project', pages_https_only: false) } let_it_be(:admin) { create(:admin) } let_it_be(:user) { create(:user) } @@ -19,7 +19,7 @@ RSpec.describe API::Pages, feature_category: :pages do end it_behaves_like '404 response' do - let(:request) { delete api("/projects/#{project.id}/pages", admin) } + let(:request) { delete api("/projects/#{project.id}/pages", admin, admin_mode: true) } end end @@ -30,13 +30,13 @@ RSpec.describe API::Pages, feature_category: :pages do context 'when Pages are deployed' do it 'returns 204' do - delete api("/projects/#{project.id}/pages", admin) + delete api("/projects/#{project.id}/pages", admin, admin_mode: true) expect(response).to have_gitlab_http_status(:no_content) end it 'removes the pages' do - delete api("/projects/#{project.id}/pages", admin) + delete api("/projects/#{project.id}/pages", admin, admin_mode: true) expect(project.reload.pages_metadatum.deployed?).to be(false) end @@ -48,7 +48,7 @@ RSpec.describe API::Pages, feature_category: :pages do end it 'returns 204' do - delete api("/projects/#{project.id}/pages", admin) + delete api("/projects/#{project.id}/pages", admin, admin_mode: true) expect(response).to have_gitlab_http_status(:no_content) end @@ -58,7 +58,7 @@ RSpec.describe API::Pages, feature_category: :pages do it 'returns 404' do id = -1 - delete api("/projects/#{id}/pages", admin) + delete api("/projects/#{id}/pages", admin, admin_mode: true) expect(response).to have_gitlab_http_status(:not_found) end diff --git a/spec/requests/api/pages/private_access_spec.rb b/spec/requests/api/pages/private_access_spec.rb index 5cc1b8f9a69..602eff73b0a 100644 --- a/spec/requests/api/pages/private_access_spec.rb +++ b/spec/requests/api/pages/private_access_spec.rb @@ -35,39 +35,39 @@ RSpec.describe "Private Project Pages Access", feature_category: :pages do describe "GET /projects/:id/pages_access" do context 'access depends on the level' do - where(:pages_access_level, :with_user, :expected_result) do - ProjectFeature::DISABLED | "admin" | 403 - ProjectFeature::DISABLED | "owner" | 403 - ProjectFeature::DISABLED | "master" | 403 - ProjectFeature::DISABLED | "developer" | 403 - ProjectFeature::DISABLED | "reporter" | 403 - ProjectFeature::DISABLED | "guest" | 403 - ProjectFeature::DISABLED | "user" | 404 - ProjectFeature::DISABLED | nil | 404 - ProjectFeature::PUBLIC | "admin" | 200 - ProjectFeature::PUBLIC | "owner" | 200 - ProjectFeature::PUBLIC | "master" | 200 - ProjectFeature::PUBLIC | "developer" | 200 - ProjectFeature::PUBLIC | "reporter" | 200 - ProjectFeature::PUBLIC | "guest" | 200 - ProjectFeature::PUBLIC | "user" | 404 - ProjectFeature::PUBLIC | nil | 404 - ProjectFeature::ENABLED | "admin" | 200 - ProjectFeature::ENABLED | "owner" | 200 - ProjectFeature::ENABLED | "master" | 200 - ProjectFeature::ENABLED | "developer" | 200 - ProjectFeature::ENABLED | "reporter" | 200 - ProjectFeature::ENABLED | "guest" | 200 - ProjectFeature::ENABLED | "user" | 404 - ProjectFeature::ENABLED | nil | 404 - ProjectFeature::PRIVATE | "admin" | 200 - ProjectFeature::PRIVATE | "owner" | 200 - ProjectFeature::PRIVATE | "master" | 200 - ProjectFeature::PRIVATE | "developer" | 200 - ProjectFeature::PRIVATE | "reporter" | 200 - ProjectFeature::PRIVATE | "guest" | 200 - ProjectFeature::PRIVATE | "user" | 404 - ProjectFeature::PRIVATE | nil | 404 + where(:pages_access_level, :with_user, :admin_mode, :expected_result) do + ProjectFeature::DISABLED | "admin" | true | 403 + ProjectFeature::DISABLED | "owner" | false | 403 + ProjectFeature::DISABLED | "master" | false | 403 + ProjectFeature::DISABLED | "developer" | false | 403 + ProjectFeature::DISABLED | "reporter" | false | 403 + ProjectFeature::DISABLED | "guest" | false | 403 + ProjectFeature::DISABLED | "user" | false | 404 + ProjectFeature::DISABLED | nil | false | 404 + ProjectFeature::PUBLIC | "admin" | true | 200 + ProjectFeature::PUBLIC | "owner" | false | 200 + ProjectFeature::PUBLIC | "master" | false | 200 + ProjectFeature::PUBLIC | "developer" | false | 200 + ProjectFeature::PUBLIC | "reporter" | false | 200 + ProjectFeature::PUBLIC | "guest" | false | 200 + ProjectFeature::PUBLIC | "user" | false | 404 + ProjectFeature::PUBLIC | nil | false | 404 + ProjectFeature::ENABLED | "admin" | true | 200 + ProjectFeature::ENABLED | "owner" | false | 200 + ProjectFeature::ENABLED | "master" | false | 200 + ProjectFeature::ENABLED | "developer" | false | 200 + ProjectFeature::ENABLED | "reporter" | false | 200 + ProjectFeature::ENABLED | "guest" | false | 200 + ProjectFeature::ENABLED | "user" | false | 404 + ProjectFeature::ENABLED | nil | false | 404 + ProjectFeature::PRIVATE | "admin" | true | 200 + ProjectFeature::PRIVATE | "owner" | false | 200 + ProjectFeature::PRIVATE | "master" | false | 200 + ProjectFeature::PRIVATE | "developer" | false | 200 + ProjectFeature::PRIVATE | "reporter" | false | 200 + ProjectFeature::PRIVATE | "guest" | false | 200 + ProjectFeature::PRIVATE | "user" | false | 404 + ProjectFeature::PRIVATE | nil | false | 404 end with_them do @@ -77,7 +77,7 @@ RSpec.describe "Private Project Pages Access", feature_category: :pages do it "correct return value" do if !with_user.nil? user = public_send(with_user) - get api("/projects/#{project.id}/pages_access", user) + get api("/projects/#{project.id}/pages_access", user, admin_mode: admin_mode) else get api("/projects/#{project.id}/pages_access") end diff --git a/spec/requests/api/pages/public_access_spec.rb b/spec/requests/api/pages/public_access_spec.rb index 1137f91f4b0..8b0ed7c59ab 100644 --- a/spec/requests/api/pages/public_access_spec.rb +++ b/spec/requests/api/pages/public_access_spec.rb @@ -35,39 +35,39 @@ RSpec.describe "Public Project Pages Access", feature_category: :pages do describe "GET /projects/:id/pages_access" do context 'access depends on the level' do - where(:pages_access_level, :with_user, :expected_result) do - ProjectFeature::DISABLED | "admin" | 403 - ProjectFeature::DISABLED | "owner" | 403 - ProjectFeature::DISABLED | "master" | 403 - ProjectFeature::DISABLED | "developer" | 403 - ProjectFeature::DISABLED | "reporter" | 403 - ProjectFeature::DISABLED | "guest" | 403 - ProjectFeature::DISABLED | "user" | 403 - ProjectFeature::DISABLED | nil | 403 - ProjectFeature::PUBLIC | "admin" | 200 - ProjectFeature::PUBLIC | "owner" | 200 - ProjectFeature::PUBLIC | "master" | 200 - ProjectFeature::PUBLIC | "developer" | 200 - ProjectFeature::PUBLIC | "reporter" | 200 - ProjectFeature::PUBLIC | "guest" | 200 - ProjectFeature::PUBLIC | "user" | 200 - ProjectFeature::PUBLIC | nil | 200 - ProjectFeature::ENABLED | "admin" | 200 - ProjectFeature::ENABLED | "owner" | 200 - ProjectFeature::ENABLED | "master" | 200 - ProjectFeature::ENABLED | "developer" | 200 - ProjectFeature::ENABLED | "reporter" | 200 - ProjectFeature::ENABLED | "guest" | 200 - ProjectFeature::ENABLED | "user" | 200 - ProjectFeature::ENABLED | nil | 200 - ProjectFeature::PRIVATE | "admin" | 200 - ProjectFeature::PRIVATE | "owner" | 200 - ProjectFeature::PRIVATE | "master" | 200 - ProjectFeature::PRIVATE | "developer" | 200 - ProjectFeature::PRIVATE | "reporter" | 200 - ProjectFeature::PRIVATE | "guest" | 200 - ProjectFeature::PRIVATE | "user" | 403 - ProjectFeature::PRIVATE | nil | 403 + where(:pages_access_level, :with_user, :admin_mode, :expected_result) do + ProjectFeature::DISABLED | "admin" | false | 403 + ProjectFeature::DISABLED | "owner" | false | 403 + ProjectFeature::DISABLED | "master" | false | 403 + ProjectFeature::DISABLED | "developer" | false | 403 + ProjectFeature::DISABLED | "reporter" | false | 403 + ProjectFeature::DISABLED | "guest" | false | 403 + ProjectFeature::DISABLED | "user" | false | 403 + ProjectFeature::DISABLED | nil | false | 403 + ProjectFeature::PUBLIC | "admin" | false | 200 + ProjectFeature::PUBLIC | "owner" | false | 200 + ProjectFeature::PUBLIC | "master" | false | 200 + ProjectFeature::PUBLIC | "developer" | false | 200 + ProjectFeature::PUBLIC | "reporter" | false | 200 + ProjectFeature::PUBLIC | "guest" | false | 200 + ProjectFeature::PUBLIC | "user" | false | 200 + ProjectFeature::PUBLIC | nil | false | 200 + ProjectFeature::ENABLED | "admin" | false | 200 + ProjectFeature::ENABLED | "owner" | false | 200 + ProjectFeature::ENABLED | "master" | false | 200 + ProjectFeature::ENABLED | "developer" | false | 200 + ProjectFeature::ENABLED | "reporter" | false | 200 + ProjectFeature::ENABLED | "guest" | false | 200 + ProjectFeature::ENABLED | "user" | false | 200 + ProjectFeature::ENABLED | nil | false | 200 + ProjectFeature::PRIVATE | "admin" | true | 200 + ProjectFeature::PRIVATE | "owner" | false | 200 + ProjectFeature::PRIVATE | "master" | false | 200 + ProjectFeature::PRIVATE | "developer" | false | 200 + ProjectFeature::PRIVATE | "reporter" | false | 200 + ProjectFeature::PRIVATE | "guest" | false | 200 + ProjectFeature::PRIVATE | "user" | false | 403 + ProjectFeature::PRIVATE | nil | false | 403 end with_them do @@ -77,7 +77,7 @@ RSpec.describe "Public Project Pages Access", feature_category: :pages do it "correct return value" do if !with_user.nil? user = public_send(with_user) - get api("/projects/#{project.id}/pages_access", user) + get api("/projects/#{project.id}/pages_access", user, admin_mode: admin_mode) else get api("/projects/#{project.id}/pages_access") end diff --git a/spec/requests/api/pages_domains_spec.rb b/spec/requests/api/pages_domains_spec.rb index ba1fb5105b8..ea83fa384af 100644 --- a/spec/requests/api/pages_domains_spec.rb +++ b/spec/requests/api/pages_domains_spec.rb @@ -41,14 +41,14 @@ RSpec.describe API::PagesDomains, feature_category: :pages do end it_behaves_like '404 response' do - let(:request) { get api('/pages/domains', admin) } + let(:request) { get api('/pages/domains', admin, admin_mode: true) } end end context 'when pages is enabled' do context 'when authenticated as an admin' do - it 'returns paginated all pages domains' do - get api('/pages/domains', admin) + it 'returns paginated all pages domains', :aggregate_failures do + get api('/pages/domains', admin, admin_mode: true) expect(response).to have_gitlab_http_status(:ok) expect(response).to match_response_schema('public_api/v4/pages_domain_basics') @@ -74,7 +74,7 @@ RSpec.describe API::PagesDomains, feature_category: :pages do describe 'GET /projects/:project_id/pages/domains' do shared_examples_for 'get pages domains' do - it 'returns paginated pages domains' do + it 'returns paginated pages domains', :aggregate_failures do get api(route, user) expect(response).to have_gitlab_http_status(:ok) @@ -145,7 +145,7 @@ RSpec.describe API::PagesDomains, feature_category: :pages do describe 'GET /projects/:project_id/pages/domains/:domain' do shared_examples_for 'get pages domain' do - it 'returns pages domain' do + it 'returns pages domain', :aggregate_failures do get api(route_domain, user) expect(response).to have_gitlab_http_status(:ok) @@ -155,7 +155,7 @@ RSpec.describe API::PagesDomains, feature_category: :pages do expect(json_response['certificate']).to be_nil end - it 'returns pages domain with project path' do + it 'returns pages domain with project path', :aggregate_failures do get api(route_domain_path, user) expect(response).to have_gitlab_http_status(:ok) @@ -165,7 +165,7 @@ RSpec.describe API::PagesDomains, feature_category: :pages do expect(json_response['certificate']).to be_nil end - it 'returns pages domain with a certificate' do + it 'returns pages domain with a certificate', :aggregate_failures do get api(route_secure_domain, user) expect(response).to have_gitlab_http_status(:ok) @@ -177,7 +177,7 @@ RSpec.describe API::PagesDomains, feature_category: :pages do expect(json_response['auto_ssl_enabled']).to be false end - it 'returns pages domain with an expired certificate' do + it 'returns pages domain with an expired certificate', :aggregate_failures do get api(route_expired_domain, user) expect(response).to have_gitlab_http_status(:ok) @@ -185,7 +185,7 @@ RSpec.describe API::PagesDomains, feature_category: :pages do expect(json_response['certificate']['expired']).to be true end - it 'returns pages domain with letsencrypt' do + it 'returns pages domain with letsencrypt', :aggregate_failures do get api(route_letsencrypt_domain, user) expect(response).to have_gitlab_http_status(:ok) @@ -258,7 +258,7 @@ RSpec.describe API::PagesDomains, feature_category: :pages do let(:params_secure) { pages_domain_secure_params.slice(:domain, :certificate, :key) } shared_examples_for 'post pages domains' do - it 'creates a new pages domain' do + it 'creates a new pages domain', :aggregate_failures do expect { post api(route, user), params: params } .to publish_event(PagesDomains::PagesDomainCreatedEvent) .with( @@ -279,7 +279,7 @@ RSpec.describe API::PagesDomains, feature_category: :pages do expect(pages_domain.auto_ssl_enabled).to be false end - it 'creates a new secure pages domain' do + it 'creates a new secure pages domain', :aggregate_failures do post api(route, user), params: params_secure pages_domain = PagesDomain.find_by(domain: json_response['domain']) @@ -291,7 +291,7 @@ RSpec.describe API::PagesDomains, feature_category: :pages do expect(pages_domain.auto_ssl_enabled).to be false end - it 'creates domain with letsencrypt enabled' do + it 'creates domain with letsencrypt enabled', :aggregate_failures do post api(route, user), params: pages_domain_with_letsencrypt_params pages_domain = PagesDomain.find_by(domain: json_response['domain']) @@ -301,7 +301,7 @@ RSpec.describe API::PagesDomains, feature_category: :pages do expect(pages_domain.auto_ssl_enabled).to be true end - it 'creates domain with letsencrypt enabled and provided certificate' do + it 'creates domain with letsencrypt enabled and provided certificate', :aggregate_failures do post api(route, user), params: params_secure.merge(auto_ssl_enabled: true) pages_domain = PagesDomain.find_by(domain: json_response['domain']) @@ -376,7 +376,7 @@ RSpec.describe API::PagesDomains, feature_category: :pages do let(:params_secure_nokey) { pages_domain_secure_params.slice(:certificate) } shared_examples_for 'put pages domain' do - it 'updates pages domain removing certificate' do + it 'updates pages domain removing certificate', :aggregate_failures do put api(route_secure_domain, user), params: { certificate: nil, key: nil } pages_domain_secure.reload @@ -399,7 +399,7 @@ RSpec.describe API::PagesDomains, feature_category: :pages do ) end - it 'updates pages domain adding certificate' do + it 'updates pages domain adding certificate', :aggregate_failures do put api(route_domain, user), params: params_secure pages_domain.reload @@ -409,7 +409,7 @@ RSpec.describe API::PagesDomains, feature_category: :pages do expect(pages_domain.key).to eq(params_secure[:key]) end - it 'updates pages domain adding certificate with letsencrypt' do + it 'updates pages domain adding certificate with letsencrypt', :aggregate_failures do put api(route_domain, user), params: params_secure.merge(auto_ssl_enabled: true) pages_domain.reload @@ -420,7 +420,7 @@ RSpec.describe API::PagesDomains, feature_category: :pages do expect(pages_domain.auto_ssl_enabled).to be true end - it 'updates pages domain enabling letsencrypt' do + it 'updates pages domain enabling letsencrypt', :aggregate_failures do put api(route_domain, user), params: { auto_ssl_enabled: true } pages_domain.reload @@ -429,7 +429,7 @@ RSpec.describe API::PagesDomains, feature_category: :pages do expect(pages_domain.auto_ssl_enabled).to be true end - it 'updates pages domain disabling letsencrypt while preserving the certificate' do + it 'updates pages domain disabling letsencrypt while preserving the certificate', :aggregate_failures do put api(route_letsencrypt_domain, user), params: { auto_ssl_enabled: false } pages_domain_with_letsencrypt.reload @@ -440,7 +440,7 @@ RSpec.describe API::PagesDomains, feature_category: :pages do expect(pages_domain_with_letsencrypt.certificate).to be end - it 'updates pages domain with expired certificate' do + it 'updates pages domain with expired certificate', :aggregate_failures do put api(route_expired_domain, user), params: params_secure pages_domain_expired.reload @@ -450,7 +450,7 @@ RSpec.describe API::PagesDomains, feature_category: :pages do expect(pages_domain_expired.key).to eq(params_secure[:key]) end - it 'updates pages domain with expired certificate not updating key' do + it 'updates pages domain with expired certificate not updating key', :aggregate_failures do put api(route_secure_domain, user), params: params_secure_nokey pages_domain_secure.reload diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 44564224193..38e622714e0 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -362,20 +362,10 @@ RSpec.configure do |config| ./spec/requests/api/deploy_tokens_spec.rb ./spec/requests/api/freeze_periods_spec.rb ./spec/requests/api/groups_spec.rb - ./spec/requests/api/issues/get_group_issues_spec.rb - ./spec/requests/api/issues/get_project_issues_spec.rb - ./spec/requests/api/issues/issues_spec.rb - ./spec/requests/api/issues/post_projects_issues_spec.rb - ./spec/requests/api/issues/put_projects_issues_spec.rb ./spec/requests/api/keys_spec.rb ./spec/requests/api/merge_requests_spec.rb ./spec/requests/api/namespaces_spec.rb ./spec/requests/api/notes_spec.rb - ./spec/requests/api/pages/internal_access_spec.rb - ./spec/requests/api/pages/pages_spec.rb - ./spec/requests/api/pages/private_access_spec.rb - ./spec/requests/api/pages/public_access_spec.rb - ./spec/requests/api/pages_domains_spec.rb ./spec/requests/api/personal_access_tokens/self_information_spec.rb ./spec/requests/api/personal_access_tokens_spec.rb ./spec/requests/api/project_export_spec.rb diff --git a/yarn.lock b/yarn.lock index 22b9598215b..2b5aa3bad87 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1237,10 +1237,10 @@ resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-3.24.0.tgz#bc8265919aa04b06cd08be91637471bad195936d" integrity sha512-R4s5qJUFUIbPflknpw1aI/PchiNq65vY7LVsJZnQkY+vi+AgmsETdut/AdferbGWmeWMU0q2wuVu9phE8lDUgA== -"@gitlab/ui@56.4.0": - version "56.4.0" - resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-56.4.0.tgz#35e2ee19fff9ff803f8737300d957b6a9f6ade1f" - integrity sha512-L+0lf5jXrE34RruiibeDOb4wiziSsUhB+d3CHTQIjtm6qdqcwgYT03AoNTgc/E/YVLshEKywTJnnyakreecAlw== +"@gitlab/ui@56.4.1": + version "56.4.1" + resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-56.4.1.tgz#bdf6284053b092608f6f0b70c6abeb36fd352aa2" + integrity sha512-WlEryaV/pwaJkHa+ioCcyB9slE+2RoPs15cmS+OtA9XsmWKqZTI1S00uZG9GcnA9hDKZM+HP2Apy7ku+myzLDQ== dependencies: "@popperjs/core" "^2.11.2" bootstrap-vue "2.23.1" |