Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
fb4d571aaf
commit
04a542b641
|
|
@ -164,7 +164,7 @@ Dangerfile
|
|||
/config/upgrade_path.yml
|
||||
|
||||
# Secure & Threat Management ownership delineation
|
||||
# https://about.gitlab.com/handbook/engineering/development/threat-management/delineate-secure-threat-management.html#technical-boundaries
|
||||
# https://handbook.gitlab.com/handbook/engineering/development/sec/delineate-sec/#technical-boundaries
|
||||
^[Threat Insights backend] @gitlab-org/govern/threat-insights-backend-team
|
||||
/development/sec/cyclonedx_property_taxonomy.md
|
||||
/app/finders/security/
|
||||
|
|
@ -181,6 +181,17 @@ Dangerfile
|
|||
/ee/spec/policies/vulnerabilities/
|
||||
/ee/spec/policies/vulnerability*.rb
|
||||
|
||||
^[Threat Insights frontend] @gitlab-org/govern/threat-insights-frontend-team
|
||||
/app/assets/javascripts/vue_merge_request_widget/widgets/security_reports/**
|
||||
/ee/app/assets/javascripts/vue_merge_request_widget/widgets/security_reports/**
|
||||
/ee/app/assets/javascripts/security_dashboard/**
|
||||
/ee/spec/frontend/security_dashboard/**
|
||||
/ee/app/assets/javascripts/vulnerabilities/**
|
||||
/spec/frontend/vue_merge_request_widget/widgets/security_reports/**
|
||||
/ee/spec/frontend/vue_merge_request_widget/widgets/security_reports/**
|
||||
/ee/app/assets/javascripts/dependencies/**
|
||||
/ee/spec/frontend/dependencies/**
|
||||
|
||||
^[Composition Analysis backend] @gitlab-org/secure/composition-analysis-be
|
||||
/app/events/package_metadata/
|
||||
/app/models/concerns/enums/package_metadata.rb
|
||||
|
|
|
|||
|
|
@ -116,7 +116,6 @@ Database/AvoidUsingPluckWithoutLimit:
|
|||
- 'ee/app/models/ee/project_group_link.rb'
|
||||
- 'ee/app/models/ee/projects/wiki_repository.rb'
|
||||
- 'ee/app/models/ee/uploads/local.rb'
|
||||
- 'ee/app/models/ee/user.rb'
|
||||
- 'ee/app/models/embedding/application_record.rb'
|
||||
- 'ee/app/models/geo/base_registry.rb'
|
||||
- 'ee/app/models/geo/container_repository_registry.rb'
|
||||
|
|
|
|||
|
|
@ -208,7 +208,6 @@ Style/RedundantSelf:
|
|||
- 'ee/lib/elastic/instance_proxy_util.rb'
|
||||
- 'ee/lib/elastic/latest/commit_config.rb'
|
||||
- 'ee/lib/elastic/latest/issue_config.rb'
|
||||
- 'ee/lib/elastic/latest/merge_request_config.rb'
|
||||
- 'ee/lib/elastic/latest/note_config.rb'
|
||||
- 'ee/lib/elastic/migration.rb'
|
||||
- 'ee/lib/gem_extensions/elasticsearch/model/indexing/instance_methods.rb'
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
<script>
|
||||
import {
|
||||
GlAvatar,
|
||||
GlButton,
|
||||
GlButtonGroup,
|
||||
GlLabel,
|
||||
|
|
@ -40,7 +39,6 @@ export default {
|
|||
),
|
||||
},
|
||||
components: {
|
||||
GlAvatar,
|
||||
GlButton,
|
||||
GlButtonGroup,
|
||||
GlLabel,
|
||||
|
|
@ -361,18 +359,17 @@ export default {
|
|||
'gl-mt-3 gl-rotate-90': list.collapsed,
|
||||
}"
|
||||
>
|
||||
<gl-avatar
|
||||
<img
|
||||
v-gl-tooltip.hover.bottom
|
||||
:title="listAssignee"
|
||||
:label="list.assignee.name"
|
||||
:alt="list.assignee.name"
|
||||
:src="list.assignee.avatarUrl"
|
||||
:entity-name="list.assignee.name"
|
||||
:size="24"
|
||||
class="gl-mr-3"
|
||||
class="avatar s20"
|
||||
height="20"
|
||||
width="20"
|
||||
/>
|
||||
</a>
|
||||
<!-- EE end -->
|
||||
|
||||
<div
|
||||
class="board-title-text"
|
||||
:class="{
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<script>
|
||||
import { GlButton, GlIcon, GlLink, GlTooltip } from '@gitlab/ui';
|
||||
import { GlButton, GlLink, GlTooltip } from '@gitlab/ui';
|
||||
import { createAlert } from '~/alert';
|
||||
import { __, s__, sprintf } from '~/locale';
|
||||
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
|
||||
|
|
@ -12,7 +12,6 @@ export default {
|
|||
components: {
|
||||
CiIcon,
|
||||
GlButton,
|
||||
GlIcon,
|
||||
GlLink,
|
||||
GlTooltip,
|
||||
},
|
||||
|
|
@ -27,31 +26,19 @@ export default {
|
|||
},
|
||||
data() {
|
||||
return {
|
||||
isHovered: false,
|
||||
isJobLogVisible: false,
|
||||
isLoadingAction: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
canReadBuild() {
|
||||
return this.job.userPermissions.readBuild;
|
||||
},
|
||||
canRetryJob() {
|
||||
return this.job.retryable && this.job.userPermissions.updateBuild && !this.isBridgeJob;
|
||||
},
|
||||
detailsPath() {
|
||||
return this.job?.detailedStatus?.detailsPath;
|
||||
},
|
||||
isBridgeJob() {
|
||||
return this.job.kind === BRIDGE_KIND;
|
||||
},
|
||||
jobChevronName() {
|
||||
return this.isJobLogVisible ? 'chevron-down' : 'chevron-right';
|
||||
},
|
||||
jobTrace() {
|
||||
if (this.canReadBuild) {
|
||||
return this.job?.trace?.htmlSummary || this.$options.i18n.noTraceText;
|
||||
}
|
||||
|
||||
return this.$options.i18n.cannotReadBuild;
|
||||
},
|
||||
parsedJobId() {
|
||||
return getIdFromGraphQLId(this.job.id);
|
||||
},
|
||||
|
|
@ -65,12 +52,6 @@ export default {
|
|||
},
|
||||
},
|
||||
methods: {
|
||||
setActiveRow() {
|
||||
this.isHovered = true;
|
||||
},
|
||||
resetActiveRow() {
|
||||
this.isHovered = false;
|
||||
},
|
||||
async retryJob() {
|
||||
try {
|
||||
this.isLoadingAction = true;
|
||||
|
|
@ -95,47 +76,34 @@ export default {
|
|||
this.isLoadingAction = false;
|
||||
}
|
||||
},
|
||||
toggleJobLog(event) {
|
||||
// Do not toggle the log visibility when clicking on a link
|
||||
if (event.target.tagName === 'A') {
|
||||
return;
|
||||
}
|
||||
this.isJobLogVisible = !this.isJobLogVisible;
|
||||
},
|
||||
},
|
||||
i18n: {
|
||||
cannotReadBuild: s__("Job|You do not have permission to read this job's log."),
|
||||
cannotRetry: s__('Job|You do not have permission to run this job again.'),
|
||||
cannotRetryTrigger: s__('Job|You cannot rerun trigger jobs from this list.'),
|
||||
jobActionTooltipText: s__('Pipelines|Retry %{jobName} Job'),
|
||||
noTraceText: s__('Job|No job log'),
|
||||
retry: __('Retry'),
|
||||
retryError: __('There was an error while retrying this job'),
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<div class="container-fluid gl-grid-rows-auto">
|
||||
<div
|
||||
class="row gl-my-3 gl-flex gl-cursor-pointer gl-items-center"
|
||||
:aria-pressed="isJobLogVisible"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
data-testid="widget-row"
|
||||
@click="toggleJobLog"
|
||||
@keyup.enter="toggleJobLog"
|
||||
@keyup.space="toggleJobLog"
|
||||
@mouseover="setActiveRow"
|
||||
@mouseout="resetActiveRow"
|
||||
>
|
||||
<div class="col-6 gl-text-left gl-font-bold gl-text-gray-900">
|
||||
<gl-icon :name="jobChevronName" />
|
||||
<div class="container-fluid gl-my-1 gl-grid-rows-auto">
|
||||
<div class="row gl-flex gl-items-center" data-testid="widget-row">
|
||||
<div class="align-items-center col-6 gl-flex gl-font-bold gl-text-gray-900">
|
||||
<ci-icon :status="job.detailedStatus" />
|
||||
{{ job.name }}
|
||||
<gl-link
|
||||
class="gl-ml-2 !gl-text-gray-900 !gl-no-underline"
|
||||
:href="detailsPath"
|
||||
data-testid="job-name-link"
|
||||
>{{ job.name }}</gl-link
|
||||
>
|
||||
</div>
|
||||
<div class="col-2 gl-text-left">{{ job.stage.name }}</div>
|
||||
<div class="col-2 gl-text-left">
|
||||
<gl-link :href="job.detailedStatus.detailsPath">#{{ parsedJobId }}</gl-link>
|
||||
<div class="col-2 gl-flex gl-items-center" data-testid="job-stage-name">
|
||||
{{ job.stage.name }}
|
||||
</div>
|
||||
<div class="col-2 gl-flex gl-items-center">
|
||||
<gl-link :href="detailsPath" data-testid="job-id-link">#{{ parsedJobId }}</gl-link>
|
||||
</div>
|
||||
<gl-tooltip v-if="!canRetryJob" :target="() => $refs.retryBtn" placement="top">
|
||||
{{ tooltipErrorText }}
|
||||
|
|
@ -155,12 +123,5 @@ export default {
|
|||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="isJobLogVisible" class="row">
|
||||
<pre
|
||||
v-safe-html="jobTrace"
|
||||
class="gl-w-full gl-bg-gray-900 gl-text-white"
|
||||
data-testid="job-log"
|
||||
></pre>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -154,7 +154,7 @@ export default {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<div class="gl-mb-4">
|
||||
<gl-loading-icon v-if="isInitialLoading" class="gl-p-4" />
|
||||
<div v-else-if="!hasFailedJobs" class="gl-p-4">{{ $options.i18n.noFailedJobs }}</div>
|
||||
<div v-else class="container-fluid gl-grid-rows-auto">
|
||||
|
|
@ -162,7 +162,7 @@ export default {
|
|||
<div
|
||||
v-for="col in $options.columns"
|
||||
:key="col.text"
|
||||
class="gl-text-left gl-font-bold"
|
||||
class="gl-flex gl-font-bold"
|
||||
:class="col.class"
|
||||
data-testid="header"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -90,6 +90,7 @@ export default {
|
|||
class="expandable-card"
|
||||
:class="{ 'is-collapsed gl-border-white hover:gl-border-gray-100': !isExpanded }"
|
||||
data-testid="failed-jobs-card"
|
||||
@click="toggleWidget"
|
||||
>
|
||||
<template #title>
|
||||
<gl-button
|
||||
|
|
|
|||
|
|
@ -28,9 +28,6 @@ query getPipelineFailedJobs($fullPath: ID!, $pipelineIid: ID!) {
|
|||
id
|
||||
name
|
||||
}
|
||||
trace {
|
||||
htmlSummary
|
||||
}
|
||||
userPermissions {
|
||||
readBuild
|
||||
updateBuild
|
||||
|
|
|
|||
|
|
@ -125,7 +125,7 @@ export default {
|
|||
:img-src="authorAvatar"
|
||||
:img-alt="authorName"
|
||||
:img-size="32"
|
||||
class="gl-my-2 gl-mr-4 gl-hidden gl-self-start sm:gl-block"
|
||||
class="avatar-cell gl-my-2 gl-mr-4 gl-hidden sm:gl-block"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
|
|
|
|||
|
|
@ -110,9 +110,9 @@ export function membersBeforeSave(members) {
|
|||
|
||||
const autoCompleteAvatar = member.avatar_url || member.username.charAt(0).toUpperCase();
|
||||
|
||||
const avatarShapeClass = member.type === GROUP_TYPE ? '' : 'gl-avatar-circle';
|
||||
const imgAvatar = `<img src="${member.avatar_url}" alt="${member.username}" class="gl-avatar gl-avatar-s24 gl-mr-2 ${avatarShapeClass}"/>`;
|
||||
const txtAvatar = `<div class="gl-avatar gl-avatar-s24 gl-mr-2 gl-justify-center gl-items-center ${avatarShapeClass}">${autoCompleteAvatar}</div>`;
|
||||
const rectAvatarClass = member.type === GROUP_TYPE ? 'rect-avatar' : '';
|
||||
const imgAvatar = `<img src="${member.avatar_url}" alt="${member.username}" class="avatar ${rectAvatarClass} avatar-inline s24 gl-mr-2"/>`;
|
||||
const txtAvatar = `<div class="avatar ${rectAvatarClass} avatar-inline s24 gl-mr-2">${autoCompleteAvatar}</div>`;
|
||||
const avatarIcon = member.mentionsDisabled
|
||||
? spriteIcon('notifications-off', 's16 vertical-align-middle gl-ml-2')
|
||||
: '';
|
||||
|
|
|
|||
|
|
@ -1,11 +1,10 @@
|
|||
<script>
|
||||
import { GlAvatar, GlIcon } from '@gitlab/ui';
|
||||
import { GlIcon } from '@gitlab/ui';
|
||||
import { TYPE_ISSUE, TYPE_MERGE_REQUEST } from '~/issues/constants';
|
||||
import { __, sprintf } from '~/locale';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
GlAvatar,
|
||||
GlIcon,
|
||||
},
|
||||
props: {
|
||||
|
|
@ -44,12 +43,13 @@ export default {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<span class="gl-relative">
|
||||
<gl-avatar
|
||||
:label="user.name"
|
||||
:src="avatarUrl"
|
||||
:size="imgSize"
|
||||
<span class="position-relative">
|
||||
<img
|
||||
:alt="assigneeAlt"
|
||||
:src="avatarUrl"
|
||||
:width="imgSize"
|
||||
:class="`s${imgSize}`"
|
||||
class="avatar avatar-inline m-0"
|
||||
data-testid="avatar-image"
|
||||
/>
|
||||
<gl-icon v-if="hasMergeIcon" name="warning-solid" aria-hidden="true" class="merge-icon" />
|
||||
|
|
|
|||
|
|
@ -1,12 +1,11 @@
|
|||
<script>
|
||||
// NOTE! For the first iteration, we are simply copying the implementation of Assignees
|
||||
// It will soon be overhauled in Issue https://gitlab.com/gitlab-org/gitlab/-/issues/233736
|
||||
import { GlAvatar, GlIcon } from '@gitlab/ui';
|
||||
import { GlIcon } from '@gitlab/ui';
|
||||
import { __, sprintf } from '~/locale';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
GlAvatar,
|
||||
GlIcon,
|
||||
},
|
||||
props: {
|
||||
|
|
@ -34,8 +33,14 @@ export default {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<span class="gl-relative">
|
||||
<gl-avatar :label="user.name" :src="avatarUrl" :size="imgSize" :alt="reviewerAlt" />
|
||||
<span class="position-relative">
|
||||
<img
|
||||
:alt="reviewerAlt"
|
||||
:src="avatarUrl"
|
||||
:width="imgSize"
|
||||
:class="`s${imgSize}`"
|
||||
class="avatar avatar-inline m-0"
|
||||
/>
|
||||
<gl-icon
|
||||
v-if="hasMergeIcon"
|
||||
name="warning-solid"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
query getTokenAccessGroupsAndProjects($search: String) {
|
||||
groups(search: $search, first: 4) {
|
||||
groups(search: $search, sort: "id_asc", first: 10) {
|
||||
nodes {
|
||||
id
|
||||
name
|
||||
|
|
@ -7,7 +7,7 @@ query getTokenAccessGroupsAndProjects($search: String) {
|
|||
fullPath
|
||||
}
|
||||
}
|
||||
projects(search: $search, first: 4) {
|
||||
projects(search: $search, sort: "id_asc", first: 10) {
|
||||
nodes {
|
||||
id
|
||||
name
|
||||
|
|
|
|||
|
|
@ -252,12 +252,12 @@ function UsersSelect(currentUser, els, options = {}) {
|
|||
});
|
||||
};
|
||||
collapsedAssigneeTemplate = template(
|
||||
`<% if( avatar ) { %> <a class="author-link" href="/<%- username %>"> <img width="24" class="gl-avatar gl-avatar-circle gl-avatar-s24" alt="" src="<%- avatar %>"> </a> <% } else { %> ${spriteIcon(
|
||||
`<% if( avatar ) { %> <a class="author-link" href="/<%- username %>"> <img width="24" class="avatar avatar-inline s24" alt="" src="<%- avatar %>"> </a> <% } else { %> ${spriteIcon(
|
||||
'user',
|
||||
)} <% } %>`,
|
||||
);
|
||||
assigneeTemplate = template(
|
||||
`<% if (username) { %> <a class="author-link gl-font-bold" href="/<%- username %>"> <% if( avatar ) { %> <img width="32" class="gl-avatar gl-avatar-circle gl-avatar-s32" alt="" src="<%- avatar %>"> <% } %> <span class="author"><%- name %></span> <span class="username"> @<%- username %> </span> </a> <% } else { %> <span class="no-value assign-yourself">
|
||||
`<% if (username) { %> <a class="author-link gl-font-bold" href="/<%- username %>"> <% if( avatar ) { %> <img width="32" class="avatar avatar-inline s32" alt="" src="<%- avatar %>"> <% } %> <span class="author"><%- name %></span> <span class="username"> @<%- username %> </span> </a> <% } else { %> <span class="no-value assign-yourself">
|
||||
${sprintf(s__('UsersSelect|No assignee - %{openingTag} assign yourself %{closingTag}'), {
|
||||
openingTag: '<a href="#" class="js-assign-yourself">',
|
||||
closingTag: '</a>',
|
||||
|
|
@ -637,7 +637,7 @@ function UsersSelect(currentUser, els, options = {}) {
|
|||
)}</a></li>`;
|
||||
} else {
|
||||
// 0 margin, because it's now handled by a wrapper
|
||||
img = `<img src='${avatar}' class='gl-avatar gl-avatar-circle gl-avatar-s32 !gl-m-0' width='32' />`;
|
||||
img = `<img src='${avatar}' class='avatar avatar-inline !gl-m-0' width='32' />`;
|
||||
}
|
||||
|
||||
return userSelect.renderRow(
|
||||
|
|
|
|||
|
|
@ -1,10 +1,9 @@
|
|||
<script>
|
||||
import { GlAvatar, GlTooltipDirective, GlLink } from '@gitlab/ui';
|
||||
import { GlTooltipDirective, GlLink } from '@gitlab/ui';
|
||||
|
||||
export default {
|
||||
name: 'MrWidgetAuthor',
|
||||
components: {
|
||||
GlAvatar,
|
||||
GlLink,
|
||||
},
|
||||
directives: {
|
||||
|
|
@ -38,9 +37,9 @@ export default {
|
|||
:title="showAuthorName ? null : author.name"
|
||||
class="mr-widget-author"
|
||||
>
|
||||
<gl-avatar :src="avatarUrl" :size="16" :alt="author.name" /><span
|
||||
<img :src="avatarUrl" :alt="author.name" class="avatar avatar-inline s16" /><span
|
||||
v-if="showAuthorName"
|
||||
class="author gl-ml-2"
|
||||
class="author"
|
||||
>{{ author.name }}</span
|
||||
>
|
||||
</gl-link>
|
||||
|
|
|
|||
|
|
@ -124,7 +124,7 @@ export default {
|
|||
v-gl-tooltip
|
||||
:title="collapsed ? expandDetailsTooltip : collapseDetailsTooltip"
|
||||
:aria-label="collapsed ? expandDetailsTooltip : collapseDetailsTooltip"
|
||||
:icon="collapsed ? 'chevron-lg-down' : 'chevron-lg-up'"
|
||||
:icon="collapsed ? 'chevron-down' : 'chevron-up'"
|
||||
category="tertiary"
|
||||
size="small"
|
||||
class="gl-align-top"
|
||||
|
|
|
|||
|
|
@ -382,7 +382,7 @@ export default {
|
|||
:title="collapseButtonLabel"
|
||||
:aria-expanded="`${!isCollapsed}`"
|
||||
:aria-label="collapseButtonLabel"
|
||||
:icon="isCollapsed ? 'chevron-lg-down' : 'chevron-lg-up'"
|
||||
:icon="isCollapsed ? 'chevron-down' : 'chevron-up'"
|
||||
category="tertiary"
|
||||
data-testid="toggle-button"
|
||||
size="small"
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ import {
|
|||
GlTooltip,
|
||||
GlButton,
|
||||
GlSprintf,
|
||||
GlAvatar,
|
||||
} from '@gitlab/ui';
|
||||
import { debounce } from 'lodash';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
|
|
@ -44,7 +43,6 @@ export default {
|
|||
GlTooltip,
|
||||
GlButton,
|
||||
GlSprintf,
|
||||
GlAvatar,
|
||||
SidebarAssignee,
|
||||
},
|
||||
props: {
|
||||
|
|
@ -284,7 +282,7 @@ export default {
|
|||
>
|
||||
<div v-if="userName" class="gl-mt-2 gl-inline-flex" data-testid="assigned-users">
|
||||
<span class="gl-relative gl-mr-4">
|
||||
<gl-avatar :src="userImg" :size="32" :alt="userName" />
|
||||
<img :alt="userName" :src="userImg" :width="32" class="avatar avatar-inline s32 gl-m-0" />
|
||||
</span>
|
||||
<span class="gl-flex gl-flex-col gl-overflow-hidden">
|
||||
<strong class="dropdown-menu-user-full-name">
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ export default {
|
|||
return !(hasContent && this.isCollapsible && this.collapsed);
|
||||
},
|
||||
toggleIcon() {
|
||||
return this.collapsed ? 'chevron-lg-down' : 'chevron-lg-up';
|
||||
return this.collapsed ? 'chevron-down' : 'chevron-up';
|
||||
},
|
||||
toggleLabel() {
|
||||
return this.collapsed ? __('Expand') : __('Collapse');
|
||||
|
|
|
|||
|
|
@ -1,8 +1,86 @@
|
|||
// Left over of avatar. Still used in email templates.
|
||||
.avatar {
|
||||
$avatar-sizes: (
|
||||
16: (
|
||||
font-size: 10px,
|
||||
line-height: 16px,
|
||||
border-radius: $border-radius-small
|
||||
),
|
||||
18: (
|
||||
border-radius: $border-radius-small
|
||||
),
|
||||
20: (
|
||||
border-radius: $border-radius-small
|
||||
),
|
||||
24: (
|
||||
font-size: 12px,
|
||||
line-height: 24px,
|
||||
border-radius: $gl-border-radius-base
|
||||
),
|
||||
26: (
|
||||
font-size: 20px,
|
||||
line-height: 1.33,
|
||||
border-radius: $gl-border-radius-base
|
||||
),
|
||||
32: (
|
||||
font-size: 14px,
|
||||
line-height: 32px,
|
||||
border-radius: $gl-border-radius-base
|
||||
),
|
||||
40: (
|
||||
font-size: 16px,
|
||||
line-height: 38px,
|
||||
border-radius: $gl-border-radius-base
|
||||
),
|
||||
48: (
|
||||
font-size: 20px,
|
||||
line-height: 48px,
|
||||
border-radius: $border-radius-large
|
||||
),
|
||||
60: (
|
||||
font-size: 32px,
|
||||
line-height: 60px,
|
||||
border-radius: $border-radius-large
|
||||
),
|
||||
64: (
|
||||
font-size: 28px,
|
||||
line-height: 64px,
|
||||
border-radius: $border-radius-large
|
||||
),
|
||||
90: (
|
||||
font-size: 36px,
|
||||
line-height: 90px,
|
||||
border-radius: $border-radius-large
|
||||
),
|
||||
96: (
|
||||
font-size: 36px,
|
||||
line-height: 94px,
|
||||
border-radius: $border-radius-large
|
||||
),
|
||||
100: (
|
||||
font-size: 36px,
|
||||
line-height: 98px,
|
||||
border-radius: $border-radius-large
|
||||
),
|
||||
160: (
|
||||
font-size: 96px,
|
||||
line-height: 158px,
|
||||
border-radius: $border-radius-large
|
||||
)
|
||||
);
|
||||
|
||||
.avatar,
|
||||
.avatar-container {
|
||||
float: left;
|
||||
margin-right: $gl-padding;
|
||||
border-radius: $avatar-radius;
|
||||
|
||||
@each $size, $size-config in $avatar-sizes {
|
||||
&.s#{$size} {
|
||||
@include avatar-size(#{$size}px, if($size < 48, 8px, 16px));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.avatar {
|
||||
transition-property: none;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
|
|
@ -11,6 +89,18 @@
|
|||
overflow: hidden;
|
||||
box-shadow: inset 0 0 0 1px var(--gl-avatar-border-color-default);
|
||||
|
||||
&.avatar-inline {
|
||||
float: none;
|
||||
display: inline-block;
|
||||
margin-left: 2px;
|
||||
flex-shrink: 0;
|
||||
|
||||
&.s16,
|
||||
&.s24 {
|
||||
margin-right: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
&.center {
|
||||
font-size: 14px;
|
||||
line-height: 1.8em;
|
||||
|
|
@ -23,6 +113,80 @@
|
|||
}
|
||||
}
|
||||
|
||||
.identicon {
|
||||
text-align: center;
|
||||
vertical-align: top;
|
||||
color: var(--gl-text-color-strong);
|
||||
background-color: var(--gl-avatar-fallback-background-color-neutral);
|
||||
|
||||
// Sizes
|
||||
@each $size, $size-config in $avatar-sizes {
|
||||
$keys: map-keys($size-config);
|
||||
|
||||
&.s#{$size} {
|
||||
@each $key in $keys {
|
||||
// We don't want `border-radius` to be included here.
|
||||
@if ($key != 'border-radius') {
|
||||
#{$key}: map-get($size-config, #{$key});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Background colors
|
||||
@for $i from 1 through length($gl-avatar-identicon-bgs) {
|
||||
&.bg#{$i} {
|
||||
color: nth($gl-avatar-identicon-texts, $i);
|
||||
background-color: nth($gl-avatar-identicon-bgs, $i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.avatar-container {
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
|
||||
a {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
border-radius: 0;
|
||||
border: 0;
|
||||
height: auto;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
&.s40 {
|
||||
min-width: 40px;
|
||||
min-height: 40px;
|
||||
}
|
||||
|
||||
&.s64 {
|
||||
min-width: 64px;
|
||||
min-height: 64px;
|
||||
}
|
||||
}
|
||||
|
||||
.rect-avatar {
|
||||
border-radius: $border-radius-small;
|
||||
|
||||
@each $size, $size-config in $avatar-sizes {
|
||||
&.s#{$size} {
|
||||
border-radius: map-get($size-config, 'border-radius');
|
||||
|
||||
.avatar {
|
||||
border-radius: map-get($size-config, 'border-radius');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.avatar-counter {
|
||||
@include avatar-counter();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -505,10 +505,6 @@
|
|||
top: calc(50% + 5px);
|
||||
left: 3rem;
|
||||
}
|
||||
|
||||
.gl-avatar {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -164,6 +164,10 @@ ul.content-list {
|
|||
.badge-secondary {
|
||||
color: $gl-text-color-secondary;
|
||||
}
|
||||
|
||||
.avatar-cell {
|
||||
align-self: flex-start;
|
||||
}
|
||||
}
|
||||
|
||||
ul.content-list.content-list-items-padding > li,
|
||||
|
|
@ -190,6 +194,14 @@ ul.controls {
|
|||
&:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.author-link {
|
||||
.avatar-inline {
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.issuable-pipeline-broken a,
|
||||
|
|
|
|||
|
|
@ -172,6 +172,16 @@
|
|||
.gl-tabs-nav li a.gl-tab-nav-item-active {
|
||||
box-shadow: inset 0 -2px 0 0 var(--ide-highlight-accent, $gl-text-color);
|
||||
}
|
||||
|
||||
// for other themes, suppress different avatar default colors for simplicity
|
||||
.avatar-container {
|
||||
&,
|
||||
.avatar {
|
||||
color: var(--ide-text-color, $gl-text-color);
|
||||
background-color: var(--ide-highlight-background, $white);
|
||||
border-color: var(--ide-highlight-background, rgba($black, $gl-avatar-border-opacity));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
input[type='text'],
|
||||
|
|
|
|||
|
|
@ -11,10 +11,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
.home-panel-metadata {
|
||||
line-height: $gl-btn-line-height;
|
||||
}
|
||||
|
||||
.home-panel-description {
|
||||
@include media-breakpoint-up(md) {
|
||||
font-size: $gl-font-size-large;
|
||||
|
|
|
|||
|
|
@ -863,6 +863,11 @@ $ide-commit-header-height: 48px;
|
|||
}
|
||||
|
||||
.ide-context-header {
|
||||
.avatar-container {
|
||||
flex: 0 0 auto;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.ide-sidebar-project-title {
|
||||
margin-left: $ide-tree-text-start - $ide-project-avatar-end;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,15 +46,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
.user-item {
|
||||
padding: 5px;
|
||||
flex-basis: 20%;
|
||||
|
||||
.user-link {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
|
||||
.issuable-gutter-toggle {
|
||||
@include media-breakpoint-down(sm) {
|
||||
margin-left: $btn-side-margin;
|
||||
|
|
|
|||
|
|
@ -376,6 +376,16 @@
|
|||
table-layout: fixed;
|
||||
}
|
||||
|
||||
.avatar-container {
|
||||
@include avatar-size(40px, 10px);
|
||||
min-height: 40px;
|
||||
min-width: 40px;
|
||||
|
||||
.identicon.s48 {
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.updated-note {
|
||||
@include media-breakpoint-up(sm) {
|
||||
margin-top: $gl-spacing-scale-2;
|
||||
|
|
|
|||
|
|
@ -140,6 +140,15 @@ table.pipeline-project-metrics tr td {
|
|||
flex-basis: 100%;
|
||||
}
|
||||
|
||||
.avatar-container {
|
||||
flex-shrink: 0;
|
||||
|
||||
> a {
|
||||
width: 100%;
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: $gl-font-size;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -65,6 +65,7 @@
|
|||
}
|
||||
|
||||
.gl-avatar:not(.gl-avatar-identicon),
|
||||
.avatar-container,
|
||||
.avatar {
|
||||
background: rgba($gray-950, 0.04);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,10 @@
|
|||
margin-top: $gl-spacing-scale-2;
|
||||
}
|
||||
|
||||
.avatar-inline {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.has-warning {
|
||||
.description {
|
||||
color: $gray-900;
|
||||
|
|
|
|||
|
|
@ -476,6 +476,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
|
|||
def get_diffs_count
|
||||
return @merge_request.context_commits_diff.raw_diffs.size if show_only_context_commits?
|
||||
return @merge_request.merge_request_diffs.find_by_id(params[:diff_id])&.size if params[:diff_id]
|
||||
return @merge_request.merge_head_diff.size if @merge_request.diffable_merge_ref? && params[:start_sha].blank?
|
||||
|
||||
@merge_request.diff_size
|
||||
end
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ module Projects
|
|||
|
||||
# overridden in EE
|
||||
def permitted_project_params
|
||||
{
|
||||
[
|
||||
incident_management_setting_attributes: ::Gitlab::Tracking::IncidentManagement.tracking_keys.keys,
|
||||
|
||||
error_tracking_setting_attributes: [
|
||||
|
|
@ -128,7 +128,7 @@ module Projects
|
|||
:token,
|
||||
{ project: [:slug, :name, :organization_slug, :organization_name, :sentry_project_id] }
|
||||
]
|
||||
}
|
||||
]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -7,6 +7,14 @@ module Resolvers
|
|||
|
||||
type ::Types::Ci::JobType.connection_type, null: true
|
||||
|
||||
argument :job_kind, ::Types::Ci::JobKindEnum,
|
||||
required: false,
|
||||
description: 'Filter jobs by kind.'
|
||||
|
||||
argument :retried, ::GraphQL::Types::Boolean,
|
||||
required: false,
|
||||
description: 'Filter jobs by retry-status.'
|
||||
|
||||
argument :security_report_types, [Types::Security::ReportTypeEnum],
|
||||
required: false,
|
||||
description: 'Filter jobs by the type of security report they produce.'
|
||||
|
|
@ -15,25 +23,22 @@ module Resolvers
|
|||
required: false,
|
||||
description: 'Filter jobs by status.'
|
||||
|
||||
argument :retried, ::GraphQL::Types::Boolean,
|
||||
required: false,
|
||||
description: 'Filter jobs by retry-status.'
|
||||
|
||||
argument :when_executed, [::GraphQL::Types::String],
|
||||
required: false,
|
||||
description: 'Filter jobs by when they are executed.'
|
||||
|
||||
argument :job_kind, ::Types::Ci::JobKindEnum,
|
||||
required: false,
|
||||
description: 'Filter jobs by kind.'
|
||||
|
||||
def resolve(statuses: nil, security_report_types: [], retried: nil, when_executed: nil, job_kind: nil)
|
||||
def resolve(
|
||||
job_kind: nil,
|
||||
retried: nil,
|
||||
security_report_types: [],
|
||||
statuses: nil,
|
||||
when_executed: nil)
|
||||
jobs = init_collection(security_report_types)
|
||||
jobs = jobs.with_status(statuses) if statuses.present?
|
||||
jobs = jobs.retried if retried
|
||||
jobs = jobs.with_when_executed(when_executed) if when_executed.present?
|
||||
jobs = jobs.latest if retried == false
|
||||
jobs = jobs.retried if retried
|
||||
jobs = jobs.with_status(statuses) if statuses.present?
|
||||
jobs = jobs.with_type(job_kind) if job_kind
|
||||
jobs = jobs.with_when_executed(when_executed) if when_executed.present?
|
||||
|
||||
jobs
|
||||
end
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ module AvatarsHelper
|
|||
|
||||
has_tooltip = options[:has_tooltip].nil? ? true : options[:has_tooltip]
|
||||
data_attributes = options[:data] || {}
|
||||
css_class = %W[gl-avatar gl-avatar-circle gl-avatar-s#{avatar_size}].push(*options[:css_class])
|
||||
css_class = %W[avatar s#{avatar_size}].push(*options[:css_class])
|
||||
alt_text = user_name ? "#{user_name}'s avatar" : "default avatar"
|
||||
|
||||
if has_tooltip
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ module ProjectsHelper
|
|||
default_opts = { size: 16 }
|
||||
opts = default_opts.merge(opts)
|
||||
|
||||
classes = %W[gl-avatar gl-avatar-circle gl-avatar-s#{opts[:size]}]
|
||||
classes = %W[avatar avatar-inline s#{opts[:size]}]
|
||||
classes << opts[:avatar_class] if opts[:avatar_class]
|
||||
|
||||
avatar = avatar_icon_for_user(author, opts[:size])
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ module SidebarsHelper
|
|||
end
|
||||
|
||||
def scope_avatar_classes(object)
|
||||
%w[gl-avatar gl-avatar-s32].tap do |klasses|
|
||||
%w[avatar-container rect-avatar s32].tap do |klasses|
|
||||
klass = sidebar_attributes_for_object(object).fetch(:scope_avatar_class, nil)
|
||||
klasses << klass if klass
|
||||
end
|
||||
|
|
|
|||
|
|
@ -7,4 +7,8 @@ module WikiPageVersionHelper
|
|||
user = wiki_page_version.author
|
||||
user.nil? ? "mailto:#{wiki_page_version.author_email}" : Gitlab::UrlBuilder.build(user)
|
||||
end
|
||||
|
||||
def wiki_page_version_author_avatar(wiki_page_version)
|
||||
image_tag(avatar_icon_for_email(wiki_page_version.author_email, 24), class: "avatar s24 float-none !gl-mr-0")
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -295,7 +295,8 @@ module ApplicationSettingImplementation
|
|||
ai_action_api_rate_limit: 160,
|
||||
code_suggestions_api_rate_limit: 60,
|
||||
require_personal_access_token_expiry: true,
|
||||
pages_extra_deployments_default_expiry_seconds: 86400
|
||||
pages_extra_deployments_default_expiry_seconds: 86400,
|
||||
scan_execution_policies_action_limit: 10
|
||||
}.tap do |hsh|
|
||||
hsh.merge!(non_production_defaults) unless Rails.env.production?
|
||||
end
|
||||
|
|
|
|||
|
|
@ -35,8 +35,8 @@ module Ci
|
|||
})
|
||||
elsif component_path.invalid_usage_for_latest?
|
||||
ServiceResponse.error(
|
||||
message: 'The ~latest version reference is not supported for non-catalog resources. ' \
|
||||
'Use a tag, branch, or SHA instead',
|
||||
message: "#{error_prefix} The ~latest version reference is not supported for non-catalog resources. " \
|
||||
'Use a tag, branch, or commit SHA instead.',
|
||||
reason: :invalid_usage)
|
||||
else
|
||||
ServiceResponse.error(message: "#{error_prefix} content not found", reason: :content_not_found)
|
||||
|
|
@ -63,7 +63,7 @@ module Ci
|
|||
strong_memoize_attr :component_path_class
|
||||
|
||||
def error_prefix
|
||||
"component '#{address}' -"
|
||||
"Component '#{address}' -"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -24,8 +24,8 @@
|
|||
- add_page_specific_style 'page_bundles/commit_description'
|
||||
|
||||
%li{ class: ["commit flex-row", ("js-toggle-container" if collapsible)], id: "commit-#{commit.short_id}" }
|
||||
.gl-self-start.gl-hidden.sm:gl-block.gl-mr-3
|
||||
= author_avatar(commit, size: 32, has_tooltip: false)
|
||||
.avatar-cell.gl-hidden.sm:gl-block
|
||||
= author_avatar(commit, size: 40, has_tooltip: false)
|
||||
|
||||
.commit-detail.flex-list.gl-flex.gl-justify-between.gl-items-center.gl-grow.gl-min-w-0
|
||||
.commit-content{ data: { testid: 'commit-content' } }
|
||||
|
|
@ -46,7 +46,7 @@
|
|||
- if commit.different_committer? && commit.committer
|
||||
- commit_committer_link = commit_committer_link(commit)
|
||||
- commit_committer_timeago = time_ago_with_tooltip(commit.committed_date, placement: 'bottom')
|
||||
- commit_committer_avatar = commit_committer_avatar(commit.committer, size: 16, has_tooltip: false)
|
||||
- commit_committer_avatar = commit_committer_avatar(commit.committer, size: 18, has_tooltip: false)
|
||||
- commit_text = _('%{commit_author_link} authored %{commit_authored_timeago} and %{commit_committer_avatar} %{commit_committer_link} committed %{commit_committer_timeago}') % { commit_author_link: commit_author_link, commit_authored_timeago: commit_authored_timeago, commit_committer_avatar: commit_committer_avatar, commit_committer_link: commit_committer_link, commit_committer_timeago: commit_committer_timeago }
|
||||
- else
|
||||
- commit_text = _('%{commit_author_link} authored %{commit_authored_timeago}') % { commit_author_link: commit_author_link, commit_authored_timeago: commit_authored_timeago }
|
||||
|
|
|
|||
|
|
@ -1,3 +0,0 @@
|
|||
- return unless can?(current_user, :read_observability, @project)
|
||||
|
||||
.js-observability-settings
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
- breadcrumb_title _('Monitor Settings')
|
||||
- @force_desktop_expanded_sidebar = true
|
||||
|
||||
= render 'projects/settings/operations/observability'
|
||||
= render_if_exists 'projects/settings/operations/observability'
|
||||
= render 'projects/settings/operations/error_tracking'
|
||||
= render 'projects/settings/operations/alert_management'
|
||||
= render 'projects/settings/operations/incidents'
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
%li.filter-dropdown-item{ class: ('js-current-user' if user == current_user) }
|
||||
= render Pajamas::ButtonComponent.new(variant: :link, button_text_classes: 'gl-flex gl-items-center') do
|
||||
.gl-shrink-0
|
||||
= user_avatar_without_link(user: user, lazy: avatar[:lazy], url: avatar[:url], size: 32, has_tooltip: false)
|
||||
= user_avatar_without_link(user: user, lazy: avatar[:lazy], url: avatar[:url], size: 40, has_tooltip: false)
|
||||
.gl-flex.gl-flex-col
|
||||
%span.gl-font-bold.gl-whitespace-normal.gl-break-words
|
||||
= user.name
|
||||
|
|
|
|||
|
|
@ -24,6 +24,6 @@
|
|||
- assignees.each do |assignee|
|
||||
= link_to polymorphic_path(issuable_type_args, { milestone_title: @milestone.title, assignee_id: assignee.id, state: 'all' }),
|
||||
class: 'has-tooltip', title: _("Assigned to %{assignee_name}") % { assignee_name: assignee.name }, data: { container: 'body' } do
|
||||
- image_tag(avatar_icon_for_user(assignee, 16), class: "gl-avatar gl-avatar-circle gl-avatar-s16", alt: '')
|
||||
- image_tag(avatar_icon_for_user(assignee, 16), class: "avatar s16", alt: '')
|
||||
|
||||
= render_if_exists "shared/milestones/issuable_weight", issuable: issuable
|
||||
|
|
|
|||
|
|
@ -523,6 +523,13 @@ vulnerability_exports:
|
|||
- table: users
|
||||
column: author_id
|
||||
on_delete: async_delete
|
||||
vulnerability_external_issue_links:
|
||||
- table: projects
|
||||
column: project_id
|
||||
on_delete: async_delete
|
||||
- table: users
|
||||
column: author_id
|
||||
on_delete: async_delete
|
||||
vulnerability_feedback:
|
||||
- table: ci_pipelines
|
||||
column: pipeline_id
|
||||
|
|
|
|||
|
|
@ -8,4 +8,7 @@ description: Stores information about the security scans that are a part of Ci::
|
|||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/23669
|
||||
milestone: '12.8'
|
||||
gitlab_schema: gitlab_sec
|
||||
sharding_key_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/454948
|
||||
# `desired_sharding_key` is `project_id`. However, the configuration can't be provided here
|
||||
# because the backfill migration was processed manually.
|
||||
# This migration is custom due to data consistency issues and cross-DB backfill.
|
||||
desired_sharding_key_migration_job_name: BackfillProjectIdToSecurityScans
|
||||
|
|
|
|||
|
|
@ -8,9 +8,7 @@ description: Stores information about connections between external issue tracker
|
|||
and vulnerabilities
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/48465
|
||||
milestone: '13.7'
|
||||
gitlab_schema: gitlab_main_cell
|
||||
allow_cross_foreign_keys:
|
||||
- gitlab_main_clusterwide
|
||||
gitlab_schema: gitlab_sec
|
||||
desired_sharding_key:
|
||||
project_id:
|
||||
references: projects
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddObservabilityAlertsEnabledToProjectSettings < Gitlab::Database::Migration[2.2]
|
||||
milestone '17.4'
|
||||
|
||||
def up
|
||||
add_column :project_settings, :observability_alerts_enabled, :boolean, default: true, null: false
|
||||
end
|
||||
|
||||
def down
|
||||
remove_column :project_settings, :observability_alerts_enabled
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddPolicyActionLimitApplicationSetting < Gitlab::Database::Migration[2.2]
|
||||
milestone '17.4'
|
||||
|
||||
enable_lock_retries!
|
||||
|
||||
def change
|
||||
add_column :application_settings, :security_policies, :jsonb, default: {}, null: false
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddSecurityPoliciesHashConstraintToApplicationSettings < Gitlab::Database::Migration[2.2]
|
||||
disable_ddl_transaction!
|
||||
milestone '17.4'
|
||||
|
||||
CONSTRAINT_NAME = 'check_application_settings_security_policies_is_hash'
|
||||
|
||||
def up
|
||||
add_check_constraint(
|
||||
:application_settings,
|
||||
"(jsonb_typeof(security_policies) = 'object')",
|
||||
CONSTRAINT_NAME
|
||||
)
|
||||
end
|
||||
|
||||
def down
|
||||
remove_check_constraint :application_settings, CONSTRAINT_NAME
|
||||
end
|
||||
end
|
||||
|
|
@ -10,31 +10,35 @@ class QueueBackfillVulnerabilityExternalIssueLinksProjectId < Gitlab::Database::
|
|||
SUB_BATCH_SIZE = 100
|
||||
|
||||
def up
|
||||
queue_batched_background_migration(
|
||||
MIGRATION,
|
||||
:vulnerability_external_issue_links,
|
||||
:id,
|
||||
:project_id,
|
||||
:vulnerabilities,
|
||||
:project_id,
|
||||
:vulnerability_id,
|
||||
job_interval: DELAY_INTERVAL,
|
||||
batch_size: BATCH_SIZE,
|
||||
sub_batch_size: SUB_BATCH_SIZE
|
||||
)
|
||||
end
|
||||
|
||||
def down
|
||||
delete_batched_background_migration(
|
||||
MIGRATION,
|
||||
:vulnerability_external_issue_links,
|
||||
:id,
|
||||
[
|
||||
Gitlab::Database::QueryAnalyzers::RestrictAllowedSchemas.with_suppressed do
|
||||
queue_batched_background_migration(
|
||||
MIGRATION,
|
||||
:vulnerability_external_issue_links,
|
||||
:id,
|
||||
:project_id,
|
||||
:vulnerabilities,
|
||||
:project_id,
|
||||
:vulnerability_id
|
||||
]
|
||||
)
|
||||
:vulnerability_id,
|
||||
job_interval: DELAY_INTERVAL,
|
||||
batch_size: BATCH_SIZE,
|
||||
sub_batch_size: SUB_BATCH_SIZE
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def down
|
||||
Gitlab::Database::QueryAnalyzers::RestrictAllowedSchemas.with_suppressed do
|
||||
delete_batched_background_migration(
|
||||
MIGRATION,
|
||||
:vulnerability_external_issue_links,
|
||||
:id,
|
||||
[
|
||||
:project_id,
|
||||
:vulnerabilities,
|
||||
:project_id,
|
||||
:vulnerability_id
|
||||
]
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class RemoveProjectsVulnerabilityExternalIssueLinksProjectIdFk < Gitlab::Database::Migration[2.2]
|
||||
milestone '17.4'
|
||||
disable_ddl_transaction!
|
||||
|
||||
FOREIGN_KEY_NAME = "fk_abd093bb21"
|
||||
|
||||
def up
|
||||
with_lock_retries do
|
||||
remove_foreign_key_if_exists(:vulnerability_external_issue_links, :projects,
|
||||
name: FOREIGN_KEY_NAME, reverse_lock_order: true)
|
||||
end
|
||||
end
|
||||
|
||||
def down
|
||||
add_concurrent_foreign_key(:vulnerability_external_issue_links, :projects,
|
||||
name: FOREIGN_KEY_NAME, column: :project_id,
|
||||
target_column: :id, on_delete: :cascade)
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class RemoveUsersVulnerabilityExternalIssueLinksAuthorIdFk < Gitlab::Database::Migration[2.2]
|
||||
milestone '17.4'
|
||||
disable_ddl_transaction!
|
||||
|
||||
FOREIGN_KEY_NAME = "fk_rails_e5ba7f7b13"
|
||||
|
||||
def up
|
||||
with_lock_retries do
|
||||
remove_foreign_key_if_exists(:vulnerability_external_issue_links, :users,
|
||||
name: FOREIGN_KEY_NAME, reverse_lock_order: true)
|
||||
end
|
||||
end
|
||||
|
||||
def down
|
||||
add_concurrent_foreign_key(:vulnerability_external_issue_links, :users,
|
||||
name: FOREIGN_KEY_NAME, column: :author_id,
|
||||
target_column: :id, on_delete: :nullify)
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1 @@
|
|||
bfdfc1454a7d21a2d15b473edf8b7e6d4dde88cb8ebef07dff0e89cfa522e98e
|
||||
|
|
@ -0,0 +1 @@
|
|||
ade03637a598a0ad8e6416cf5a0accfb074dca82a8ebade15509b2e9216196bc
|
||||
|
|
@ -0,0 +1 @@
|
|||
a68ceb0f06cbee9806f007d27c86c43d34694f48ae2ed624ab110c3ecc8c7478
|
||||
|
|
@ -0,0 +1 @@
|
|||
94b8b6456c58d120a912adfca337c71e4abc2aec0005d67785b21cfd068db48d
|
||||
|
|
@ -0,0 +1 @@
|
|||
709583f3caaea6656c95ac146da29439aeb6ac7dea7606fb52abbaf857496dd5
|
||||
|
|
@ -6050,6 +6050,7 @@ CREATE TABLE application_settings (
|
|||
cluster_agents jsonb DEFAULT '{}'::jsonb NOT NULL,
|
||||
observability_backend_ssl_verification_enabled boolean DEFAULT true NOT NULL,
|
||||
pages jsonb DEFAULT '{}'::jsonb NOT NULL,
|
||||
security_policies jsonb DEFAULT '{}'::jsonb NOT NULL,
|
||||
CONSTRAINT app_settings_container_reg_cleanup_tags_max_list_size_positive CHECK ((container_registry_cleanup_tags_service_max_list_size >= 0)),
|
||||
CONSTRAINT app_settings_dep_proxy_ttl_policies_worker_capacity_positive CHECK ((dependency_proxy_ttl_group_policy_worker_capacity >= 0)),
|
||||
CONSTRAINT app_settings_ext_pipeline_validation_service_url_text_limit CHECK ((char_length(external_pipeline_validation_service_url) <= 255)),
|
||||
|
|
@ -6106,6 +6107,7 @@ CREATE TABLE application_settings (
|
|||
CONSTRAINT check_application_settings_package_registry_is_hash CHECK ((jsonb_typeof(package_registry) = 'object'::text)),
|
||||
CONSTRAINT check_application_settings_rate_limits_is_hash CHECK ((jsonb_typeof(rate_limits) = 'object'::text)),
|
||||
CONSTRAINT check_application_settings_rate_limits_unauth_git_http_is_hash CHECK ((jsonb_typeof(rate_limits_unauthenticated_git_http) = 'object'::text)),
|
||||
CONSTRAINT check_application_settings_security_policies_is_hash CHECK ((jsonb_typeof(security_policies) = 'object'::text)),
|
||||
CONSTRAINT check_application_settings_service_ping_settings_is_hash CHECK ((jsonb_typeof(service_ping_settings) = 'object'::text)),
|
||||
CONSTRAINT check_b8c74ea5b3 CHECK ((char_length(deactivation_email_additional_text) <= 1000)),
|
||||
CONSTRAINT check_cdfbd99405 CHECK ((char_length(security_txt_content) <= 2048)),
|
||||
|
|
@ -16710,6 +16712,7 @@ CREATE TABLE project_settings (
|
|||
allow_merge_without_pipeline boolean DEFAULT false NOT NULL,
|
||||
duo_features_enabled boolean DEFAULT true NOT NULL,
|
||||
require_reauthentication_to_approve boolean,
|
||||
observability_alerts_enabled boolean DEFAULT true NOT NULL,
|
||||
CONSTRAINT check_1a30456322 CHECK ((char_length(pages_unique_domain) <= 63)),
|
||||
CONSTRAINT check_3a03e7557a CHECK ((char_length(previous_default_branch) <= 4096)),
|
||||
CONSTRAINT check_3ca5cbffe6 CHECK ((char_length(issue_branch_template) <= 255)),
|
||||
|
|
@ -34039,9 +34042,6 @@ ALTER TABLE ONLY identities
|
|||
ALTER TABLE ONLY boards
|
||||
ADD CONSTRAINT fk_ab0a250ff6 FOREIGN KEY (iteration_cadence_id) REFERENCES iterations_cadences(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE ONLY vulnerability_external_issue_links
|
||||
ADD CONSTRAINT fk_abd093bb21 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE ONLY audit_events_streaming_http_instance_namespace_filters
|
||||
ADD CONSTRAINT fk_abe44125bc FOREIGN KEY (audit_events_instance_external_audit_event_destination_id) REFERENCES audit_events_instance_external_audit_event_destinations(id) ON DELETE CASCADE;
|
||||
|
||||
|
|
@ -36319,9 +36319,6 @@ ALTER TABLE ONLY incident_management_escalation_policies
|
|||
ALTER TABLE ONLY software_license_policies
|
||||
ADD CONSTRAINT fk_rails_e5b77d620e FOREIGN KEY (scan_result_policy_id) REFERENCES scan_result_policies(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE ONLY vulnerability_external_issue_links
|
||||
ADD CONSTRAINT fk_rails_e5ba7f7b13 FOREIGN KEY (author_id) REFERENCES users(id) ON DELETE SET NULL;
|
||||
|
||||
ALTER TABLE ONLY approval_merge_request_rule_sources
|
||||
ADD CONSTRAINT fk_rails_e605a04f76 FOREIGN KEY (approval_merge_request_rule_id) REFERENCES approval_merge_request_rules(id) ON DELETE CASCADE;
|
||||
|
||||
|
|
|
|||
|
|
@ -731,7 +731,7 @@ You might receive an error message similar to the following when using the `~lat
|
|||
version qualifier to reference a component hosted by a [catalog project](#set-a-component-project-as-a-catalog-project):
|
||||
|
||||
```plaintext
|
||||
This GitLab CI configuration is invalid: component 'gitlab.com/my-namespace/my-project/my-component@~latest' - content not found
|
||||
This GitLab CI configuration is invalid: Component 'gitlab.com/my-namespace/my-project/my-component@~latest' - content not found
|
||||
```
|
||||
|
||||
The `~latest` behavior [was updated](https://gitlab.com/gitlab-org/gitlab/-/issues/442238)
|
||||
|
|
|
|||
|
|
@ -176,8 +176,6 @@ is identified after release, the following steps must still be completed:
|
|||
|
||||
### In the release following the required stop
|
||||
|
||||
1. Update `Gitlab::Database::MIN_SCHEMA_GITLAB_VERSION` in `lib/gitlab/database.rb` to the
|
||||
new required stop versions. Do not change `Gitlab::Database::MIN_SCHEMA_VERSION`.
|
||||
1. In the `charts` project, update the
|
||||
[upgrade check hook](https://docs.gitlab.com/charts/development/upgrade_stop.html)
|
||||
to the required stop version.
|
||||
|
|
|
|||
|
|
@ -6,19 +6,24 @@ group: unassigned
|
|||
|
||||
# Documenting experimental and beta features
|
||||
|
||||
Some features are not generally available and are instead considered
|
||||
[experimental or beta](../../policy/experiment-beta-support.md).
|
||||
When you document an [experiment or beta](../../policy/experiment-beta-support.md) feature:
|
||||
|
||||
When you document a feature in one of these three statuses:
|
||||
- Include the status in the [product availability details](styleguide/availability_details.md#status).
|
||||
- Include [feature flag details](feature_flags.md) if behind a feature flag.
|
||||
- [Update the feature status](styleguide/availability_details.md#changed-feature-status) when it changes.
|
||||
|
||||
- Add the tier badge after the page or topic title.
|
||||
- Do not include `(Experiment)` or `(Beta)` in the left nav.
|
||||
- Ensure the history lists the feature's status.
|
||||
## When features become generally available
|
||||
|
||||
These features are usually behind a feature flag, which follow [these documentation guidelines](feature_flags.md).
|
||||
When the feature changes from experiment or beta to generally available:
|
||||
|
||||
If you add details of how users should enroll, or how to contact the team with issues,
|
||||
the `FLAG:` note should be above these details.
|
||||
- Remove the **Status** from the product availability details.
|
||||
- Remove any language about the feature not being ready for production.
|
||||
- Update the [history](../documentation/styleguide/availability_details.md#history).
|
||||
|
||||
## Features that require user enrollment or feedback
|
||||
|
||||
To include details about how users should enroll or leave feedback,
|
||||
add it below the `FLAG:` note.
|
||||
|
||||
For example:
|
||||
|
||||
|
|
@ -42,26 +47,10 @@ the list of users testing this feature, do this thing. If you find a bug,
|
|||
[open an issue](https://link).
|
||||
```
|
||||
|
||||
## When features become generally available
|
||||
|
||||
When the feature changes from experiment or beta to generally available, remove:
|
||||
|
||||
- The **Status** from the availability details.
|
||||
- Any language about the feature not being ready for production in the body
|
||||
description.
|
||||
- The feature flag information if available.
|
||||
|
||||
Ensure the history is up-to-date by adding a note about the production release.
|
||||
|
||||
## GitLab Duo features
|
||||
|
||||
Follow these guidelines when you document GitLab Duo features.
|
||||
|
||||
NOTE:
|
||||
As of August, 2024, all GitLab Duo features except Code Suggestions have forward-looking tier statements, for example,
|
||||
`For a limited time, Premium. In the future, Premium with GitLab Duo Pro.`
|
||||
Use these type of statements until further notice.
|
||||
|
||||
### Experiment
|
||||
|
||||
When documenting a GitLab Duo experiment:
|
||||
|
|
|
|||
|
|
@ -57,22 +57,21 @@ For tier, choose one:
|
|||
Document add-ons by using the phrase `with` and the add-on.
|
||||
For example, `with GitLab Duo Pro`.
|
||||
|
||||
As of August, 2024, all GitLab Duo features except Code Suggestions have
|
||||
forward-looking tier statements. Use these type of statements until further notice.
|
||||
|
||||
The possibilities are:
|
||||
|
||||
```markdown
|
||||
**Tier:** Premium with GitLab Duo Pro
|
||||
**Tier:** Premium with GitLab Duo Pro or Ultimate with GitLab Duo Pro or Enterprise
|
||||
**Tier:** Ultimate with GitLab Duo Pro
|
||||
**Tier:** Ultimate with GitLab Duo Pro or Enterprise
|
||||
**Tier:** Ultimate with GitLab Duo Enterprise
|
||||
**Tier:** For a limited time, Premium or Ultimate. In the future, Premium with GitLab Duo Pro or Ultimate with [GitLab Duo Pro or Enterprise](../../subscriptions/subscription-add-ons.md).
|
||||
**Tier:** For a limited time, Ultimate. In the future, Ultimate with [GitLab Duo Pro or Enterprise](../../subscriptions/subscription-add-ons.md).
|
||||
**Tier:** For a limited time, Ultimate. In the future, Ultimate with [GitLab Duo Enterprise](../../subscriptions/subscription-add-ons.md).
|
||||
```
|
||||
|
||||
Do not use a period at the end of the phrase.
|
||||
|
||||
You might have to differentiate which add-on applies for each offering (GitLab.com, Dedicated, self-managed). If you have to differentiate, use this format:
|
||||
|
||||
```markdown
|
||||
**Tier: GitLab.com and Self-managed:** Premium with GitLab Duo Pro or Ultimate with [GitLab Duo Pro or Enterprise](../../subscriptions/subscription-add-ons.md) **GitLab Dedicated:** GitLab Duo Pro or Enterprise
|
||||
**Tier: GitLab.com and Self-managed:** For a limited time, Premium or Ultimate. In the future, Premium with GitLab Duo Pro or Ultimate with [GitLab Duo Pro or Enterprise](../../subscriptions/subscription-add-ons.md). **GitLab Dedicated:** GitLab Duo Pro or Enterprise.
|
||||
```
|
||||
|
||||
NOTE:
|
||||
|
|
|
|||
|
|
@ -94,13 +94,18 @@ the following sections and tables provide an alternative.
|
|||
|
||||
## Scan execution policy schema
|
||||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/472213) in GitLab 17.4 [with flags](../../../administration/feature_flags.md) named `scan_execution_policy_action_limit` (for projects) and `scan_execution_policy_action_limit_group` (for groups). Disabled by default.
|
||||
|
||||
FLAG:
|
||||
The availability of this feature is controlled by a feature flag.
|
||||
For more information, see the history.
|
||||
| Field | Type | Required | Possible values | Description |
|
||||
|-------|------|----------|-----------------|-------------|
|
||||
| `name` | `string` | true | | Name of the policy. Maximum of 255 characters.|
|
||||
| `description` (optional) | `string` | true | | Description of the policy. |
|
||||
| `enabled` | `boolean` | true | `true`, `false` | Flag to enable (`true`) or disable (`false`) the policy. |
|
||||
| `rules` | `array` of rules | true | | List of rules that the policy applies. |
|
||||
| `actions` | `array` of actions | true | | List of actions that the policy enforces. |
|
||||
| `actions` | `array` of actions | true | | List of actions that the policy enforces. Limited to a maximum of 10 in GitLab 18.0 and later. |
|
||||
|
||||
## `pipeline` rule type
|
||||
|
||||
|
|
|
|||
|
|
@ -131,7 +131,6 @@ then process the merge request according to your standard workflow.
|
|||
|
||||
Vulnerability Resolution is enabled for the following list of vulnerability classes. If you see that the button is disabled, that means that the CWE is not part of the supported list at this time. We are actively testing and expanding coverage for Vulnerability Resolution to more classes of vulnerabilities.
|
||||
|
||||
<br><br>
|
||||
<details><summary style="color:#5943b6"><a>View the complete list of supported CWEs for Vulnerability Resolution</a></summary>
|
||||
|
||||
<ul>
|
||||
|
|
|
|||
|
|
@ -189,6 +189,9 @@ For a quick overview, items that are exported include:
|
|||
- Emoji reactions
|
||||
- Project and inherited group members, as long as the user has the Maintainer role for the
|
||||
exported project's group or is an administrator
|
||||
- Some merge request approval rules:
|
||||
- [Approvals for protected branches](../merge_requests/approvals/rules.md#approvals-for-protected-branches).
|
||||
- [Users that are eligible approvers](../merge_requests/approvals/rules.md#eligible-approvers).
|
||||
|
||||
#### Project items that are not exported
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::Backup::Cli::BackupExecutor do
|
||||
let(:context) { build_fake_context }
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
require 'thor'
|
||||
|
||||
RSpec.describe Gitlab::Backup::Cli::Commands::BackupSubcommand do
|
||||
describe "#executor_options" do
|
||||
it "returns the expected hash" do
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::Backup::Cli::Dependencies do
|
||||
let(:bin_path) { Dir.mktmpdir('dependencies', temp_path) }
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::Backup::Cli::Metadata::BackupMetadata do
|
||||
subject(:metadata) { build(:backup_metadata) }
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::Backup::Cli::RestoreExecutor do
|
||||
let(:context) { build_fake_context }
|
||||
let(:backup_id) { "1715018771_2024_05_06_17.0.0-pre" }
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::Backup::Cli::Shell::Command do
|
||||
let(:envdata) do
|
||||
{ 'CUSTOM' => 'data' }
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::Backup::Cli::Shell::Pipeline do
|
||||
let(:command) { Gitlab::Backup::Cli::Shell::Command }
|
||||
let(:printf_command) { command.new('printf "3\n2\n1"') }
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::Backup::Cli::SourceContext do
|
||||
subject(:context) { described_class.new }
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::Backup::Cli::Targets::ObjectStorage::Google do
|
||||
let(:gitlab_config) { class_double("GitlabSettings::Settings") }
|
||||
let(:supported_object_store) do
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::Backup::Cli::Tasks::Task do
|
||||
let(:options) { nil }
|
||||
let(:context) { build_fake_context }
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::Backup::Cli::Utils::PgDump do
|
||||
let(:cmd_args) { pg_dump.send(:cmd_args) }
|
||||
let(:database_name) { 'gitlab_database' }
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::Backup::Cli::Utils::Tar do
|
||||
subject(:tar) { described_class.new }
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::Backup::Cli do
|
||||
it "has a version number" do
|
||||
expect(Gitlab::Backup::Cli::VERSION).not_to be nil
|
||||
|
|
|
|||
|
|
@ -1,10 +1,9 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require "gitlab/backup/cli"
|
||||
require 'active_support/all'
|
||||
require 'tmpdir'
|
||||
require 'fileutils'
|
||||
require 'factory_bot'
|
||||
require 'bundler/setup'
|
||||
Bundler.require(:default, :development, :test)
|
||||
|
||||
require 'thor'
|
||||
require 'gitlab/rspec/next_instance_of'
|
||||
|
||||
ENV["RAILS_ENV"] ||= "test"
|
||||
|
|
|
|||
|
|
@ -216,7 +216,7 @@ module Keeps
|
|||
end
|
||||
|
||||
def before_cuttoff_milestone?(milestone)
|
||||
Gem::Version.new(milestone) <= Gem::Version.new(::Gitlab::Database::MIN_SCHEMA_GITLAB_VERSION)
|
||||
Gem::Version.new(milestone) <= Gem::Version.new(::Gitlab::Database.min_schema_gitlab_version)
|
||||
end
|
||||
|
||||
def each_batched_background_migration
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ module Banzai
|
|||
avatar = user_avatar_without_link(
|
||||
user: user,
|
||||
user_email: email,
|
||||
css_class: 'gl-mr-2',
|
||||
css_class: 'avatar-inline',
|
||||
has_tooltip: false,
|
||||
only_path: false
|
||||
)
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ module Gitlab
|
|||
:chat_data, :allow_mirror_update, :bridge, :content, :dry_run, :logger, :execution_policy_dry_run,
|
||||
# These attributes are set by Chains during processing:
|
||||
:config_content, :yaml_processor_result, :workflow_rules_result, :pipeline_seed,
|
||||
:pipeline_config, :pipeline_execution_policies, :partition_id
|
||||
:pipeline_config, :execution_policy_pipelines, :partition_id
|
||||
) do
|
||||
include Gitlab::Utils::StrongMemoize
|
||||
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ module Gitlab
|
|||
def no_pipeline_to_create?
|
||||
# If there are security policy pipelines,
|
||||
# they will be merged onto the pipeline in PipelineExecutionPolicies::MergeJobs
|
||||
stage_names.empty? && @command.pipeline_execution_policies.blank?
|
||||
stage_names.empty? && @command.execution_policy_pipelines.blank?
|
||||
end
|
||||
|
||||
def stage_names
|
||||
|
|
|
|||
|
|
@ -32,9 +32,6 @@ module Gitlab
|
|||
# https://gitlab.com/gitlab-org/gitlab-foss/issues/61974
|
||||
MAX_TEXT_SIZE_LIMIT = 1_000_000
|
||||
|
||||
# Migrations before this version may have been removed
|
||||
MIN_SCHEMA_GITLAB_VERSION = '17.3'
|
||||
|
||||
# Schema we store dynamically managed partitions in (e.g. for time partitioning)
|
||||
DYNAMIC_PARTITIONS_SCHEMA = :gitlab_partitions_dynamic
|
||||
|
||||
|
|
@ -142,6 +139,18 @@ module Gitlab
|
|||
Gitlab::Runtime.max_threads + headroom
|
||||
end
|
||||
|
||||
# Expose path information so that we can use it to make sure migrations are
|
||||
# healthy
|
||||
def self.upgrade_path
|
||||
path_data = YAML.safe_load_file(Rails.root.join('config/upgrade_path.yml'))
|
||||
Gitlab::Utils::UpgradePath.new(path_data, Gitlab.version_info)
|
||||
end
|
||||
|
||||
# Migrations before this version may have been removed.
|
||||
def self.min_schema_gitlab_version
|
||||
upgrade_path.last_required_stop
|
||||
end
|
||||
|
||||
# Database configured. Returns true even if the database is shared
|
||||
def self.has_config?(database_name)
|
||||
ActiveRecord::Base.configurations
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ task schema_version_check: :environment do
|
|||
# But a database with existing migrations less than our min version is not
|
||||
if schema_version > 0 && schema_version < minimum_migration_version
|
||||
raise "Your current database version is too old to be migrated. " \
|
||||
"You should upgrade to GitLab #{Gitlab::Database::MIN_SCHEMA_GITLAB_VERSION} before moving to this version. " \
|
||||
"You should upgrade to GitLab #{Gitlab::Database.min_schema_gitlab_version} before moving to this version. " \
|
||||
"Please see https://docs.gitlab.com/ee/policy/maintenance.html#upgrade-recommendations"
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -37063,6 +37063,12 @@ msgstr ""
|
|||
msgid "Observability|Create issues from this page to view them as related items here."
|
||||
msgstr ""
|
||||
|
||||
msgid "Observability|Creates alerts automatically for Observability-related errors."
|
||||
msgstr ""
|
||||
|
||||
msgid "Observability|Enable Observability alerts"
|
||||
msgstr ""
|
||||
|
||||
msgid "Observability|Enable tracing, metrics, or logs on your project."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -37129,10 +37135,7 @@ msgstr ""
|
|||
msgid "Observability|Usage by day"
|
||||
msgstr ""
|
||||
|
||||
msgid "Observability|View our %{docsLink} for further instructions on how to use these features."
|
||||
msgstr ""
|
||||
|
||||
msgid "Observability|documentation"
|
||||
msgid "Observability|View our %{documentation} for further instructions on how to use these features."
|
||||
msgstr ""
|
||||
|
||||
msgid "Oct"
|
||||
|
|
@ -49105,6 +49108,9 @@ msgstr ""
|
|||
msgid "SecurityOrchestration|Policy editor"
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityOrchestration|Policy exceeds the maximum of %{limit} actions"
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityOrchestration|Policy is invalid"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -64158,6 +64164,9 @@ msgstr ""
|
|||
msgid "disabled"
|
||||
msgstr ""
|
||||
|
||||
msgid "documentation"
|
||||
msgstr ""
|
||||
|
||||
msgid "does not belong to the top-level group of the namespace."
|
||||
msgstr ""
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
ARG GDK_SHA=c6f57a57d8d3463241fd37be965ba5697138dc72
|
||||
ARG GDK_SHA=59f9233de457781829a606c11e775b4809677dc3
|
||||
# Use tag prefix when running on 'stable' branch to make sure 'protected' image is used which is not deleted by registry cleanup
|
||||
ARG GDK_BASE_TAG_PREFIX
|
||||
|
||||
|
|
|
|||
|
|
@ -225,7 +225,7 @@ module QA
|
|||
|
||||
def expand_merge_checks
|
||||
within_element('.mr-widget-section') do
|
||||
click_element('chevron-lg-down-icon')
|
||||
click_element('chevron-down-icon')
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -143,6 +143,42 @@ RSpec.describe 'User creates a merge request', :js, feature_category: :code_revi
|
|||
end
|
||||
end
|
||||
|
||||
context 'when source and target both have a commit with the same content' do
|
||||
let_it_be(:project) { create(:project, :repository) }
|
||||
let_it_be(:user) { create(:user) }
|
||||
|
||||
let(:title) { 'Some feature' }
|
||||
|
||||
before do
|
||||
project.add_maintainer(user)
|
||||
sign_in(user)
|
||||
|
||||
# create a commit with identical content on source and target
|
||||
project.repository.create_file(user, 'bbb.txt', 'zzzz', message: 'Commit on target', branch_name: 'feature')
|
||||
project.repository.create_file(user, 'bbb.txt', 'zzzz', message: 'Commit on src', branch_name: 'fix')
|
||||
end
|
||||
|
||||
it "contains the correct changes count", :sidekiq_inline do
|
||||
visit(project_new_merge_request_path(project))
|
||||
|
||||
compare_source_and_target('fix', 'feature')
|
||||
|
||||
fill_in('Title', with: title)
|
||||
click_button('Create merge request')
|
||||
|
||||
page.within('.diffs-tab') do
|
||||
expect(page).to have_content('Changes 2')
|
||||
end
|
||||
|
||||
click_on 'Changes'
|
||||
wait_for_requests
|
||||
|
||||
page.within('.diffs-tab') do
|
||||
expect(page).to have_content('Changes 2')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def compare_source_and_target(source_branch, target_branch)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import Vue from 'vue';
|
||||
import VueApollo from 'vue-apollo';
|
||||
import { GlIcon, GlLink } from '@gitlab/ui';
|
||||
import createMockApollo from 'helpers/mock_apollo_helper';
|
||||
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
|
||||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
|
|
@ -44,13 +43,10 @@ describe('FailedJobDetails component', () => {
|
|||
});
|
||||
};
|
||||
|
||||
const findArrowIcon = () => wrapper.findComponent(GlIcon);
|
||||
const findJobId = () => wrapper.findComponent(GlLink);
|
||||
const findJobLog = () => wrapper.findByTestId('job-log');
|
||||
const findJobName = () => wrapper.findByText(defaultProps.job.name);
|
||||
const findJobId = () => wrapper.findByTestId('job-id-link');
|
||||
const findJobName = () => wrapper.findByTestId('job-name-link');
|
||||
const findRetryButton = () => wrapper.findByTestId('retry-button');
|
||||
const findRow = () => wrapper.findByTestId('widget-row');
|
||||
const findStageName = () => wrapper.findByText(defaultProps.job.stage.name);
|
||||
const findStageName = () => wrapper.findByTestId('job-stage-name');
|
||||
|
||||
beforeEach(() => {
|
||||
mockRetryResponse = jest.fn();
|
||||
|
|
@ -76,10 +72,6 @@ describe('FailedJobDetails component', () => {
|
|||
expect(findJobId().exists()).toBe(true);
|
||||
expect(findJobId().text()).toContain(String(jobId));
|
||||
});
|
||||
|
||||
it('does not renders the job lob', () => {
|
||||
expect(findJobLog().exists()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Retry action', () => {
|
||||
|
|
@ -178,77 +170,4 @@ describe('FailedJobDetails component', () => {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Job log', () => {
|
||||
describe('without permissions', () => {
|
||||
beforeEach(async () => {
|
||||
createComponent({ props: { job: { ...job, userPermissions: { readBuild: false } } } });
|
||||
await findRow().trigger('click');
|
||||
});
|
||||
|
||||
it('does not renders the received html of the job log', () => {
|
||||
expect(findJobLog().html()).not.toContain(defaultProps.job.trace.htmlSummary);
|
||||
});
|
||||
|
||||
it('shows a permission error message', () => {
|
||||
expect(findJobLog().text()).toBe("You do not have permission to read this job's log.");
|
||||
});
|
||||
});
|
||||
|
||||
describe('with permissions', () => {
|
||||
beforeEach(() => {
|
||||
createComponent();
|
||||
});
|
||||
|
||||
describe('when clicking on the row', () => {
|
||||
beforeEach(async () => {
|
||||
await findRow().trigger('click');
|
||||
});
|
||||
|
||||
describe('while collapsed', () => {
|
||||
it('expands the job log', () => {
|
||||
expect(findJobLog().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('renders the down arrow', () => {
|
||||
expect(findArrowIcon().props().name).toBe('chevron-down');
|
||||
});
|
||||
|
||||
it('renders the received html of the job log', () => {
|
||||
expect(findJobLog().html()).toContain(defaultProps.job.trace.htmlSummary);
|
||||
});
|
||||
});
|
||||
|
||||
describe('while expanded', () => {
|
||||
it('collapes the job log', async () => {
|
||||
expect(findJobLog().exists()).toBe(true);
|
||||
|
||||
await findRow().trigger('click');
|
||||
|
||||
expect(findJobLog().exists()).toBe(false);
|
||||
});
|
||||
|
||||
it('renders the right arrow', async () => {
|
||||
expect(findArrowIcon().props().name).toBe('chevron-down');
|
||||
|
||||
await findRow().trigger('click');
|
||||
|
||||
expect(findArrowIcon().props().name).toBe('chevron-right');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when clicking on a link element within the row', () => {
|
||||
it('does not expands/collapse the job log', async () => {
|
||||
expect(findJobLog().exists()).toBe(false);
|
||||
expect(findArrowIcon().props().name).toBe('chevron-right');
|
||||
|
||||
await findJobId().vm.$emit('click');
|
||||
|
||||
expect(findJobLog().exists()).toBe(false);
|
||||
expect(findArrowIcon().props().name).toBe('chevron-right');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -20,9 +20,6 @@ export const job = {
|
|||
id: '1',
|
||||
name: 'build',
|
||||
},
|
||||
trace: {
|
||||
htmlSummary: '<h1>Hello</h1>',
|
||||
},
|
||||
userPermissions: {
|
||||
readBuild: true,
|
||||
updateBuild: true,
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { GlModal } from '@gitlab/ui';
|
||||
import { GlModal, GlSprintf } from '@gitlab/ui';
|
||||
import Vue, { nextTick } from 'vue';
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import Vuex from 'vuex';
|
||||
import { mountExtended } from 'helpers/vue_test_utils_helper';
|
||||
import { shallowMountExtended, mountExtended } from 'helpers/vue_test_utils_helper';
|
||||
import DeployFreezeTable from '~/deploy_freeze/components/deploy_freeze_table.vue';
|
||||
import createStore from '~/deploy_freeze/store';
|
||||
import { RECEIVE_FREEZE_PERIODS_SUCCESS } from '~/deploy_freeze/store/mutation_types';
|
||||
|
|
@ -15,13 +15,13 @@ describe('Deploy freeze table', () => {
|
|||
let wrapper;
|
||||
let store;
|
||||
|
||||
const createComponent = () => {
|
||||
const createComponent = (mountFn = mountExtended) => {
|
||||
store = createStore({
|
||||
projectId: '8',
|
||||
timezoneData: timezoneDataFixture,
|
||||
});
|
||||
jest.spyOn(store, 'dispatch').mockImplementation();
|
||||
wrapper = mountExtended(DeployFreezeTable, {
|
||||
wrapper = mountFn(DeployFreezeTable, {
|
||||
attachTo: document.body,
|
||||
store,
|
||||
});
|
||||
|
|
@ -35,24 +35,33 @@ describe('Deploy freeze table', () => {
|
|||
const findDeleteDeployFreezeModal = () => wrapper.findComponent(GlModal);
|
||||
const findCount = () => wrapper.findByTestId('crud-count');
|
||||
|
||||
beforeEach(() => {
|
||||
createComponent();
|
||||
});
|
||||
describe('When mounting', () => {
|
||||
beforeEach(() => {
|
||||
createComponent(shallowMountExtended);
|
||||
});
|
||||
|
||||
it('dispatches fetchFreezePeriods when mounted', () => {
|
||||
expect(store.dispatch).toHaveBeenCalledWith('fetchFreezePeriods');
|
||||
it('dispatches fetchFreezePeriods when mounted', () => {
|
||||
expect(store.dispatch).toHaveBeenCalledWith('fetchFreezePeriods');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Renders correct data', () => {
|
||||
it('displays empty', () => {
|
||||
expect(findEmptyFreezePeriods().exists()).toBe(true);
|
||||
expect(findEmptyFreezePeriods().text()).toMatchInterpolatedText(
|
||||
'No deploy freezes exist for this project. To add one, select Add deploy freeze above.',
|
||||
);
|
||||
describe('without empty data', () => {
|
||||
beforeEach(() => {
|
||||
createComponent(shallowMountExtended);
|
||||
});
|
||||
|
||||
it('displays empty', () => {
|
||||
expect(findEmptyFreezePeriods().exists()).toBe(true);
|
||||
expect(wrapper.findComponent(GlSprintf).attributes('message')).toBe(
|
||||
'No deploy freezes exist for this project. To add one, select %{strongStart}Add deploy freeze%{strongEnd} above.',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('with data', () => {
|
||||
beforeEach(async () => {
|
||||
createComponent();
|
||||
store.commit(RECEIVE_FREEZE_PERIODS_SUCCESS, freezePeriodsFixture);
|
||||
await nextTick();
|
||||
});
|
||||
|
|
@ -106,6 +115,10 @@ describe('Deploy freeze table', () => {
|
|||
});
|
||||
|
||||
describe('Table click actions', () => {
|
||||
beforeEach(() => {
|
||||
createComponent();
|
||||
});
|
||||
|
||||
it('displays add deploy freeze button', () => {
|
||||
expect(findAddDeployFreezeButton().exists()).toBe(true);
|
||||
expect(findAddDeployFreezeButton().text()).toBe('Add deploy freeze');
|
||||
|
|
|
|||
|
|
@ -557,8 +557,7 @@ describe('GfmAutoComplete', () => {
|
|||
expect(membersBeforeSave([{ ...mockGroup, avatar_url: null }])).toEqual([
|
||||
{
|
||||
username: 'my-group',
|
||||
avatarTag:
|
||||
'<div class="gl-avatar gl-avatar-s24 gl-mr-2 gl-justify-center gl-items-center ">M</div>',
|
||||
avatarTag: '<div class="avatar rect-avatar avatar-inline s24 gl-mr-2">M</div>',
|
||||
title: 'My Group (2)',
|
||||
search: 'MyGroup my-group',
|
||||
icon: '',
|
||||
|
|
@ -571,7 +570,7 @@ describe('GfmAutoComplete', () => {
|
|||
{
|
||||
username: 'my-group',
|
||||
avatarTag:
|
||||
'<img src="./group.jpg" alt="my-group" class="gl-avatar gl-avatar-s24 gl-mr-2 "/>',
|
||||
'<img src="./group.jpg" alt="my-group" class="avatar rect-avatar avatar-inline s24 gl-mr-2"/>',
|
||||
title: 'My Group (2)',
|
||||
search: 'MyGroup my-group',
|
||||
icon: '',
|
||||
|
|
@ -584,7 +583,7 @@ describe('GfmAutoComplete', () => {
|
|||
{
|
||||
username: 'my-group',
|
||||
avatarTag:
|
||||
'<img src="./group.jpg" alt="my-group" class="gl-avatar gl-avatar-s24 gl-mr-2 "/>',
|
||||
'<img src="./group.jpg" alt="my-group" class="avatar rect-avatar avatar-inline s24 gl-mr-2"/>',
|
||||
title: 'My Group',
|
||||
search: 'MyGroup my-group',
|
||||
icon: '<svg class="s16 vertical-align-middle gl-ml-2"><use xlink:href="/icons.svg#notifications-off" /></svg>',
|
||||
|
|
@ -601,7 +600,7 @@ describe('GfmAutoComplete', () => {
|
|||
{
|
||||
username: 'my-user',
|
||||
avatarTag:
|
||||
'<img src="./users.jpg" alt="my-user" class="gl-avatar gl-avatar-s24 gl-mr-2 gl-avatar-circle"/>',
|
||||
'<img src="./users.jpg" alt="my-user" class="avatar avatar-inline s24 gl-mr-2"/>',
|
||||
title: 'My User',
|
||||
search: 'MyUser my-user',
|
||||
icon: '',
|
||||
|
|
|
|||
|
|
@ -260,8 +260,9 @@ describe('GroupItemComponent', () => {
|
|||
expect(vm.$el.querySelector('.folder-toggle-wrap')).toBeDefined();
|
||||
expect(vm.$el.querySelector('.folder-toggle-wrap .item-type-icon')).toBeDefined();
|
||||
|
||||
expect(vm.$el.querySelector('.gl-avatar')).toBeDefined();
|
||||
expect(vm.$el.querySelector('.gl-avatar a.no-expand')).toBeDefined();
|
||||
expect(vm.$el.querySelector('.avatar-container')).toBeDefined();
|
||||
expect(vm.$el.querySelector('.avatar-container a.no-expand')).toBeDefined();
|
||||
expect(vm.$el.querySelector('.avatar-container .avatar')).toBeDefined();
|
||||
|
||||
expect(vm.$el.querySelector('.title')).toBeDefined();
|
||||
expect(vm.$el.querySelector('.title a.no-expand')).toBeDefined();
|
||||
|
|
|
|||
|
|
@ -242,7 +242,7 @@ describe('RelatedIssuesBlock', () => {
|
|||
it('is expanded by default', () => {
|
||||
const toggleButton = findToggleButton();
|
||||
|
||||
expect(toggleButton.props('icon')).toBe('chevron-lg-up');
|
||||
expect(toggleButton.props('icon')).toBe('chevron-up');
|
||||
expect(toggleButton.props('disabled')).toBe(false);
|
||||
expect(toggleButton.attributes('aria-expanded')).toBe('true');
|
||||
expect(findRelatedIssuesBody().exists()).toBe(true);
|
||||
|
|
@ -254,7 +254,7 @@ describe('RelatedIssuesBlock', () => {
|
|||
|
||||
const toggleButton = findToggleButton();
|
||||
|
||||
expect(toggleButton.props('icon')).toBe('chevron-lg-down');
|
||||
expect(toggleButton.props('icon')).toBe('chevron-down');
|
||||
expect(toggleButton.attributes('aria-expanded')).toBe('false');
|
||||
expect(findRelatedIssuesBody().exists()).toBe(false);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import { shallowMount } from '@vue/test-utils';
|
||||
import { GlAvatar } from '@gitlab/ui';
|
||||
import { TEST_HOST } from 'helpers/test_constants';
|
||||
import AssigneeAvatar from '~/sidebar/components/assignees/assignee_avatar.vue';
|
||||
import userDataMock from '../../user_data_mock';
|
||||
|
|
@ -27,7 +26,7 @@ describe('AssigneeAvatar', () => {
|
|||
window.gon = { default_avatar_url: TEST_DEFAULT_AVATAR_URL };
|
||||
});
|
||||
|
||||
const findImg = () => wrapper.findComponent(GlAvatar);
|
||||
const findImg = () => wrapper.find('img');
|
||||
|
||||
it('does not show warning icon if assignee can merge', () => {
|
||||
createComponent();
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { GlAvatar, GlIcon } from '@gitlab/ui';
|
||||
import { GlIcon } from '@gitlab/ui';
|
||||
import { mount } from '@vue/test-utils';
|
||||
import { trimText } from 'helpers/text_helper';
|
||||
import UsersMockHelper from 'helpers/user_mock_data_helper';
|
||||
|
|
@ -79,10 +79,8 @@ describe('Assignee component', () => {
|
|||
const assignee = collapsedChildren.at(0);
|
||||
|
||||
expect(collapsedChildren.length).toBe(1);
|
||||
expect(assignee.findComponent(GlAvatar).attributes('src')).toBe(UsersMock.user.avatar);
|
||||
expect(assignee.findComponent(GlAvatar).attributes('alt')).toBe(
|
||||
`${UsersMock.user.name}'s avatar`,
|
||||
);
|
||||
expect(assignee.find('.avatar').attributes('src')).toBe(UsersMock.user.avatar);
|
||||
expect(assignee.find('.avatar').attributes('alt')).toBe(`${UsersMock.user.name}'s avatar`);
|
||||
|
||||
expect(trimText(assignee.find('.author').text())).toBe(UsersMock.user.name);
|
||||
});
|
||||
|
|
@ -102,15 +100,15 @@ describe('Assignee component', () => {
|
|||
|
||||
const first = collapsedChildren.at(0);
|
||||
|
||||
expect(first.findComponent(GlAvatar).attributes('src')).toBe(users[0].avatar_url);
|
||||
expect(first.findComponent(GlAvatar).attributes('alt')).toBe(`${users[0].name}'s avatar`);
|
||||
expect(first.find('.avatar').attributes('src')).toBe(users[0].avatar_url);
|
||||
expect(first.find('.avatar').attributes('alt')).toBe(`${users[0].name}'s avatar`);
|
||||
|
||||
expect(trimText(first.find('.author').text())).toBe(users[0].name);
|
||||
|
||||
const second = collapsedChildren.at(1);
|
||||
|
||||
expect(second.findComponent(GlAvatar).attributes('src')).toBe(users[1].avatar_url);
|
||||
expect(second.findComponent(GlAvatar).attributes('alt')).toBe(`${users[1].name}'s avatar`);
|
||||
expect(second.find('.avatar').attributes('src')).toBe(users[1].avatar_url);
|
||||
expect(second.find('.avatar').attributes('alt')).toBe(`${users[1].name}'s avatar`);
|
||||
|
||||
expect(trimText(second.find('.author').text())).toBe(users[1].name);
|
||||
});
|
||||
|
|
@ -128,8 +126,8 @@ describe('Assignee component', () => {
|
|||
|
||||
const first = collapsedChildren.at(0);
|
||||
|
||||
expect(first.findComponent(GlAvatar).attributes('src')).toBe(users[0].avatar_url);
|
||||
expect(first.findComponent(GlAvatar).attributes('alt')).toBe(`${users[0].name}'s avatar`);
|
||||
expect(first.find('.avatar').attributes('src')).toBe(users[0].avatar_url);
|
||||
expect(first.find('.avatar').attributes('alt')).toBe(`${users[0].name}'s avatar`);
|
||||
|
||||
expect(trimText(first.find('.author').text())).toBe(users[0].name);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import { shallowMount } from '@vue/test-utils';
|
||||
import { GlAvatar } from '@gitlab/ui';
|
||||
import { nextTick } from 'vue';
|
||||
import MrWidgetAuthor from '~/vue_merge_request_widget/components/mr_widget_author.vue';
|
||||
|
||||
|
|
@ -38,7 +37,7 @@ describe('MrWidgetAuthor', () => {
|
|||
});
|
||||
|
||||
it('renders image with avatar url', () => {
|
||||
expect(wrapper.findComponent(GlAvatar).attributes('src')).toBe(
|
||||
expect(wrapper.find('img').attributes('src')).toBe(
|
||||
'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
|
||||
);
|
||||
});
|
||||
|
|
@ -53,7 +52,7 @@ describe('MrWidgetAuthor', () => {
|
|||
|
||||
await nextTick();
|
||||
|
||||
expect(wrapper.findComponent(GlAvatar).props('src')).toBe('no_avatar.png');
|
||||
expect(wrapper.find('img').attributes('src')).toBe('no_avatar.png');
|
||||
});
|
||||
|
||||
it('renders author name', () => {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import Vue from 'vue';
|
||||
import VueApollo from 'vue-apollo';
|
||||
import { GlAvatar, GlDropdownItem } from '@gitlab/ui';
|
||||
import { GlDropdownItem } from '@gitlab/ui';
|
||||
import axios from 'axios';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
|
||||
|
|
@ -146,7 +146,7 @@ describe('Alert Details Sidebar Assignees', () => {
|
|||
props: { alert: mockAlerts[1] },
|
||||
});
|
||||
|
||||
expect(findAssigned().findComponent(GlAvatar).props('src')).toBe('/url');
|
||||
expect(findAssigned().find('img').attributes('src')).toBe('/url');
|
||||
expect(findAssigned().find('.dropdown-menu-user-full-name').text()).toBe('root');
|
||||
expect(findAssigned().find('.dropdown-menu-user-username').text()).toBe('@root');
|
||||
});
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue