Add latest changes from gitlab-org/gitlab@master
|
|
@ -885,7 +885,6 @@
|
|||
- <<: *if-merge-request
|
||||
- <<: *if-default-branch-refs
|
||||
variables:
|
||||
ARCH: amd64,arm64
|
||||
BUILD_GDK_BASE: "true"
|
||||
|
||||
.build-images:rules:build-assets-image:
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ import {
|
|||
GlTooltip,
|
||||
GlTooltipDirective,
|
||||
GlPopover,
|
||||
GlBadge,
|
||||
GlPagination,
|
||||
} from '@gitlab/ui';
|
||||
import semverLt from 'semver/functions/lt';
|
||||
import semverInc from 'semver/functions/inc';
|
||||
|
|
@ -15,7 +17,7 @@ import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
|
|||
import timeagoMixin from '~/vue_shared/mixins/timeago';
|
||||
import { helpPagePath } from '~/helpers/help_page_helper';
|
||||
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
|
||||
import { AGENT_STATUSES, I18N_AGENT_TABLE } from '../constants';
|
||||
import { MAX_LIST_COUNT, AGENT_STATUSES, I18N_AGENT_TABLE } from '../constants';
|
||||
import { getAgentConfigPath } from '../clusters_util';
|
||||
import DeleteAgentButton from './delete_agent_button.vue';
|
||||
|
||||
|
|
@ -28,6 +30,8 @@ export default {
|
|||
GlSprintf,
|
||||
GlTooltip,
|
||||
GlPopover,
|
||||
GlBadge,
|
||||
GlPagination,
|
||||
TimeAgoTooltip,
|
||||
DeleteAgentButton,
|
||||
},
|
||||
|
|
@ -60,6 +64,12 @@ export default {
|
|||
type: Number,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
currentPage: 1,
|
||||
limit: this.maxAgents ?? MAX_LIST_COUNT,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
fields() {
|
||||
const tdClass = 'gl-pt-3! gl-pb-4! gl-vertical-align-middle!';
|
||||
|
|
@ -114,6 +124,16 @@ export default {
|
|||
serverVersion() {
|
||||
return this.kasVersion || this.gitlabVersion;
|
||||
},
|
||||
showPagination() {
|
||||
return !this.maxAgents && this.agents.length > this.limit;
|
||||
},
|
||||
prevPage() {
|
||||
return Math.max(this.currentPage - 1, 0);
|
||||
},
|
||||
nextPage() {
|
||||
const nextPage = this.currentPage + 1;
|
||||
return nextPage > Math.ceil(this.agents.length / this.limit) ? null : nextPage;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
getStatusCellId(item) {
|
||||
|
|
@ -184,84 +204,105 @@ export default {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<gl-table
|
||||
:items="agentsList"
|
||||
:fields="fields"
|
||||
stacked="md"
|
||||
class="gl-mb-4!"
|
||||
data-testid="cluster-agent-list-table"
|
||||
>
|
||||
<template #cell(name)="{ item }">
|
||||
<gl-link :href="item.webPath" data-testid="cluster-agent-name-link">
|
||||
{{ item.name }}
|
||||
</gl-link>
|
||||
</template>
|
||||
|
||||
<template #cell(status)="{ item }">
|
||||
<span
|
||||
:id="getStatusCellId(item)"
|
||||
class="gl-md-pr-5"
|
||||
data-testid="cluster-agent-connection-status"
|
||||
>
|
||||
<span :class="$options.AGENT_STATUSES[item.status].class" class="gl-mr-3">
|
||||
<gl-icon :name="$options.AGENT_STATUSES[item.status].icon" :size="16" /></span
|
||||
>{{ $options.AGENT_STATUSES[item.status].name }}
|
||||
</span>
|
||||
<gl-tooltip v-if="item.status === 'active'" :target="getStatusCellId(item)" placement="right">
|
||||
<gl-sprintf :message="$options.AGENT_STATUSES[item.status].tooltip.title"
|
||||
><template #timeAgo>{{ timeFormatted(item.lastContact) }}</template>
|
||||
</gl-sprintf>
|
||||
</gl-tooltip>
|
||||
<gl-popover
|
||||
v-else
|
||||
:target="getStatusCellId(item)"
|
||||
:title="$options.AGENT_STATUSES[item.status].tooltip.title"
|
||||
placement="right"
|
||||
container="viewport"
|
||||
>
|
||||
<p>
|
||||
<gl-sprintf :message="$options.AGENT_STATUSES[item.status].tooltip.body"
|
||||
><template #timeAgo>{{ timeFormatted(item.lastContact) }}</template></gl-sprintf
|
||||
>
|
||||
</p>
|
||||
<p class="gl-mb-0">
|
||||
<gl-link :href="$options.troubleshootingLink" target="_blank" class="gl-font-sm">
|
||||
{{ $options.i18n.troubleshootingText }}</gl-link
|
||||
>
|
||||
</p>
|
||||
</gl-popover>
|
||||
</template>
|
||||
|
||||
<template #cell(lastContact)="{ item }">
|
||||
<span data-testid="cluster-agent-last-contact">
|
||||
<time-ago-tooltip v-if="item.lastContact" :time="item.lastContact" />
|
||||
<span v-else>{{ $options.i18n.neverConnectedText }}</span>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<template #cell(version)="{ item }">
|
||||
<span :id="getVersionCellId(item)" data-testid="cluster-agent-version">
|
||||
{{ getAgentVersionString(item) }}
|
||||
|
||||
<gl-icon
|
||||
v-if="isVersionMismatch(item) || isVersionOutdated(item)"
|
||||
name="warning"
|
||||
class="gl-text-orange-500 gl-ml-2"
|
||||
/>
|
||||
</span>
|
||||
|
||||
<gl-popover
|
||||
v-if="isVersionMismatch(item) || isVersionOutdated(item)"
|
||||
:target="getVersionCellId(item)"
|
||||
:title="getVersionPopoverTitle(item)"
|
||||
:data-testid="getPopoverTestId(item)"
|
||||
placement="right"
|
||||
container="viewport"
|
||||
>
|
||||
<div v-if="isVersionMismatch(item) && isVersionOutdated(item)">
|
||||
<p>{{ $options.i18n.versionMismatchText }}</p>
|
||||
<div>
|
||||
<gl-table
|
||||
:items="agentsList"
|
||||
:fields="fields"
|
||||
:per-page="limit"
|
||||
:current-page="currentPage"
|
||||
stacked="md"
|
||||
class="gl-mb-4!"
|
||||
data-testid="cluster-agent-list-table"
|
||||
>
|
||||
<template #cell(name)="{ item }">
|
||||
<gl-link :href="item.webPath" data-testid="cluster-agent-name-link">{{ item.name }}</gl-link
|
||||
><gl-badge v-if="item.isShared" class="gl-ml-3">{{
|
||||
$options.i18n.sharedBadgeText
|
||||
}}</gl-badge>
|
||||
</template>
|
||||
|
||||
<template #cell(status)="{ item }">
|
||||
<span
|
||||
:id="getStatusCellId(item)"
|
||||
class="gl-md-pr-5"
|
||||
data-testid="cluster-agent-connection-status"
|
||||
>
|
||||
<span :class="$options.AGENT_STATUSES[item.status].class" class="gl-mr-3">
|
||||
<gl-icon :name="$options.AGENT_STATUSES[item.status].icon" :size="16" /></span
|
||||
>{{ $options.AGENT_STATUSES[item.status].name }}
|
||||
</span>
|
||||
<gl-tooltip
|
||||
v-if="item.status === 'active'"
|
||||
:target="getStatusCellId(item)"
|
||||
placement="right"
|
||||
>
|
||||
<gl-sprintf :message="$options.AGENT_STATUSES[item.status].tooltip.title"
|
||||
><template #timeAgo>{{ timeFormatted(item.lastContact) }}</template>
|
||||
</gl-sprintf>
|
||||
</gl-tooltip>
|
||||
<gl-popover
|
||||
v-else
|
||||
:target="getStatusCellId(item)"
|
||||
:title="$options.AGENT_STATUSES[item.status].tooltip.title"
|
||||
placement="right"
|
||||
container="viewport"
|
||||
>
|
||||
<p>
|
||||
<gl-sprintf :message="$options.AGENT_STATUSES[item.status].tooltip.body"
|
||||
><template #timeAgo>{{ timeFormatted(item.lastContact) }}</template></gl-sprintf
|
||||
>
|
||||
</p>
|
||||
<p class="gl-mb-0">
|
||||
<gl-link :href="$options.troubleshootingLink" target="_blank" class="gl-font-sm">
|
||||
{{ $options.i18n.troubleshootingText }}</gl-link
|
||||
>
|
||||
</p>
|
||||
</gl-popover>
|
||||
</template>
|
||||
|
||||
<template #cell(lastContact)="{ item }">
|
||||
<span data-testid="cluster-agent-last-contact">
|
||||
<time-ago-tooltip v-if="item.lastContact" :time="item.lastContact" />
|
||||
<span v-else>{{ $options.i18n.neverConnectedText }}</span>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<template #cell(version)="{ item }">
|
||||
<span :id="getVersionCellId(item)" data-testid="cluster-agent-version">
|
||||
{{ getAgentVersionString(item) }}
|
||||
|
||||
<gl-icon
|
||||
v-if="isVersionMismatch(item) || isVersionOutdated(item)"
|
||||
name="warning"
|
||||
class="gl-text-orange-500 gl-ml-2"
|
||||
/>
|
||||
</span>
|
||||
|
||||
<gl-popover
|
||||
v-if="isVersionMismatch(item) || isVersionOutdated(item)"
|
||||
:target="getVersionCellId(item)"
|
||||
:title="getVersionPopoverTitle(item)"
|
||||
:data-testid="getPopoverTestId(item)"
|
||||
placement="right"
|
||||
container="viewport"
|
||||
>
|
||||
<div v-if="isVersionMismatch(item) && isVersionOutdated(item)">
|
||||
<p>{{ $options.i18n.versionMismatchText }}</p>
|
||||
|
||||
<p class="gl-mb-0">
|
||||
<gl-sprintf :message="$options.i18n.versionOutdatedText">
|
||||
<template #version>{{ serverVersion }}</template>
|
||||
</gl-sprintf>
|
||||
<gl-link :href="$options.versionUpdateLink" class="gl-font-sm">
|
||||
{{ $options.i18n.viewDocsText }}</gl-link
|
||||
>
|
||||
</p>
|
||||
</div>
|
||||
<p v-else-if="isVersionMismatch(item)" class="gl-mb-0">
|
||||
{{ $options.i18n.versionMismatchText }}
|
||||
</p>
|
||||
|
||||
<p v-else-if="isVersionOutdated(item)" class="gl-mb-0">
|
||||
<gl-sprintf :message="$options.i18n.versionOutdatedText">
|
||||
<template #version>{{ serverVersion }}</template>
|
||||
</gl-sprintf>
|
||||
|
|
@ -269,53 +310,54 @@ export default {
|
|||
{{ $options.i18n.viewDocsText }}</gl-link
|
||||
>
|
||||
</p>
|
||||
</div>
|
||||
<p v-else-if="isVersionMismatch(item)" class="gl-mb-0">
|
||||
{{ $options.i18n.versionMismatchText }}
|
||||
</p>
|
||||
</gl-popover>
|
||||
</template>
|
||||
|
||||
<p v-else-if="isVersionOutdated(item)" class="gl-mb-0">
|
||||
<gl-sprintf :message="$options.i18n.versionOutdatedText">
|
||||
<template #version>{{ serverVersion }}</template>
|
||||
</gl-sprintf>
|
||||
<gl-link :href="$options.versionUpdateLink" class="gl-font-sm">
|
||||
{{ $options.i18n.viewDocsText }}</gl-link
|
||||
>
|
||||
</p>
|
||||
</gl-popover>
|
||||
</template>
|
||||
<template #cell(agentID)="{ item }">
|
||||
<span data-testid="cluster-agent-id">
|
||||
{{ getAgentId(item) }}
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<template #cell(agentID)="{ item }">
|
||||
<span data-testid="cluster-agent-id">
|
||||
{{ getAgentId(item) }}
|
||||
</span>
|
||||
</template>
|
||||
<template #cell(configuration)="{ item }">
|
||||
<span data-testid="cluster-agent-configuration-link">
|
||||
<gl-link v-if="item.configFolder" :href="item.configFolder.webPath">
|
||||
{{ getAgentConfigPath(item.name) }}
|
||||
</gl-link>
|
||||
|
||||
<template #cell(configuration)="{ item }">
|
||||
<span data-testid="cluster-agent-configuration-link">
|
||||
<gl-link v-if="item.configFolder" :href="item.configFolder.webPath">
|
||||
{{ getAgentConfigPath(item.name) }}
|
||||
</gl-link>
|
||||
<span v-else-if="item.isShared">
|
||||
{{ $options.i18n.externalConfigText }}
|
||||
</span>
|
||||
|
||||
<span v-else
|
||||
>{{ $options.i18n.defaultConfigText }}
|
||||
<gl-link
|
||||
v-gl-tooltip
|
||||
:href="$options.configHelpLink"
|
||||
:title="$options.i18n.defaultConfigTooltip"
|
||||
:aria-label="$options.i18n.defaultConfigTooltip"
|
||||
class="gl-vertical-align-middle"
|
||||
><gl-icon name="question-o" :size="14" /></gl-link
|
||||
></span>
|
||||
</span>
|
||||
</template>
|
||||
<span v-else
|
||||
>{{ $options.i18n.defaultConfigText }}
|
||||
<gl-link
|
||||
v-gl-tooltip
|
||||
:href="$options.configHelpLink"
|
||||
:title="$options.i18n.defaultConfigTooltip"
|
||||
:aria-label="$options.i18n.defaultConfigTooltip"
|
||||
class="gl-vertical-align-middle"
|
||||
><gl-icon name="question-o" :size="14" /></gl-link
|
||||
></span>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<template #cell(options)="{ item }">
|
||||
<delete-agent-button
|
||||
:agent="item"
|
||||
:default-branch-name="defaultBranchName"
|
||||
:max-agents="maxAgents"
|
||||
/>
|
||||
</template>
|
||||
</gl-table>
|
||||
<template #cell(options)="{ item }">
|
||||
<delete-agent-button
|
||||
v-if="!item.isShared"
|
||||
:agent="item"
|
||||
:default-branch-name="defaultBranchName"
|
||||
/>
|
||||
</template>
|
||||
</gl-table>
|
||||
|
||||
<gl-pagination
|
||||
v-if="showPagination"
|
||||
v-model="currentPage"
|
||||
:prev-page="prevPage"
|
||||
:next-page="nextPage"
|
||||
align="center"
|
||||
class="gl-mt-5"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
<script>
|
||||
import { GlAlert, GlKeysetPagination, GlLoadingIcon, GlBanner } from '@gitlab/ui';
|
||||
import { GlAlert, GlLoadingIcon, GlBanner } from '@gitlab/ui';
|
||||
import { s__ } from '~/locale';
|
||||
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
|
||||
import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue';
|
||||
import { MAX_LIST_COUNT, AGENT_FEEDBACK_ISSUE, AGENT_FEEDBACK_KEY } from '../constants';
|
||||
import { AGENT_FEEDBACK_ISSUE, AGENT_FEEDBACK_KEY } from '../constants';
|
||||
import getAgentsQuery from '../graphql/queries/get_agents.query.graphql';
|
||||
import { getAgentLastContact, getAgentStatus } from '../clusters_util';
|
||||
import AgentEmptyState from './agent_empty_state.vue';
|
||||
|
|
@ -27,7 +27,6 @@ export default {
|
|||
return {
|
||||
defaultBranchName: this.defaultBranchName,
|
||||
projectPath: this.projectPath,
|
||||
...this.cursor,
|
||||
};
|
||||
},
|
||||
update(data) {
|
||||
|
|
@ -37,13 +36,15 @@ export default {
|
|||
result() {
|
||||
this.emitAgentsLoaded();
|
||||
},
|
||||
error() {
|
||||
this.queryErrored = true;
|
||||
},
|
||||
},
|
||||
},
|
||||
components: {
|
||||
AgentEmptyState,
|
||||
AgentTable,
|
||||
GlAlert,
|
||||
GlKeysetPagination,
|
||||
GlLoadingIcon,
|
||||
GlBanner,
|
||||
LocalStorageSync,
|
||||
|
|
@ -69,41 +70,41 @@ export default {
|
|||
},
|
||||
data() {
|
||||
return {
|
||||
cursor: {
|
||||
first: this.limit ? this.limit : MAX_LIST_COUNT,
|
||||
last: null,
|
||||
},
|
||||
folderList: {},
|
||||
feedbackBannerDismissed: false,
|
||||
queryErrored: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
agentList() {
|
||||
let list = this.agents?.project?.clusterAgents?.nodes;
|
||||
const localAgents = this.agents?.project?.clusterAgents?.nodes || [];
|
||||
const sharedAgents = [
|
||||
...(this.agents?.project?.ciAccessAuthorizedAgents?.nodes || []),
|
||||
...(this.agents?.project?.userAccessAuthorizedAgents?.nodes || []),
|
||||
].map((node) => {
|
||||
return {
|
||||
...node.agent,
|
||||
isShared: true,
|
||||
};
|
||||
});
|
||||
|
||||
if (list) {
|
||||
list = list.map((agent) => {
|
||||
const filteredList = [...localAgents, ...sharedAgents]
|
||||
.filter((node, index, list) => {
|
||||
return node && index === list.findIndex((agent) => agent.id === node.id);
|
||||
})
|
||||
.map((agent) => {
|
||||
const configFolder = this.folderList[agent.name];
|
||||
const lastContact = getAgentLastContact(agent?.tokens?.nodes);
|
||||
const status = getAgentStatus(lastContact);
|
||||
return { ...agent, configFolder, lastContact, status };
|
||||
});
|
||||
}
|
||||
})
|
||||
.sort((a, b) => b.lastUsedAt - a.lastUsedAt);
|
||||
|
||||
return list;
|
||||
},
|
||||
agentPageInfo() {
|
||||
return this.agents?.project?.clusterAgents?.pageInfo || {};
|
||||
return filteredList;
|
||||
},
|
||||
isLoading() {
|
||||
return this.$apollo.queries.agents.loading;
|
||||
},
|
||||
showPagination() {
|
||||
return !this.limit && (this.agentPageInfo.hasPreviousPage || this.agentPageInfo.hasNextPage);
|
||||
},
|
||||
treePageInfo() {
|
||||
return this.agents?.project?.repository?.tree?.trees?.pageInfo || {};
|
||||
},
|
||||
feedbackBannerEnabled() {
|
||||
return this.glFeatures.showGitlabAgentFeedback;
|
||||
},
|
||||
|
|
@ -112,22 +113,6 @@ export default {
|
|||
},
|
||||
},
|
||||
methods: {
|
||||
nextPage() {
|
||||
this.cursor = {
|
||||
first: MAX_LIST_COUNT,
|
||||
last: null,
|
||||
afterAgent: this.agentPageInfo.endCursor,
|
||||
afterTree: this.treePageInfo.endCursor,
|
||||
};
|
||||
},
|
||||
prevPage() {
|
||||
this.cursor = {
|
||||
first: null,
|
||||
last: MAX_LIST_COUNT,
|
||||
beforeAgent: this.agentPageInfo.startCursor,
|
||||
beforeTree: this.treePageInfo.endCursor,
|
||||
};
|
||||
},
|
||||
updateTreeList(data) {
|
||||
const configFolders = data?.project?.repository?.tree?.trees?.nodes;
|
||||
|
||||
|
|
@ -138,8 +123,7 @@ export default {
|
|||
}
|
||||
},
|
||||
emitAgentsLoaded() {
|
||||
const count = this.agents?.project?.clusterAgents?.count;
|
||||
this.$emit('onAgentsLoad', count);
|
||||
this.$emit('onAgentsLoad', this.agentList?.length);
|
||||
},
|
||||
handleBannerClose() {
|
||||
this.feedbackBannerDismissed = true;
|
||||
|
|
@ -151,7 +135,7 @@ export default {
|
|||
<template>
|
||||
<gl-loading-icon v-if="isLoading" size="lg" />
|
||||
|
||||
<section v-else-if="agentList">
|
||||
<section v-else-if="!queryErrored">
|
||||
<div v-if="agentList.length">
|
||||
<local-storage-sync
|
||||
v-if="feedbackBannerEnabled"
|
||||
|
|
@ -174,12 +158,8 @@ export default {
|
|||
<agent-table
|
||||
:agents="agentList"
|
||||
:default-branch-name="defaultBranchName"
|
||||
:max-agents="cursor.first"
|
||||
:max-agents="limit"
|
||||
/>
|
||||
|
||||
<div v-if="showPagination" class="gl-display-flex gl-justify-content-center gl-mt-5">
|
||||
<gl-keyset-pagination v-bind="agentPageInfo" @prev="prevPage" @next="nextPage" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<agent-empty-state v-else />
|
||||
|
|
|
|||
|
|
@ -39,11 +39,6 @@ export default {
|
|||
required: false,
|
||||
type: String,
|
||||
},
|
||||
maxAgents: {
|
||||
default: null,
|
||||
required: false,
|
||||
type: Number,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
|
@ -64,8 +59,6 @@ export default {
|
|||
getAgentsQueryVariables() {
|
||||
return {
|
||||
defaultBranchName: this.defaultBranchName,
|
||||
first: this.maxAgents,
|
||||
last: null,
|
||||
projectPath: this.projectPath,
|
||||
};
|
||||
},
|
||||
|
|
|
|||
|
|
@ -13,10 +13,9 @@ import {
|
|||
MODAL_TYPE_EMPTY,
|
||||
MODAL_TYPE_REGISTER,
|
||||
} from '../constants';
|
||||
import { addAgentToStore, addAgentConfigToStore } from '../graphql/cache_update';
|
||||
import { addAgentConfigToStore } from '../graphql/cache_update';
|
||||
import createAgent from '../graphql/mutations/create_agent.mutation.graphql';
|
||||
import createAgentToken from '../graphql/mutations/create_agent_token.mutation.graphql';
|
||||
import getAgentsQuery from '../graphql/queries/get_agents.query.graphql';
|
||||
import agentConfigurations from '../graphql/queries/agent_configurations.query.graphql';
|
||||
import AvailableAgentsDropdown from './available_agents_dropdown.vue';
|
||||
import AgentToken from './agent_token.vue';
|
||||
|
|
@ -148,14 +147,6 @@ export default {
|
|||
projectPath: this.projectPath,
|
||||
},
|
||||
},
|
||||
update: (store, { data: { createClusterAgent } }) => {
|
||||
addAgentToStore(
|
||||
store,
|
||||
createClusterAgent,
|
||||
getAgentsQuery,
|
||||
this.getAgentsQueryVariables,
|
||||
);
|
||||
},
|
||||
})
|
||||
.then(({ data: { createClusterAgent } }) => {
|
||||
return createClusterAgent;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { __, s__, sprintf } from '~/locale';
|
||||
import { helpPagePath } from '~/helpers/help_page_helper';
|
||||
|
||||
export const MAX_LIST_COUNT = 25;
|
||||
export const MAX_LIST_COUNT = 20;
|
||||
export const INSTALL_AGENT_MODAL_ID = 'install-agent';
|
||||
export const ACTIVE_CONNECTION_TIME = 480000;
|
||||
export const NAME_MAX_LENGTH = 50;
|
||||
|
|
@ -86,6 +86,8 @@ export const I18N_AGENT_TABLE = {
|
|||
viewDocsText: s__('ClusterAgents|How to update an agent?'),
|
||||
defaultConfigText: s__('ClusterAgents|Default configuration'),
|
||||
defaultConfigTooltip: s__('ClusterAgents|What is default configuration?'),
|
||||
sharedBadgeText: s__('ClusterAgents|shared'),
|
||||
externalConfigText: s__('ClusterAgents|External project'),
|
||||
};
|
||||
|
||||
export const I18N_AGENT_TOKEN = {
|
||||
|
|
|
|||
|
|
@ -2,27 +2,6 @@ import produce from 'immer';
|
|||
|
||||
export const hasErrors = ({ errors = [] }) => errors?.length;
|
||||
|
||||
export function addAgentToStore(store, createClusterAgent, query, variables) {
|
||||
if (!hasErrors(createClusterAgent)) {
|
||||
const { clusterAgent } = createClusterAgent;
|
||||
const sourceData = store.readQuery({
|
||||
query,
|
||||
variables,
|
||||
});
|
||||
|
||||
const data = produce(sourceData, (draftData) => {
|
||||
draftData.project.clusterAgents.nodes.push(clusterAgent);
|
||||
draftData.project.clusterAgents.count += 1;
|
||||
});
|
||||
|
||||
store.writeQuery({
|
||||
query,
|
||||
variables,
|
||||
data,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function addAgentConfigToStore(
|
||||
store,
|
||||
clusterAgentTokenCreate,
|
||||
|
|
@ -65,7 +44,12 @@ export function removeAgentFromStore(store, deleteClusterAgent, query, variables
|
|||
draftData.project.clusterAgents.nodes = draftData.project.clusterAgents.nodes.filter(
|
||||
({ id }) => id !== deleteClusterAgent.id,
|
||||
);
|
||||
draftData.project.clusterAgents.count -= 1;
|
||||
draftData.project.ciAccessAuthorizedAgents.nodes = draftData.project.ciAccessAuthorizedAgents.nodes.filter(
|
||||
({ agent }) => agent.id !== deleteClusterAgent.id,
|
||||
);
|
||||
draftData.project.userAccessAuthorizedAgents.nodes = draftData.project.userAccessAuthorizedAgents.nodes.filter(
|
||||
({ agent }) => agent.id !== deleteClusterAgent.id,
|
||||
);
|
||||
});
|
||||
|
||||
store.writeQuery({
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ fragment ClusterAgentFragment on ClusterAgent {
|
|||
id
|
||||
name
|
||||
webPath
|
||||
createdAt
|
||||
connections {
|
||||
nodes {
|
||||
metadata {
|
||||
|
|
|
|||
|
|
@ -1,26 +1,28 @@
|
|||
#import "~/graphql_shared/fragments/page_info.fragment.graphql"
|
||||
#import "../fragments/cluster_agent.fragment.graphql"
|
||||
|
||||
query getAgents(
|
||||
$defaultBranchName: String!
|
||||
$projectPath: ID!
|
||||
$first: Int
|
||||
$last: Int
|
||||
$afterAgent: String
|
||||
$beforeAgent: String
|
||||
) {
|
||||
query getAgents($defaultBranchName: String!, $projectPath: ID!) {
|
||||
project(fullPath: $projectPath) {
|
||||
id
|
||||
clusterAgents(first: $first, last: $last, before: $beforeAgent, after: $afterAgent) {
|
||||
clusterAgents {
|
||||
nodes {
|
||||
...ClusterAgentFragment
|
||||
}
|
||||
}
|
||||
|
||||
pageInfo {
|
||||
...PageInfo
|
||||
ciAccessAuthorizedAgents {
|
||||
nodes {
|
||||
agent {
|
||||
...ClusterAgentFragment
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
count
|
||||
userAccessAuthorizedAgents {
|
||||
nodes {
|
||||
agent {
|
||||
...ClusterAgentFragment
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
repository {
|
||||
|
|
|
|||
|
|
@ -577,6 +577,7 @@ export const saveDiffDiscussion = async ({ state, dispatch }, { note, formData }
|
|||
const postData = getNoteFormData({
|
||||
commit: state.commit,
|
||||
note,
|
||||
showWhitespace: state.showWhitespace,
|
||||
...formData,
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -140,6 +140,7 @@ export function getFormData(params) {
|
|||
linePosition,
|
||||
positionType,
|
||||
lineRange,
|
||||
showWhitespace,
|
||||
} = params;
|
||||
|
||||
const position = JSON.stringify({
|
||||
|
|
@ -156,6 +157,7 @@ export function getFormData(params) {
|
|||
width: params.width,
|
||||
height: params.height,
|
||||
line_range: lineRange,
|
||||
ignore_whitespace_change: !showWhitespace,
|
||||
});
|
||||
|
||||
const postData = {
|
||||
|
|
|
|||
|
|
@ -164,7 +164,7 @@ export default {
|
|||
|
||||
<gl-tabs
|
||||
content-class="gl-pt-0"
|
||||
data-testid="security-configuration-container"
|
||||
data-qa-selector="security_configuration_container"
|
||||
sync-active-tab-with-query-params
|
||||
lazy
|
||||
>
|
||||
|
|
@ -196,9 +196,12 @@ export default {
|
|||
{{ $options.i18n.description }}
|
||||
</p>
|
||||
<p v-if="canViewCiHistory">
|
||||
<gl-link data-testid="security-view-history-link" :href="gitlabCiHistoryPath">{{
|
||||
$options.i18n.configurationHistory
|
||||
}}</gl-link>
|
||||
<gl-link
|
||||
data-testid="security-view-history-link"
|
||||
data-qa-selector="security_configuration_history_link"
|
||||
:href="gitlabCiHistoryPath"
|
||||
>{{ $options.i18n.configurationHistory }}</gl-link
|
||||
>
|
||||
</p>
|
||||
</template>
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ export default {
|
|||
variant="info"
|
||||
:primary-button-link="autoDevopsPath"
|
||||
:primary-button-text="$options.i18n.primaryButtonText"
|
||||
data-testid="autodevops-container"
|
||||
data-qa-selector="autodevops_container"
|
||||
@dismiss="dismissMethod"
|
||||
>
|
||||
<gl-sprintf :message="$options.i18n.body">
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ export default {
|
|||
v-if="isNotSastIACTemporaryHack"
|
||||
:class="statusClasses"
|
||||
data-testid="feature-status"
|
||||
:data-qa-feature="`${feature.type}_${hasEnabledStatus}_status`"
|
||||
:data-qa-selector="`${feature.type}_status`"
|
||||
>
|
||||
<feature-card-badge
|
||||
v-if="hasBadge"
|
||||
|
|
@ -164,7 +164,7 @@ export default {
|
|||
:href="feature.configurationPath"
|
||||
variant="confirm"
|
||||
:category="configurationButton.category"
|
||||
:data-testid="`${feature.type}_enable_button`"
|
||||
:data-qa-selector="`${feature.type}_enable_button`"
|
||||
class="gl-mt-5"
|
||||
>
|
||||
{{ configurationButton.text }}
|
||||
|
|
@ -176,7 +176,7 @@ export default {
|
|||
variant="confirm"
|
||||
:category="manageViaMrButtonCategory"
|
||||
class="gl-mt-5"
|
||||
:data-testid="`${feature.type}_mr_button`"
|
||||
:data-qa-selector="`${feature.type}_mr_button`"
|
||||
@error="onError"
|
||||
/>
|
||||
|
||||
|
|
|
|||
|
|
@ -43,7 +43,6 @@ class DiffNotePosition < ApplicationRecord
|
|||
def self.position_to_attrs(position)
|
||||
position_attrs = position.to_h
|
||||
position_attrs[:diff_content_type] = position_attrs.delete(:position_type)
|
||||
position_attrs.delete(:line_range)
|
||||
position_attrs
|
||||
position_attrs.except(:line_range, :ignore_whitespace_change)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -146,6 +146,12 @@
|
|||
{ "type": "integer" },
|
||||
{ "type": "string", "maxLength": 10 }
|
||||
]
|
||||
},
|
||||
"ignore_whitespace_change": {
|
||||
"oneOf": [
|
||||
{ "type": "null" },
|
||||
{ "type": "boolean" }
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,12 +3,12 @@
|
|||
= dropdown_tag(_('Select'),
|
||||
options: { toggle_class: 'js-allowed-to-merge wide',
|
||||
dropdown_class: 'dropdown-menu-selectable capitalize-header', dropdown_qa_selector: 'allowed_to_merge_dropdown_content', dropdown_testid: 'allowed-to-merge-dropdown',
|
||||
data: { field_name: 'protected_branch[merge_access_levels_attributes][0][access_level]', input_id: 'merge_access_levels_attributes', qa_selector: 'select_allowed_to_merge_dropdown' }})
|
||||
data: { field_name: 'protected_branch[merge_access_levels_attributes][0][access_level]', input_id: 'merge_access_levels_attributes', qa_selector: 'allowed_to_merge_dropdown' }})
|
||||
- content_for :push_access_levels do
|
||||
.push_access_levels-container
|
||||
= dropdown_tag(_('Select'),
|
||||
options: { toggle_class: "js-allowed-to-push js-multiselect wide",
|
||||
dropdown_class: 'dropdown-menu-selectable capitalize-header', dropdown_qa_selector: 'allowed_to_push_dropdown_content' , dropdown_testid: 'allowed-to-push-dropdown',
|
||||
data: { field_name: 'protected_branch[push_access_levels_attributes][0][access_level]', input_id: 'push_access_levels_attributes', qa_selector: 'select_allowed_to_push_dropdown' }})
|
||||
data: { field_name: 'protected_branch[push_access_levels_attributes][0][access_level]', input_id: 'push_access_levels_attributes', qa_selector: 'allowed_to_push_dropdown' }})
|
||||
|
||||
= render 'protected_branches/shared/create_protected_branch', protected_branch_entity: protected_branch_entity
|
||||
|
|
|
|||
|
|
@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/366854
|
|||
milestone: '15.3'
|
||||
type: development
|
||||
group: group::tenant scale
|
||||
default_enabled: false
|
||||
default_enabled: true
|
||||
|
|
|
|||
|
|
@ -119,6 +119,41 @@ NOTE:
|
|||
To protect, update, or unprotect an environment, you must have at least the
|
||||
Maintainer role.
|
||||
|
||||
#### Migrate to multiple approval rules
|
||||
|
||||
You can migrate a protected environment from unified approval rules to multiple
|
||||
approval rules. Unified approval rules allow all entities that can deploy to an
|
||||
environment to approve deployment jobs. To migrate to multiple approval rules,
|
||||
create a new approval rule for each entity allowed to deploy to the environment.
|
||||
|
||||
To migrate with the UI:
|
||||
|
||||
1. On the top bar, select **Main menu > Projects** and find your project.
|
||||
1. On the left sidebar, select **Settings > CI/CD**.
|
||||
1. Expand **Protected environments**.
|
||||
1. From the **Environment** list, select your environment.
|
||||
1. For each entity allowed to deploy to the environment:
|
||||
1. Select **Add approval rules**.
|
||||
1. In the modal window, select which entity is allowed to approve the
|
||||
deployment job.
|
||||
1. Enter the number of required approvals.
|
||||
1. Select **Save**.
|
||||
|
||||
Each deployment requires the specified number of approvals from each entity.
|
||||
|
||||
For example, the `Production` environment below requires five total approvals,
|
||||
and allows deployments from only the group `Very Important Group` and the user
|
||||
`Administrator`:
|
||||
|
||||

|
||||
|
||||
To migrate, create rules for the `Very Important Group` and `Administrator`. To
|
||||
preserve the number of required approvals, set the number of required approvals
|
||||
for `Very Important Group` to four and `Administrator` to one. The new rules
|
||||
require `Administrator` to approve every deployment job in `Production`.
|
||||
|
||||

|
||||
|
||||
### Allow self-approval **(PREMIUM)**
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/381418) in GitLab 15.8.
|
||||
|
|
|
|||
|
After Width: | Height: | Size: 107 KiB |
|
After Width: | Height: | Size: 121 KiB |
|
|
@ -12,7 +12,7 @@ or open threads, you can prevent it from being accepted before you
|
|||
[mark it as ready](#mark-merge-requests-as-ready). Flag it as a draft to disable
|
||||
the **Merge** button until you remove the **Draft** flag:
|
||||
|
||||

|
||||

|
||||
|
||||
## Mark merge requests as drafts
|
||||
|
||||
|
|
@ -42,10 +42,7 @@ When a merge request is ready to be merged, you can remove the `Draft` flag in s
|
|||
|
||||
- **Viewing a merge request**: In the upper-right corner of the merge request, select **Mark as ready**.
|
||||
Users with at least the Developer role
|
||||
can also scroll to the bottom of the merge request description and select **Mark as ready**:
|
||||
|
||||

|
||||
|
||||
can also scroll to the bottom of the merge request description and select **Mark as ready**.
|
||||
- **Editing an existing merge request**: Remove `[Draft]`, `Draft:` or `(Draft)`
|
||||
from the beginning of the title, or clear **Mark as draft**
|
||||
below the **Title** field.
|
||||
|
|
@ -71,7 +68,7 @@ draft merge requests:
|
|||
1. Select **Yes** to include drafts, or **No** to exclude, and press **Return**
|
||||
to update the list of merge requests:
|
||||
|
||||

|
||||

|
||||
|
||||
## Pipelines for drafts
|
||||
|
||||
|
|
|
|||
|
After Width: | Height: | Size: 8.5 KiB |
|
Before Width: | Height: | Size: 4.8 KiB |
|
Before Width: | Height: | Size: 3.4 KiB |
|
After Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 7.9 KiB |
|
After Width: | Height: | Size: 4.5 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 7.3 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
|
@ -93,6 +93,8 @@ or:
|
|||
|
||||
To filter the list of merge requests:
|
||||
|
||||
1. On the top bar, select **Main menu > Projects** and find your project.
|
||||
1. On the left sidebar, select **Merge requests**.
|
||||
1. Above the list of merge requests, select **Search or filter results...**.
|
||||
1. From the dropdown list, select the attribute you wish to filter by. Some examples:
|
||||
- [**By environment or deployment date**](#by-environment-or-deployment-date).
|
||||
|
|
@ -132,17 +134,15 @@ Projects using a [fast-forward merge method](methods/index.md#fast-forward-merge
|
|||
do not return results, as this method does not create a merge commit.
|
||||
|
||||
When filtering by an environment, a dropdown list presents all environments that
|
||||
you can choose from:
|
||||
you can choose from.
|
||||
|
||||

|
||||
When filtering by `Deployed-before` or `Deployed-after`:
|
||||
|
||||
When filtering by `Deployed-before` or `Deployed-after`, the date refers to when
|
||||
the deployment to an environment (triggered by the merge commit) completed successfully.
|
||||
You must enter the deploy date manually. Deploy dates
|
||||
use the format `YYYY-MM-DD`, and must be quoted if you wish to specify
|
||||
both a date and time (`"YYYY-MM-DD HH:MM"`):
|
||||
|
||||

|
||||
- The date refers to when the deployment to an environment (triggered by the
|
||||
merge commit) completed successfully.
|
||||
- You must enter the deploy date manually.
|
||||
- Deploy dates use the format `YYYY-MM-DD`, and must be wrapped in double quotes (`"`)
|
||||
if you want to specify both a date and time (`"YYYY-MM-DD HH:MM"`).
|
||||
|
||||
## Add changes to a merge request
|
||||
|
||||
|
|
@ -182,7 +182,7 @@ The merge request is added to the user's assigned merge request list.
|
|||
GitLab enables multiple assignees for merge requests, if multiple people are
|
||||
accountable for it:
|
||||
|
||||

|
||||

|
||||
|
||||
To assign multiple assignees to a merge request, use the `/assign @user`
|
||||
[quick action](../quick_actions.md#issues-merge-requests-and-epics) in a text area, or:
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ If you review a merge request and it's ready to merge, but the pipeline hasn't
|
|||
completed yet, you can set it to auto-merge. You don't
|
||||
have to remember later to merge the work manually:
|
||||
|
||||

|
||||

|
||||
|
||||
NOTE:
|
||||
[In GitLab 16.0 and later](https://gitlab.com/gitlab-org/gitlab/-/issues/359057), **Merge when pipeline succeeds** and **Add to merge train when pipeline succeeds** are renamed **Set to auto-merge**.
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ for environments. If it's the first time the branch is deployed, the link
|
|||
returns a `404` error until done. During the deployment, the stop button is
|
||||
disabled. If the pipeline fails to deploy, the deployment information is hidden.
|
||||
|
||||

|
||||

|
||||
|
||||
For more information, [read about pipelines](../../../ci/pipelines/index.md).
|
||||
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ module API
|
|||
}
|
||||
}
|
||||
} do |note|
|
||||
note.position.to_h
|
||||
note.position.to_h.except(:ignore_whitespace_change)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ module API
|
|||
expose :commit_id, if: ->(note, options) { note.noteable_type == "MergeRequest" && note.is_a?(DiffNote) }
|
||||
|
||||
expose :position, if: ->(note, options) { note.is_a?(DiffNote) } do |note|
|
||||
note.position.to_h
|
||||
note.position.to_h.except(:ignore_whitespace_change)
|
||||
end
|
||||
|
||||
expose :resolvable?, as: :resolvable
|
||||
|
|
|
|||
|
|
@ -22,33 +22,6 @@ module API
|
|||
end
|
||||
resource :groups, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
|
||||
namespace ':id/-/packages/npm' do
|
||||
params do
|
||||
requires :package_name, type: String, desc: 'Package name'
|
||||
end
|
||||
namespace '-/package/*package_name' do
|
||||
get 'dist-tags', format: false do
|
||||
not_found!
|
||||
end
|
||||
|
||||
namespace 'dist-tags/:tag' do
|
||||
put format: false do
|
||||
not_found!
|
||||
end
|
||||
|
||||
delete format: false do
|
||||
not_found!
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
post '-/npm/v1/security/audits/quick' do
|
||||
not_found!
|
||||
end
|
||||
|
||||
post '-/npm/v1/security/advisories/bulk' do
|
||||
not_found!
|
||||
end
|
||||
|
||||
include ::API::Concerns::Packages::NpmEndpoints
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
module Gitlab
|
||||
module Database
|
||||
class TablesTruncate
|
||||
GITLAB_SCHEMAS_TO_IGNORE = %i[gitlab_geo].freeze
|
||||
GITLAB_SCHEMAS_TO_IGNORE = %i[gitlab_geo gitlab_embedding].freeze
|
||||
|
||||
def initialize(database_name:, min_batch_size:, logger: nil, until_table: nil, dry_run: false)
|
||||
@database_name = database_name
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ module Gitlab
|
|||
attr_reader :base_sha
|
||||
attr_reader :start_sha
|
||||
attr_reader :head_sha
|
||||
attr_reader :ignore_whitespace_change
|
||||
|
||||
def initialize(attrs)
|
||||
if diff_file = attrs[:diff_file]
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ module Gitlab
|
|||
@y = attrs[:y]
|
||||
@width = attrs[:width]
|
||||
@height = attrs[:height]
|
||||
@ignore_whitespace_change = false
|
||||
|
||||
super(attrs)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ module Gitlab
|
|||
@old_line = attrs[:old_line]
|
||||
@new_line = attrs[:new_line]
|
||||
@line_range = attrs[:line_range]
|
||||
@ignore_whitespace_change = !!attrs[:ignore_whitespace_change]
|
||||
|
||||
super(attrs)
|
||||
end
|
||||
|
|
@ -25,7 +26,8 @@ module Gitlab
|
|||
end
|
||||
|
||||
def to_h
|
||||
super.merge(old_line: old_line, new_line: new_line, line_range: line_range)
|
||||
super.merge(old_line: old_line, new_line: new_line, line_range: line_range,
|
||||
ignore_whitespace_change: ignore_whitespace_change)
|
||||
end
|
||||
|
||||
def line_age
|
||||
|
|
|
|||
|
|
@ -19,7 +19,8 @@ module Gitlab
|
|||
:x,
|
||||
:y,
|
||||
:line_range,
|
||||
:position_type, to: :formatter
|
||||
:position_type,
|
||||
:ignore_whitespace_change, to: :formatter
|
||||
|
||||
# A position can belong to a text line or to an image coordinate
|
||||
# it depends of the position_type argument.
|
||||
|
|
@ -69,11 +70,11 @@ module Gitlab
|
|||
end
|
||||
|
||||
def to_json(opts = nil)
|
||||
Gitlab::Json.generate(formatter.to_h, opts)
|
||||
Gitlab::Json.generate(to_h.except(:ignore_whitespace_change), opts)
|
||||
end
|
||||
|
||||
def as_json(opts = nil)
|
||||
to_h.as_json(opts)
|
||||
to_h.except(:ignore_whitespace_change).as_json(opts)
|
||||
end
|
||||
|
||||
def type
|
||||
|
|
@ -134,7 +135,7 @@ module Gitlab
|
|||
end
|
||||
|
||||
def diff_options
|
||||
{ paths: paths, expanded: true, include_stats: false }
|
||||
{ paths: paths, expanded: true, include_stats: false, ignore_whitespace_change: ignore_whitespace_change }
|
||||
end
|
||||
|
||||
def diff_line(repository)
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ module Gitlab
|
|||
return unless old_diff_refs&.complete? && new_diff_refs&.complete?
|
||||
return unless old_position.diff_refs == old_diff_refs
|
||||
|
||||
@ignore_whitespace_change = old_position.ignore_whitespace_change
|
||||
strategy = old_position.on_text? ? LineStrategy : ImageStrategy
|
||||
|
||||
strategy.new(self).trace(old_position)
|
||||
|
|
@ -50,7 +51,7 @@ module Gitlab
|
|||
|
||||
def compare(start_sha, head_sha, straight: false)
|
||||
compare = CompareService.new(project, head_sha).execute(project, start_sha, straight: straight)
|
||||
compare.diffs(paths: paths, expanded: true)
|
||||
compare.diffs(paths: paths, expanded: true, ignore_whitespace_change: @ignore_whitespace_change)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -62,6 +62,8 @@ module Gitlab
|
|||
# The line number as of D can be found by using the LineMapper on diff C->D
|
||||
# and providing the line number as of C.
|
||||
|
||||
@ignore_whitespace_change = position.ignore_whitespace_change
|
||||
|
||||
if position.added?
|
||||
trace_added_line(position)
|
||||
elsif position.removed?
|
||||
|
|
@ -189,7 +191,8 @@ module Gitlab
|
|||
diff_file: diff_file,
|
||||
old_line: old_line,
|
||||
new_line: new_line,
|
||||
line_range: line_range
|
||||
line_range: line_range,
|
||||
ignore_whitespace_change: @ignore_whitespace_change
|
||||
}.compact
|
||||
|
||||
Position.new(**params)
|
||||
|
|
|
|||
|
|
@ -1853,9 +1853,6 @@ msgstr ""
|
|||
msgid "AI actions"
|
||||
msgstr ""
|
||||
|
||||
msgid "AI generated this test"
|
||||
msgstr ""
|
||||
|
||||
msgid "AI-generated test file"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -10236,6 +10233,9 @@ msgstr ""
|
|||
msgid "ClusterAgents|Event occurred"
|
||||
msgstr ""
|
||||
|
||||
msgid "ClusterAgents|External project"
|
||||
msgstr ""
|
||||
|
||||
msgid "ClusterAgents|Failed to create a token"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -10406,6 +10406,9 @@ msgstr ""
|
|||
msgid "ClusterAgents|Your instance doesn't have the %{linkStart}GitLab Agent Server (KAS)%{linkEnd} set up. Ask a GitLab Administrator to install it."
|
||||
msgstr ""
|
||||
|
||||
msgid "ClusterAgents|shared"
|
||||
msgstr ""
|
||||
|
||||
msgid "ClusterAgent|User has insufficient permissions to create a token for this project"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -29311,38 +29314,56 @@ msgstr ""
|
|||
msgid "NamespaceLimits|You must select a namespace and add a reason for excluding it"
|
||||
msgstr ""
|
||||
|
||||
msgid "NamespaceStorageSize|%{namespace_name} contains %{locked_project_count} locked project"
|
||||
msgid_plural "NamespaceStorageSize|%{namespace_name} contains %{locked_project_count} locked projects"
|
||||
msgid "NamespaceStorageSize|%{namespace_name} is now read-only. Your ability to write new data to this namespace is restricted. %{read_only_link_start}Which actions are restricted?%{link_end}"
|
||||
msgstr ""
|
||||
|
||||
msgid "NamespaceStorageSize|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
|
||||
msgstr ""
|
||||
|
||||
msgid "NamespaceStorageSize|If %{namespace_name} exceeds the storage quota, your ability to write new data to this namespace will be restricted. %{read_only_link_start}Which actions become restricted?%{link_end}"
|
||||
msgstr ""
|
||||
|
||||
msgid "NamespaceStorageSize|If a project reaches 100%% of the storage quota (%{free_size_limit}) the project will be in a read-only state, and you won't be able to push to your repository or add large files."
|
||||
msgstr ""
|
||||
|
||||
msgid "NamespaceStorageSize|To prevent your projects from being in a read-only state %{manage_storage_link_start}manage your storage usage%{link_end}, or %{purchase_more_link_start}purchase more storage%{link_end}."
|
||||
msgstr ""
|
||||
|
||||
msgid "NamespaceStorageSize|To prevent your projects from being in a read-only state %{manage_storage_link_start}manage your storage usage%{link_end}, or contact a user with the %{group_member_link_start}owner role for this namespace%{link_end} and ask them to %{purchase_more_link_start}purchase more storage%{link_end}."
|
||||
msgstr ""
|
||||
|
||||
msgid "NamespaceStorageSize|To reduce storage usage, reduce git repository and git LFS storage."
|
||||
msgstr ""
|
||||
|
||||
msgid "NamespaceStorageSize|To remove the read-only state %{manage_storage_link_start}manage your storage usage%{link_end}, or %{purchase_more_link_start}purchase more storage%{link_end}."
|
||||
msgstr ""
|
||||
|
||||
msgid "NamespaceStorageSize|To remove the read-only state %{manage_storage_link_start}manage your storage usage%{link_end}, or contact a user with the %{group_member_link_start}owner role for this namespace%{link_end} and ask them to %{purchase_more_link_start}purchase more storage%{link_end}."
|
||||
msgstr ""
|
||||
|
||||
msgid "NamespaceStorageSize|To remove the read-only state, reduce git repository and git LFS storage, or %{purchase_more_link_start}purchase more storage%{link_end}."
|
||||
msgstr ""
|
||||
|
||||
msgid "NamespaceStorageSize|To remove the read-only state, reduce git repository and git LFS storage, or contact a user with the %{group_member_link_start}owner role for this namespace%{link_end} and ask them to %{purchase_more_link_start}purchase more storage%{link_end}."
|
||||
msgstr ""
|
||||
|
||||
msgid "NamespaceStorageSize|You have consumed all available storage and you can't push or add large files to projects over the free tier limit (%{free_size_limit})."
|
||||
msgstr ""
|
||||
|
||||
msgid "NamespaceStorageSize|You have reached the free storage limit of %{free_size_limit} for %{namespace_name}"
|
||||
msgstr ""
|
||||
|
||||
msgid "NamespaceStorageSize|You have reached the free storage limit of %{free_size_limit} on %{readonly_project_count} project"
|
||||
msgid_plural "NamespaceStorageSize|You have reached the free storage limit of %{free_size_limit} on %{readonly_project_count} projects"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
msgid "NamespaceStorageSize|%{namespace_name} is now read-only. Projects under this namespace are locked and actions are restricted. %{actions_restricted_link}"
|
||||
msgstr ""
|
||||
|
||||
msgid "NamespaceStorageSize|If %{namespace_name} exceeds the storage quota, all projects in the namespace will be locked and actions will be restricted. %{actions_restricted_link}"
|
||||
msgstr ""
|
||||
|
||||
msgid "NamespaceStorageSize|If you reach 100%% storage capacity, you will not be able to: %{repository_limits_description}"
|
||||
msgstr ""
|
||||
|
||||
msgid "NamespaceStorageSize|Manage your storage usage or, if you are a namespace Owner, purchase additional storage. %{learn_more_link}."
|
||||
msgstr ""
|
||||
|
||||
msgid "NamespaceStorageSize|Please purchase additional storage to unlock your projects over the free %{free_size_limit} project limit. You can't %{repository_limits_description}"
|
||||
msgstr ""
|
||||
|
||||
msgid "NamespaceStorageSize|You have consumed all of your additional storage, please purchase more to unlock your projects over the free %{free_size_limit} limit. You can't %{repository_limits_description}"
|
||||
msgstr ""
|
||||
|
||||
msgid "NamespaceStorageSize|You have reached the free storage limit of %{free_size_limit} on one or more projects"
|
||||
msgid "NamespaceStorageSize|You have used %{usage_in_percent} of the storage quota for %{namespace_name}"
|
||||
msgstr ""
|
||||
|
||||
msgid "NamespaceStorageSize|You have used %{usage_in_percent} of the storage quota for %{namespace_name} (%{used_storage} of %{storage_limit})"
|
||||
msgstr ""
|
||||
|
||||
msgid "NamespaceStorageSize|push to your repository, create pipelines, create issues or add comments. To reduce storage capacity, delete unused repositories, artifacts, wikis, issues, and pipelines. %{learn_more_link}."
|
||||
msgstr ""
|
||||
|
||||
msgid "NamespaceStorage|%{name_with_link} is now read-only. Projects under this namespace are locked and actions are restricted."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -44752,6 +44773,9 @@ msgid_plural "Test coverage: %d hits"
|
|||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
msgid "Test generated by AI"
|
||||
msgstr ""
|
||||
|
||||
msgid "Test settings"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -50629,12 +50653,6 @@ msgstr ""
|
|||
msgid "Which API requests are affected?"
|
||||
msgstr ""
|
||||
|
||||
msgid "Which actions are restricted?"
|
||||
msgstr ""
|
||||
|
||||
msgid "Which actions become restricted?"
|
||||
msgstr ""
|
||||
|
||||
msgid "While it's rare to have no vulnerabilities, it can happen. In any event, we ask that you please double check your settings to make sure you've set up your dashboard correctly."
|
||||
msgstr ""
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,9 @@ module QA
|
|||
@attributes[:pattern] ||= selector
|
||||
|
||||
options.each do |option|
|
||||
@attributes[:pattern] = option if option.is_a?(String) || option.is_a?(Regexp)
|
||||
if option.is_a?(String) || option.is_a?(Regexp)
|
||||
@attributes[:pattern] = option
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -26,7 +28,7 @@ module QA
|
|||
end
|
||||
|
||||
def selector_css
|
||||
%(#{qa_selector},.#{selector})
|
||||
%Q([data-qa-selector="#{@name}"]#{additional_selectors},.#{selector})
|
||||
end
|
||||
|
||||
def expression
|
||||
|
|
@ -38,19 +40,14 @@ module QA
|
|||
end
|
||||
|
||||
def matches?(line)
|
||||
!!(line =~ /["']#{name}['"]|["']#{name.to_s.tr('_', '-')}['"]|#{expression}/)
|
||||
!!(line =~ /["']#{name}['"]|#{expression}/)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def qa_selector
|
||||
%([data-testid="#{@name}"]#{additional_selectors},[data-testid="#{@name.to_s.tr('_',
|
||||
'-')}"]#{additional_selectors},[data-qa-selector="#{@name}"]#{additional_selectors})
|
||||
end
|
||||
|
||||
def additional_selectors
|
||||
@attributes.dup.delete_if { |attr| attr == :pattern || attr == :required }.map do |key, value|
|
||||
%([data-qa-#{key.to_s.tr('_', '-')}="#{value}"])
|
||||
%Q([data-qa-#{key.to_s.tr('_', '-')}="#{value}"])
|
||||
end.join
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -14,10 +14,8 @@ module QA
|
|||
end
|
||||
end
|
||||
|
||||
def wait_for_markdown_preview(component, content)
|
||||
return if has_markdown_preview?(component, content)
|
||||
|
||||
raise ElementNotFound, %("Couldn't find #{component} element with content '#{content}')
|
||||
def preview
|
||||
click_link('Preview')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -9,13 +9,15 @@ module QA
|
|||
|
||||
view 'app/assets/javascripts/security_configuration/components/app.vue' do
|
||||
element :security_configuration_container
|
||||
element :security_view_history_link
|
||||
element :security_configuration_history_link
|
||||
end
|
||||
|
||||
view 'app/assets/javascripts/security_configuration/components/feature_card.vue' do
|
||||
element :feature_status
|
||||
element :dependency_scanning_status, "`${feature.type}_status`" # rubocop:disable QA/ElementWithPattern
|
||||
element :sast_status, "`${feature.type}_status`" # rubocop:disable QA/ElementWithPattern
|
||||
element :sast_enable_button, "`${feature.type}_enable_button`" # rubocop:disable QA/ElementWithPattern
|
||||
element :dependency_scanning_mr_button, "`${feature.type}_mr_button`" # rubocop:disable QA/ElementWithPattern
|
||||
element :license_scanning_status, "`${feature.type}_status`" # rubocop:disable QA/ElementWithPattern
|
||||
end
|
||||
|
||||
view 'app/assets/javascripts/security_configuration/components/auto_dev_ops_alert.vue' do
|
||||
|
|
@ -23,15 +25,15 @@ module QA
|
|||
end
|
||||
|
||||
def has_security_configuration_history_link?
|
||||
has_element?(:security_view_history_link)
|
||||
has_element?(:security_configuration_history_link)
|
||||
end
|
||||
|
||||
def has_no_security_configuration_history_link?
|
||||
has_no_element?(:security_view_history_link)
|
||||
has_no_element?(:security_configuration_history_link)
|
||||
end
|
||||
|
||||
def click_security_configuration_history_link
|
||||
click_element(:security_view_history_link)
|
||||
click_element(:security_configuration_history_link)
|
||||
end
|
||||
|
||||
def click_sast_enable_button
|
||||
|
|
@ -42,20 +44,40 @@ module QA
|
|||
click_element(:dependency_scanning_mr_button)
|
||||
end
|
||||
|
||||
def has_true_sast_status?
|
||||
has_element?(:feature_status, feature: 'sast_true_status')
|
||||
def has_sast_status?(status_text)
|
||||
within_element(:sast_status) do
|
||||
has_text?(status_text)
|
||||
end
|
||||
end
|
||||
|
||||
def has_false_sast_status?
|
||||
has_element?(:feature_status, feature: 'sast_false_status')
|
||||
def has_no_sast_status?(status_text)
|
||||
within_element(:sast_status) do
|
||||
has_no_text?(status_text)
|
||||
end
|
||||
end
|
||||
|
||||
def has_true_dependency_scanning_status?
|
||||
has_element?(:feature_status, feature: 'dependency_scanning_true_status')
|
||||
def has_dependency_scanning_status?(status_text)
|
||||
within_element(:dependency_scanning_status) do
|
||||
has_text?(status_text)
|
||||
end
|
||||
end
|
||||
|
||||
def has_false_dependency_scanning_status?
|
||||
has_element?(:feature_status, feature: 'dependency_scanning_false_status')
|
||||
def has_no_dependency_scanning_status?(status_text)
|
||||
within_element(:dependency_scanning_status) do
|
||||
has_no_text?(status_text)
|
||||
end
|
||||
end
|
||||
|
||||
def has_license_compliance_status?(status_text)
|
||||
within_element(:license_scanning_status) do
|
||||
has_text?(status_text)
|
||||
end
|
||||
end
|
||||
|
||||
def has_no_license_compliance_status?(status_text)
|
||||
within_element(:license_scanning_status) do
|
||||
has_no_text?(status_text)
|
||||
end
|
||||
end
|
||||
|
||||
def has_auto_devops_container?
|
||||
|
|
|
|||
|
|
@ -11,9 +11,9 @@ module QA
|
|||
end
|
||||
|
||||
view 'app/views/protected_branches/_create_protected_branch.html.haml' do
|
||||
element :select_allowed_to_push_dropdown
|
||||
element :allowed_to_push_dropdown
|
||||
element :allowed_to_push_dropdown_content
|
||||
element :select_allowed_to_merge_dropdown
|
||||
element :allowed_to_merge_dropdown
|
||||
element :allowed_to_merge_dropdown_content
|
||||
end
|
||||
|
||||
|
|
@ -45,7 +45,7 @@ module QA
|
|||
private
|
||||
|
||||
def select_allowed(action, allowed)
|
||||
click_element :"select_allowed_to_#{action}_dropdown"
|
||||
click_element :"allowed_to_#{action}_dropdown"
|
||||
|
||||
allowed[:roles] = Resource::ProtectedBranch::Roles::NO_ONE unless allowed.key?(:roles)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
# tagged transient due to feature-flag caching flakiness. Remove tag along with feature flag removal.
|
||||
|
||||
module QA
|
||||
RSpec.describe 'Create', feature_flag: { name: 'source_editor_toolbar', scope: :global } do
|
||||
RSpec.describe 'Create' do
|
||||
describe 'Source editor toolbar preview', product_group: :source_code do
|
||||
let(:project) do
|
||||
Resource::Project.fabricate_via_api! do |project|
|
||||
|
|
@ -13,14 +13,9 @@ module QA
|
|||
let(:edited_readme_content) { 'Here is the edited content.' }
|
||||
|
||||
before do
|
||||
Runtime::Feature.enable(:source_editor_toolbar)
|
||||
Flow::Login.sign_in
|
||||
end
|
||||
|
||||
after do
|
||||
Runtime::Feature.disable(:source_editor_toolbar)
|
||||
end
|
||||
|
||||
it 'can preview markdown side-by-side while editing',
|
||||
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/367749' do
|
||||
project.visit!
|
||||
|
|
@ -30,16 +25,11 @@ module QA
|
|||
|
||||
Page::File::Show.perform(&:click_edit)
|
||||
|
||||
# wait_until required due to feature_caching. Remove along with feature flag removal.
|
||||
Page::File::Edit.perform do |file|
|
||||
Support::Waiter.wait_until(sleep_interval: 2, max_duration: 60, reload_page: page,
|
||||
retry_on_exception: true) do
|
||||
expect(file).to have_element(:editor_toolbar_button)
|
||||
end
|
||||
file.remove_content
|
||||
file.click_editor_toolbar
|
||||
file.add_content('# ' + edited_readme_content)
|
||||
file.wait_for_markdown_preview('h1', edited_readme_content)
|
||||
file.preview
|
||||
expect(file.has_markdown_preview?('h1', edited_readme_content)).to be true
|
||||
file.commit_changes
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ RSpec.describe QA::Page::Element do
|
|||
subject { described_class.new(:something, /link_to 'something'/) }
|
||||
|
||||
it 'has an attribute[pattern] of the pattern' do
|
||||
expect(subject.attributes[:pattern]).to eq(/link_to 'something'/)
|
||||
expect(subject.attributes[:pattern]).to eq /link_to 'something'/
|
||||
end
|
||||
|
||||
it 'is not required by default' do
|
||||
|
|
@ -98,7 +98,7 @@ RSpec.describe QA::Page::Element do
|
|||
subject { described_class.new(:something, /link_to 'something_else_entirely'/, required: true) }
|
||||
|
||||
it 'has an attribute[pattern] of the passed pattern' do
|
||||
expect(subject.attributes[:pattern]).to eq(/link_to 'something_else_entirely'/)
|
||||
expect(subject.attributes[:pattern]).to eq /link_to 'something_else_entirely'/
|
||||
end
|
||||
|
||||
it 'is required' do
|
||||
|
|
@ -118,10 +118,6 @@ RSpec.describe QA::Page::Element do
|
|||
expect(subject.selector_css).to include(%q([data-qa-selector="my_element"]))
|
||||
end
|
||||
|
||||
it 'properly translates to a data-testid' do
|
||||
expect(subject.selector_css).to include(%q([data-testid="my_element"]))
|
||||
end
|
||||
|
||||
context 'additional selectors' do
|
||||
let(:element) { described_class.new(:my_element, index: 3, another_match: 'something') }
|
||||
let(:required_element) { described_class.new(:my_element, required: true, index: 3) }
|
||||
|
|
|
|||
|
|
@ -0,0 +1,49 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'User comments on a diff with whitespace changes', :js, feature_category: :code_review_workflow do
|
||||
include MergeRequestDiffHelpers
|
||||
|
||||
let_it_be(:project) { create(:project, :repository) }
|
||||
let(:merge_request) do
|
||||
create(:merge_request_with_diffs, source_project: project, target_project: project,
|
||||
source_branch: 'changes-with-whitespace')
|
||||
end
|
||||
|
||||
let(:user) { create(:user) }
|
||||
|
||||
before do
|
||||
project.add_maintainer(user)
|
||||
sign_in(user)
|
||||
|
||||
visit(diffs_project_merge_request_path(project, merge_request, view: 'parallel'))
|
||||
end
|
||||
|
||||
context 'when hiding whitespace changes' do
|
||||
before do
|
||||
find('.js-show-diff-settings').click
|
||||
find('[data-testid="show-whitespace"]').click
|
||||
wait_for_requests
|
||||
end
|
||||
|
||||
it 'allows commenting on line combinations that are not present in the real diff' do
|
||||
# Comment on line combination old: 19, new 20
|
||||
# This line combination does not exist when whitespace is shown
|
||||
click_diff_line(
|
||||
find_by_scrolling('div[data-path="files/ruby/popen.rb"] .left-side a[data-linenumber="19"]').find(:xpath,
|
||||
'../..'), 'left')
|
||||
|
||||
page.within('.js-discussion-note-form') do
|
||||
fill_in(:note_note, with: 'Comment on diff with whitespace')
|
||||
click_button('Add comment now')
|
||||
end
|
||||
|
||||
wait_for_requests
|
||||
|
||||
page.within('.notes_holder') do
|
||||
expect(page).to have_content('Comment on diff with whitespace')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
import { GlLink, GlIcon } from '@gitlab/ui';
|
||||
import { GlLink, GlIcon, GlBadge, GlTable, GlPagination } from '@gitlab/ui';
|
||||
import { sprintf } from '~/locale';
|
||||
import AgentTable from '~/clusters_list/components/agent_table.vue';
|
||||
import DeleteAgentButton from '~/clusters_list/components/delete_agent_button.vue';
|
||||
|
|
@ -17,6 +17,7 @@ const provideData = {
|
|||
};
|
||||
const defaultProps = {
|
||||
agents: clusterAgents,
|
||||
maxAgents: null,
|
||||
};
|
||||
|
||||
const DeleteAgentButtonStub = stubComponent(DeleteAgentButton, {
|
||||
|
|
@ -39,7 +40,11 @@ describe('AgentTable', () => {
|
|||
const findAgentId = (at) => wrapper.findAllByTestId('cluster-agent-id').at(at);
|
||||
const findConfiguration = (at) =>
|
||||
wrapper.findAllByTestId('cluster-agent-configuration-link').at(at);
|
||||
const findDeleteAgentButton = () => wrapper.findAllComponents(DeleteAgentButton);
|
||||
const findDeleteAgentButtons = () => wrapper.findAllComponents(DeleteAgentButton);
|
||||
const findTableRow = (at) => wrapper.findComponent(GlTable).find('tbody').findAll('tr').at(at);
|
||||
const findSharedBadgeByRow = (at) => findTableRow(at).findComponent(GlBadge);
|
||||
const findDeleteAgentButtonByRow = (at) => findTableRow(at).findComponent(DeleteAgentButton);
|
||||
const findPagination = () => wrapper.findComponent(GlPagination);
|
||||
|
||||
const createWrapper = ({ provide = provideData, propsData = defaultProps } = {}) => {
|
||||
wrapper = mountExtended(AgentTable, {
|
||||
|
|
@ -64,6 +69,11 @@ describe('AgentTable', () => {
|
|||
`('displays agent link for $agentName', ({ agentName, link, lineNumber }) => {
|
||||
expect(findAgentLink(lineNumber).text()).toBe(agentName);
|
||||
expect(findAgentLink(lineNumber).attributes('href')).toBe(link);
|
||||
expect(findSharedBadgeByRow(lineNumber).exists()).toBe(false);
|
||||
});
|
||||
|
||||
it('displays "shared" badge if the agent is shared', () => {
|
||||
expect(findSharedBadgeByRow(9).text()).toBe(I18N_AGENT_TABLE.sharedBadgeText);
|
||||
});
|
||||
|
||||
it.each`
|
||||
|
|
@ -116,8 +126,9 @@ describe('AgentTable', () => {
|
|||
},
|
||||
);
|
||||
|
||||
it('displays actions menu for each agent', () => {
|
||||
expect(findDeleteAgentButton()).toHaveLength(clusterAgents.length);
|
||||
it('displays actions menu for each agent except the shared agents', () => {
|
||||
expect(findDeleteAgentButtons()).toHaveLength(clusterAgents.length - 1);
|
||||
expect(findDeleteAgentButtonByRow(9).exists()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -132,6 +143,7 @@ describe('AgentTable', () => {
|
|||
${6} | ${'14.8.0'} | ${'15.0.0'} | ${false} | ${true} | ${outdatedTitle}
|
||||
${7} | ${'14.8.0'} | ${'15.0.0-rc1'} | ${false} | ${true} | ${outdatedTitle}
|
||||
${8} | ${'14.8.0'} | ${'14.8.10'} | ${false} | ${false} | ${''}
|
||||
${9} | ${''} | ${'14.8.0'} | ${false} | ${false} | ${''}
|
||||
`(
|
||||
'when agent version is "$agentVersion", KAS version is "$kasVersion" and version mismatch is "$versionMismatch"',
|
||||
({ agentMockIdx, agentVersion, kasVersion, versionMismatch, versionOutdated, title }) => {
|
||||
|
|
@ -181,5 +193,32 @@ describe('AgentTable', () => {
|
|||
}
|
||||
},
|
||||
);
|
||||
|
||||
describe('pagination', () => {
|
||||
it('should not render pagination buttons when there are no additional pages', () => {
|
||||
createWrapper();
|
||||
|
||||
expect(findPagination().exists()).toBe(false);
|
||||
});
|
||||
|
||||
it('should render pagination buttons when there are additional pages', () => {
|
||||
createWrapper({
|
||||
propsData: { agents: [...clusterAgents, ...clusterAgents, ...clusterAgents] },
|
||||
});
|
||||
|
||||
expect(findPagination().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('should not render pagination buttons when maxAgents is passed from the parent component', () => {
|
||||
createWrapper({
|
||||
propsData: {
|
||||
agents: [...clusterAgents, ...clusterAgents, ...clusterAgents],
|
||||
maxAgents: 6,
|
||||
},
|
||||
});
|
||||
|
||||
expect(findPagination().exists()).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { GlAlert, GlKeysetPagination, GlLoadingIcon, GlBanner } from '@gitlab/ui';
|
||||
import { GlAlert, GlLoadingIcon, GlBanner } from '@gitlab/ui';
|
||||
import { shallowMount } from '@vue/test-utils';
|
||||
import VueApollo from 'vue-apollo';
|
||||
import Vue, { nextTick } from 'vue';
|
||||
|
|
@ -19,6 +19,7 @@ Vue.use(VueApollo);
|
|||
|
||||
describe('Agents', () => {
|
||||
let wrapper;
|
||||
let testDate = new Date();
|
||||
|
||||
const defaultProps = {
|
||||
defaultBranchName: 'default',
|
||||
|
|
@ -31,9 +32,9 @@ describe('Agents', () => {
|
|||
props = {},
|
||||
glFeatures = {},
|
||||
agents = [],
|
||||
pageInfo = null,
|
||||
ciAccessAuthorizedAgentsNodes = [],
|
||||
userAccessAuthorizedAgentsNodes = [],
|
||||
trees = [],
|
||||
count = 0,
|
||||
queryResponse = null,
|
||||
}) => {
|
||||
const provide = provideData;
|
||||
|
|
@ -43,12 +44,16 @@ describe('Agents', () => {
|
|||
id: '1',
|
||||
clusterAgents: {
|
||||
nodes: agents,
|
||||
pageInfo,
|
||||
connections: { nodes: [] },
|
||||
tokens: { nodes: [] },
|
||||
count,
|
||||
},
|
||||
repository: { tree: { trees: { nodes: trees, pageInfo } } },
|
||||
ciAccessAuthorizedAgents: {
|
||||
nodes: ciAccessAuthorizedAgentsNodes,
|
||||
},
|
||||
userAccessAuthorizedAgents: {
|
||||
nodes: userAccessAuthorizedAgentsNodes,
|
||||
},
|
||||
repository: { tree: { trees: { nodes: trees } } },
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
@ -78,7 +83,6 @@ describe('Agents', () => {
|
|||
|
||||
const findAgentTable = () => wrapper.findComponent(AgentTable);
|
||||
const findEmptyState = () => wrapper.findComponent(AgentEmptyState);
|
||||
const findPaginationButtons = () => wrapper.findComponent(GlKeysetPagination);
|
||||
const findAlert = () => wrapper.findComponent(GlAlert);
|
||||
const findBanner = () => wrapper.findComponent(GlBanner);
|
||||
|
||||
|
|
@ -87,13 +91,13 @@ describe('Agents', () => {
|
|||
});
|
||||
|
||||
describe('when there is a list of agents', () => {
|
||||
let testDate = new Date();
|
||||
const agents = [
|
||||
{
|
||||
__typename: 'ClusterAgent',
|
||||
id: '1',
|
||||
name: 'agent-1',
|
||||
webPath: '/agent-1',
|
||||
createdAt: testDate,
|
||||
connections: null,
|
||||
tokens: null,
|
||||
},
|
||||
|
|
@ -102,6 +106,7 @@ describe('Agents', () => {
|
|||
id: '2',
|
||||
name: 'agent-2',
|
||||
webPath: '/agent-2',
|
||||
createdAt: testDate,
|
||||
connections: null,
|
||||
tokens: {
|
||||
nodes: [
|
||||
|
|
@ -113,8 +118,26 @@ describe('Agents', () => {
|
|||
},
|
||||
},
|
||||
];
|
||||
|
||||
const count = 2;
|
||||
const ciAccessAuthorizedAgentsNodes = [
|
||||
{
|
||||
agent: {
|
||||
__typename: 'ClusterAgent',
|
||||
id: '3',
|
||||
name: 'ci-agent-1',
|
||||
webPath: 'shared-project/agent-1',
|
||||
createdAt: testDate,
|
||||
connections: null,
|
||||
tokens: null,
|
||||
},
|
||||
},
|
||||
];
|
||||
const userAccessAuthorizedAgentsNodes = [
|
||||
{
|
||||
agent: {
|
||||
...agents[0],
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const trees = [
|
||||
{
|
||||
|
|
@ -156,10 +179,26 @@ describe('Agents', () => {
|
|||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
name: 'ci-agent-1',
|
||||
configFolder: undefined,
|
||||
webPath: 'shared-project/agent-1',
|
||||
status: 'unused',
|
||||
isShared: true,
|
||||
lastContact: null,
|
||||
connections: null,
|
||||
tokens: null,
|
||||
},
|
||||
];
|
||||
|
||||
beforeEach(() => {
|
||||
return createWrapper({ agents, count, trees });
|
||||
return createWrapper({
|
||||
agents,
|
||||
ciAccessAuthorizedAgentsNodes,
|
||||
userAccessAuthorizedAgentsNodes,
|
||||
trees,
|
||||
});
|
||||
});
|
||||
|
||||
it('should render agent table', () => {
|
||||
|
|
@ -172,7 +211,7 @@ describe('Agents', () => {
|
|||
});
|
||||
|
||||
it('should emit agents count to the parent component', () => {
|
||||
expect(wrapper.emitted().onAgentsLoad).toEqual([[count]]);
|
||||
expect(wrapper.emitted().onAgentsLoad).toEqual([[expectedAgentsList.length]]);
|
||||
});
|
||||
|
||||
describe.each`
|
||||
|
|
@ -192,7 +231,7 @@ describe('Agents', () => {
|
|||
localStorage.setItem(AGENT_FEEDBACK_KEY, true);
|
||||
}
|
||||
|
||||
return createWrapper({ glFeatures, agents, count, trees });
|
||||
return createWrapper({ glFeatures, agents, trees });
|
||||
});
|
||||
|
||||
it(`should ${bannerShown ? 'show' : 'hide'} the feedback banner`, () => {
|
||||
|
|
@ -206,7 +245,7 @@ describe('Agents', () => {
|
|||
showGitlabAgentFeedback: true,
|
||||
};
|
||||
beforeEach(() => {
|
||||
return createWrapper({ glFeatures, agents, count, trees });
|
||||
return createWrapper({ glFeatures, agents, trees });
|
||||
});
|
||||
|
||||
it('should render the correct title', () => {
|
||||
|
|
@ -238,51 +277,6 @@ describe('Agents', () => {
|
|||
expect(findAgentTable().props('agents')).toMatchObject(expectedAgentsList);
|
||||
});
|
||||
});
|
||||
|
||||
it('should not render pagination buttons when there are no additional pages', () => {
|
||||
expect(findPaginationButtons().exists()).toBe(false);
|
||||
});
|
||||
|
||||
describe('when the list has additional pages', () => {
|
||||
const pageInfo = {
|
||||
hasNextPage: true,
|
||||
hasPreviousPage: false,
|
||||
startCursor: 'prev',
|
||||
endCursor: 'next',
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
return createWrapper({
|
||||
agents,
|
||||
pageInfo: {
|
||||
...pageInfo,
|
||||
__typename: 'PageInfo',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should render pagination buttons', () => {
|
||||
expect(findPaginationButtons().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('should pass pageInfo to the pagination component', () => {
|
||||
expect(findPaginationButtons().props()).toMatchObject(pageInfo);
|
||||
});
|
||||
|
||||
describe('when limit is passed from the parent component', () => {
|
||||
beforeEach(() => {
|
||||
return createWrapper({
|
||||
props: { limit: 6 },
|
||||
agents,
|
||||
pageInfo,
|
||||
});
|
||||
});
|
||||
|
||||
it('should not render pagination buttons', () => {
|
||||
expect(findPaginationButtons().exists()).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when the agent list is empty', () => {
|
||||
|
|
@ -302,7 +296,10 @@ describe('Agents', () => {
|
|||
|
||||
describe('when agents query has errored', () => {
|
||||
beforeEach(() => {
|
||||
return createWrapper({ agents: null });
|
||||
createWrapper({
|
||||
queryResponse: jest.fn().mockRejectedValue({}),
|
||||
});
|
||||
return waitForPromises();
|
||||
});
|
||||
|
||||
it('displays an alert message', () => {
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import deleteAgentMutation from '~/clusters_list/graphql/mutations/delete_agent.
|
|||
import createMockApollo from 'helpers/mock_apollo_helper';
|
||||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
import DeleteAgentButton from '~/clusters_list/components/delete_agent_button.vue';
|
||||
import { MAX_LIST_COUNT, DELETE_AGENT_BUTTON } from '~/clusters_list/constants';
|
||||
import { DELETE_AGENT_BUTTON } from '~/clusters_list/constants';
|
||||
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
|
||||
import { getAgentResponse, mockDeleteResponse, mockErrorDeleteResponse } from '../mocks/apollo';
|
||||
|
||||
|
|
@ -16,7 +16,6 @@ Vue.use(VueApollo);
|
|||
|
||||
const projectPath = 'path/to/project';
|
||||
const defaultBranchName = 'default';
|
||||
const maxAgents = MAX_LIST_COUNT;
|
||||
const agent = {
|
||||
id: 'agent-id',
|
||||
name: 'agent-name',
|
||||
|
|
@ -53,8 +52,6 @@ describe('DeleteAgentButton', () => {
|
|||
variables: {
|
||||
projectPath,
|
||||
defaultBranchName,
|
||||
first: maxAgents,
|
||||
last: null,
|
||||
},
|
||||
data: getAgentResponse.data,
|
||||
});
|
||||
|
|
@ -71,7 +68,6 @@ describe('DeleteAgentButton', () => {
|
|||
};
|
||||
const propsData = {
|
||||
defaultBranchName,
|
||||
maxAgents,
|
||||
agent,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -205,4 +205,14 @@ export const clusterAgents = [
|
|||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'ci-agent-1',
|
||||
id: '3',
|
||||
webPath: 'shared-project/agent-1',
|
||||
status: 'inactive',
|
||||
lastContact: connectedTimeInactive.getTime(),
|
||||
isShared: true,
|
||||
connections: null,
|
||||
tokens: null,
|
||||
},
|
||||
];
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ const agent = {
|
|||
id: 'agent-id',
|
||||
name: 'agent-name',
|
||||
webPath: 'agent-webPath',
|
||||
createdAt: new Date(),
|
||||
};
|
||||
const token = {
|
||||
id: 'token-id',
|
||||
|
|
@ -14,13 +15,6 @@ const tokens = {
|
|||
const connections = {
|
||||
nodes: [],
|
||||
};
|
||||
const pageInfo = {
|
||||
endCursor: '',
|
||||
hasNextPage: false,
|
||||
hasPreviousPage: false,
|
||||
startCursor: '',
|
||||
};
|
||||
const count = 1;
|
||||
|
||||
export const createAgentResponse = {
|
||||
data: {
|
||||
|
|
@ -73,10 +67,12 @@ export const getAgentResponse = {
|
|||
project: {
|
||||
__typename: 'Project',
|
||||
id: 'project-1',
|
||||
clusterAgents: { nodes: [{ ...agent, connections, tokens }], pageInfo, count },
|
||||
clusterAgents: { nodes: [{ ...agent, connections, tokens }] },
|
||||
ciAccessAuthorizedAgents: { nodes: [] },
|
||||
userAccessAuthorizedAgents: { nodes: [] },
|
||||
repository: {
|
||||
tree: {
|
||||
trees: { nodes: [{ ...agent, path: null }], pageInfo },
|
||||
trees: { nodes: [{ ...agent, path: null }] },
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -140,6 +140,7 @@ describe('DiffsStoreUtils', () => {
|
|||
old_line: options.noteTargetLine.old_line,
|
||||
new_line: options.noteTargetLine.new_line,
|
||||
line_range: options.lineRange,
|
||||
ignore_whitespace_change: true,
|
||||
});
|
||||
|
||||
const postData = {
|
||||
|
|
@ -198,6 +199,7 @@ describe('DiffsStoreUtils', () => {
|
|||
position_type: TEXT_DIFF_POSITION_TYPE,
|
||||
old_line: options.noteTargetLine.old_line,
|
||||
new_line: options.noteTargetLine.new_line,
|
||||
ignore_whitespace_change: true,
|
||||
});
|
||||
|
||||
const postData = {
|
||||
|
|
|
|||
|
|
@ -7,12 +7,14 @@ RSpec.describe API::Entities::DraftNote, feature_category: :code_review_workflow
|
|||
let_it_be(:json) { entity.as_json }
|
||||
|
||||
it 'exposes correct attributes' do
|
||||
position = entity.position.to_h.except(:ignore_whitespace_change)
|
||||
|
||||
expect(json["id"]).to eq entity.id
|
||||
expect(json["author_id"]).to eq entity.author_id
|
||||
expect(json["merge_request_id"]).to eq entity.merge_request_id
|
||||
expect(json["resolve_discussion"]).to eq entity.resolve_discussion
|
||||
expect(json["discussion_id"]).to eq entity.discussion_id
|
||||
expect(json["note"]).to eq entity.note
|
||||
expect(json["position"].transform_keys(&:to_sym)).to eq entity.position.to_h
|
||||
expect(json["position"].transform_keys(&:to_sym)).to eq position
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -10,7 +10,8 @@ RSpec.describe Gitlab::Diff::Formatters::TextFormatter do
|
|||
head_sha: 789,
|
||||
old_path: 'old_path.txt',
|
||||
new_path: 'new_path.txt',
|
||||
line_range: nil
|
||||
line_range: nil,
|
||||
ignore_whitespace_change: false
|
||||
}
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ RSpec.describe Gitlab::Diff::PositionTracer do
|
|||
let(:project) { double }
|
||||
let(:old_diff_refs) { diff_refs }
|
||||
let(:new_diff_refs) { diff_refs }
|
||||
let(:position) { double(on_text?: on_text?, diff_refs: diff_refs) }
|
||||
let(:position) { double(on_text?: on_text?, diff_refs: diff_refs, ignore_whitespace_change: false) }
|
||||
let(:tracer) { double }
|
||||
|
||||
context 'position is on text' do
|
||||
|
|
|
|||
|
|
@ -1454,7 +1454,7 @@ RSpec.describe Gitlab::Git::Repository, feature_category: :source_code_managemen
|
|||
it "returns the number of commits in the whole repository" do
|
||||
options = { all: true }
|
||||
|
||||
expect(repository.count_commits(options)).to eq(315)
|
||||
expect(repository.count_commits(options)).to eq(316)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -160,7 +160,8 @@ RSpec.describe Gitlab::GithubImport::Importer::DiffNoteImporter, :aggregate_fail
|
|||
new_path: file_path,
|
||||
old_path: file_path,
|
||||
position_type: 'text',
|
||||
line_range: nil
|
||||
line_range: nil,
|
||||
ignore_whitespace_change: false
|
||||
})
|
||||
expect(note.note)
|
||||
.to eq <<~NOTE
|
||||
|
|
|
|||
|
|
@ -104,7 +104,8 @@ RSpec.describe Gitlab::GithubImport::Representation::DiffNote, :clean_gitlab_red
|
|||
old_line: nil,
|
||||
old_path: 'README.md',
|
||||
position_type: 'text',
|
||||
start_sha: 'start'
|
||||
start_sha: 'start',
|
||||
ignore_whitespace_change: false
|
||||
)
|
||||
end
|
||||
end
|
||||
|
|
@ -122,7 +123,8 @@ RSpec.describe Gitlab::GithubImport::Representation::DiffNote, :clean_gitlab_red
|
|||
new_line: nil,
|
||||
old_path: 'README.md',
|
||||
position_type: 'text',
|
||||
start_sha: 'start'
|
||||
start_sha: 'start',
|
||||
ignore_whitespace_change: false
|
||||
)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -153,46 +153,32 @@ RSpec.describe API::NpmGroupPackages, feature_category: :package_registry do
|
|||
end
|
||||
|
||||
describe 'GET /api/v4/packages/npm/-/package/*package_name/dist-tags' do
|
||||
let(:url) { api("/groups/#{group.id}/-/packages/npm/-/package/#{package_name}/dist-tags") }
|
||||
|
||||
subject { get(url) }
|
||||
|
||||
it_behaves_like 'returning response status', :not_found
|
||||
it_behaves_like 'handling get dist tags requests', scope: :group do
|
||||
let(:url) { api("/groups/#{group.id}/-/packages/npm/-/package/#{package_name}/dist-tags") }
|
||||
end
|
||||
end
|
||||
|
||||
describe 'PUT /api/v4/packages/npm/-/package/*package_name/dist-tags/:tag' do
|
||||
let(:tag_name) { 'test' }
|
||||
let(:headers) { build_token_auth_header(personal_access_token.token) }
|
||||
let(:url) { api("/groups/#{group.id}/-/packages/npm/-/package/#{package_name}/dist-tags/#{tag_name}") }
|
||||
|
||||
subject { put(url, headers: headers) }
|
||||
|
||||
it_behaves_like 'returning response status', :not_found
|
||||
it_behaves_like 'handling create dist tag requests', scope: :group do
|
||||
let(:url) { api("/groups/#{group.id}/-/packages/npm/-/package/#{package_name}/dist-tags/#{tag_name}") }
|
||||
end
|
||||
end
|
||||
|
||||
describe 'DELETE /api/v4/packages/npm/-/package/*package_name/dist-tags/:tag' do
|
||||
let(:tag_name) { 'test' }
|
||||
let(:headers) { build_token_auth_header(personal_access_token.token) }
|
||||
let(:url) { api("/groups/#{group.id}/-/packages/npm/-/package/#{package_name}/dist-tags/#{tag_name}") }
|
||||
|
||||
subject { delete(url, headers: headers) }
|
||||
|
||||
it_behaves_like 'returning response status', :not_found
|
||||
it_behaves_like 'handling delete dist tag requests', scope: :group do
|
||||
let(:url) { api("/groups/#{group.id}/-/packages/npm/-/package/#{package_name}/dist-tags/#{tag_name}") }
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST /api/v4/groups/:id/-/packages/npm/-/npm/v1/security/advisories/bulk' do
|
||||
let(:url) { api("/groups/#{group.id}/-/packages/npm/-/npm/v1/security/advisories/bulk") }
|
||||
|
||||
subject { post(url) }
|
||||
|
||||
it_behaves_like 'returning response status', :not_found
|
||||
it_behaves_like 'handling audit request', path: 'advisories/bulk', scope: :group do
|
||||
let(:url) { api("/groups/#{group.id}/-/packages/npm/-/npm/v1/security/advisories/bulk") }
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST /api/v4/groups/:id/-/packages/npm/-/npm/v1/security/audits/quick' do
|
||||
let(:url) { api("/groups/#{group.id}/-/packages/npm/-/npm/v1/security/audits/quick") }
|
||||
|
||||
subject { post(url) }
|
||||
|
||||
it_behaves_like 'returning response status', :not_found
|
||||
it_behaves_like 'handling audit request', path: 'audits/quick', scope: :group do
|
||||
let(:url) { api("/groups/#{group.id}/-/packages/npm/-/npm/v1/security/audits/quick") }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -93,7 +93,8 @@ module TestEnv
|
|||
'gitaly-rename-test' => '94bb47c',
|
||||
'smime-signed-commits' => 'ed775cc',
|
||||
'Ääh-test-utf-8' => '7975be0',
|
||||
'ssh-signed-commit' => '7b5160f'
|
||||
'ssh-signed-commit' => '7b5160f',
|
||||
'changes-with-whitespace' => 'f2d141fadb33ceaafc95667c1a0a308ad5edc5f9'
|
||||
}.freeze
|
||||
|
||||
# gitlab-test-fork is a fork of gitlab-fork, but we don't necessarily
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
RSpec.shared_examples 'delegates AI request to Workhorse' do |provider_flag|
|
||||
RSpec.shared_examples 'behind AI related feature flags' do |provider_flag|
|
||||
context "when #{provider_flag} is disabled" do
|
||||
before do
|
||||
stub_feature_flags(provider_flag => false)
|
||||
|
|
@ -24,7 +24,9 @@ RSpec.shared_examples 'delegates AI request to Workhorse' do |provider_flag|
|
|||
expect(response).to have_gitlab_http_status(:not_found)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
RSpec.shared_examples 'delegates AI request to Workhorse' do
|
||||
it 'responds with Workhorse send-url headers' do
|
||||
post api(url, current_user), params: input_params
|
||||
|
||||
|
|
|
|||
|
|
@ -18,10 +18,12 @@ RSpec.shared_examples 'diff discussions API' do |parent_type, noteable_type, id_
|
|||
it "returns a discussion by id" do
|
||||
get api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/discussions/#{diff_note.discussion_id}", user)
|
||||
|
||||
position = diff_note.position.to_h.except(:ignore_whitespace_change)
|
||||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(json_response['id']).to eq(diff_note.discussion_id)
|
||||
expect(json_response['notes'].first['body']).to eq(diff_note.note)
|
||||
expect(json_response['notes'].first['position']).to eq(diff_note.position.to_h.stringify_keys)
|
||||
expect(json_response['notes'].first['position']).to eq(position.stringify_keys)
|
||||
expect(json_response['notes'].first['line_range']).to eq(nil)
|
||||
end
|
||||
end
|
||||
|
|
@ -39,7 +41,7 @@ RSpec.shared_examples 'diff discussions API' do |parent_type, noteable_type, id_
|
|||
}
|
||||
}
|
||||
|
||||
position = diff_note.position.to_h.merge({ line_range: line_range })
|
||||
position = diff_note.position.to_h.merge({ line_range: line_range }).except(:ignore_whitespace_change)
|
||||
|
||||
post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/discussions", user),
|
||||
params: { body: 'hi!', position: position }
|
||||
|
|
|
|||
|
|
@ -449,7 +449,7 @@ RSpec.shared_examples 'handling audit request' do |path:, scope: :project|
|
|||
project.send("add_#{user_role}", user) if user_role
|
||||
project.update!(visibility: visibility.to_s)
|
||||
|
||||
if scope == :instance
|
||||
if %i[instance group].include?(scope)
|
||||
allow_fetch_application_setting(attribute: "npm_package_requests_forwarding", return_value: request_forward)
|
||||
else
|
||||
allow_fetch_cascade_application_setting(attribute: "npm_package_requests_forwarding", return_value: request_forward)
|
||||
|
|
@ -459,7 +459,7 @@ RSpec.shared_examples 'handling audit request' do |path:, scope: :project|
|
|||
example_name = "#{params[:expected_result]} audit request"
|
||||
status = params[:expected_status]
|
||||
|
||||
if scope == :instance && params[:expected_status] != :unauthorized
|
||||
if %i[instance group].include?(scope) && params[:expected_status] != :unauthorized
|
||||
if params[:request_forward]
|
||||
example_name = 'redirect audit request'
|
||||
status = :temporary_redirect
|
||||
|
|
@ -638,6 +638,8 @@ RSpec.shared_examples 'handling get dist tags requests' do |scope: :project|
|
|||
status = :not_found
|
||||
end
|
||||
|
||||
status = :not_found if scope == :group && params[:package_name_type] == :non_existing
|
||||
|
||||
it_behaves_like example_name, status: status
|
||||
end
|
||||
end
|
||||
|
|
@ -854,6 +856,8 @@ RSpec.shared_examples 'handling different package names, visibilities and user r
|
|||
status = params[:auth].nil? ? :unauthorized : :not_found
|
||||
end
|
||||
|
||||
status = :not_found if scope == :group && params[:package_name_type] == :non_existing && params[:auth].present?
|
||||
|
||||
it_behaves_like example_name, status: status
|
||||
end
|
||||
end
|
||||
|
|
|
|||