Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
f6b58d1490
commit
885275c832
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
71dbaa115c10ae08292a7df74d3f8297ab38f208
|
||||
705e00092a936f0233fe16339aba3a1c65db36b0
|
||||
|
|
|
|||
|
|
@ -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) => {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)"
|
||||
|
|
|
|||
|
|
@ -125,7 +125,7 @@ export default {
|
|||
:select-item="selectItem"
|
||||
:is-selected="isSelected"
|
||||
:item="item"
|
||||
:first="index === 0"
|
||||
:first="!hiddenDelete && index === 0"
|
||||
></slot>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
|
|
|||
|
|
@ -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)),
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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!')
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -0,0 +1 @@
|
|||
7df50689f7e9311ee8e5bd2513f4361be0fceef3962344d2d16bf511132c7a33
|
||||
|
|
@ -0,0 +1 @@
|
|||
094eb5044e841050288c7362cc58c1b63ce4a349fe49a4c5ebee6b83a05feb56
|
||||
|
|
@ -0,0 +1 @@
|
|||
e2f19bbc322127e439fffc4c1e2718288538aa6cb2d50a5248f12470b1c9491e
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)'
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ swap:
|
|||
params: parameters
|
||||
pg: PostgreSQL
|
||||
'postgres$': PostgreSQL
|
||||
golang: Go
|
||||
raketask: Rake task
|
||||
raketasks: Rake tasks
|
||||
rspec: RSpec
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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`.
|
||||
|
|
|
|||
|
|
@ -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. |
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)**
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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).
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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 (
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ They consist of:
|
|||
|
||||
Example:
|
||||
|
||||
```golang
|
||||
```go
|
||||
u.route("PUT", apiProjectPattern+`packages/nuget/`, mimeMultipartUploader),
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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 (
|
||||
|
|
|
|||
|
|
@ -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) |
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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).
|
||||
|
||||
|
|
|
|||
Binary file not shown.
|
After Width: | Height: | Size: 23 KiB |
|
|
@ -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:
|
||||
|
||||

|
||||
|
||||
## 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.
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 ""
|
||||
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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', () => {
|
||||
|
|
|
|||
|
|
@ -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', () => {
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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', () => {
|
||||
|
|
|
|||
|
|
@ -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 the list of tags is empty', () => {
|
||||
beforeEach(() => {
|
||||
resolver = jest.fn().mockResolvedValue(imageTagsMock([]));
|
||||
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();
|
||||
return waitForApolloRequestRender();
|
||||
await waitForApolloRequestRender();
|
||||
|
||||
expect(findRegistryList().props('hiddenDelete')).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when the list of tags is empty', () => {
|
||||
beforeEach(async () => {
|
||||
resolver = jest.fn().mockResolvedValue(imageTagsMock({ nodes: [] }));
|
||||
mountComponent();
|
||||
fireFirstSortUpdate();
|
||||
await waitForApolloRequestRender();
|
||||
});
|
||||
|
||||
it('does not show the loader', () => {
|
||||
|
|
|
|||
|
|
@ -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 },
|
||||
|
|
|
|||
|
|
@ -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 } });
|
||||
});
|
||||
|
||||
expect(findDeleteSelected().exists()).toBe(false);
|
||||
it('is hidden', () => {
|
||||
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', () => {
|
||||
|
|
|
|||
|
|
@ -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' }
|
||||
|
||||
|
|
|
|||
|
|
@ -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] })
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
|
|
|||
|
|
@ -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}")
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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 }
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
Loading…
Reference in New Issue