Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
ee0b7522d9
commit
60a260df41
2
Gemfile
2
Gemfile
|
@ -536,7 +536,7 @@ gem 'valid_email', '~> 0.1'
|
|||
# JSON
|
||||
gem 'json', '~> 2.5.1'
|
||||
gem 'json_schemer', '~> 0.2.18'
|
||||
gem 'oj', '~> 3.13.17'
|
||||
gem 'oj', '~> 3.13.18'
|
||||
gem 'multi_json', '~> 1.14.1'
|
||||
gem 'yajl-ruby', '~> 1.4.1', require: 'yajl'
|
||||
|
||||
|
|
|
@ -869,7 +869,7 @@ GEM
|
|||
plist (~> 3.1)
|
||||
train-core
|
||||
wmi-lite (~> 1.0)
|
||||
oj (3.13.17)
|
||||
oj (3.13.18)
|
||||
omniauth (1.9.1)
|
||||
hashie (>= 3.4.6)
|
||||
rack (>= 1.6.2, < 3)
|
||||
|
@ -1637,7 +1637,7 @@ DEPENDENCIES
|
|||
oauth2 (~> 2.0)
|
||||
octokit (~> 4.15)
|
||||
ohai (~> 16.10)
|
||||
oj (~> 3.13.17)
|
||||
oj (~> 3.13.18)
|
||||
omniauth (~> 1.8)
|
||||
omniauth-alicloud (~> 1.0.1)
|
||||
omniauth-atlassian-oauth2 (~> 0.2.0)
|
||||
|
|
|
@ -170,7 +170,7 @@ export default {
|
|||
return this.targetType === 'issue';
|
||||
},
|
||||
canAssign() {
|
||||
return this.getNoteableData.current_user?.can_update && this.isIssue;
|
||||
return this.getNoteableData.current_user?.can_set_issue_metadata && this.isIssue;
|
||||
},
|
||||
displayAuthorBadgeText() {
|
||||
return sprintf(__('This user is the author of this %{noteable}.'), {
|
||||
|
|
|
@ -52,31 +52,20 @@ export default {
|
|||
return n__('%d commit', '%d commits', this.isSquashEnabled ? 1 : this.commitsCount);
|
||||
},
|
||||
message() {
|
||||
if (this.glFeatures.restructuredMrWidget) {
|
||||
if (this.state === 'closed') {
|
||||
return s__('mrWidgetCommitsAdded|The changes were not merged into %{targetBranch}.');
|
||||
} else if (this.isMerged) {
|
||||
return s__(
|
||||
'mrWidgetCommitsAdded|Changes merged into %{targetBranch} with %{mergeCommitSha}%{squashedCommits}.',
|
||||
);
|
||||
}
|
||||
|
||||
return this.isFastForwardEnabled
|
||||
? s__('mrWidgetCommitsAdded|%{commitCount} will be added to %{targetBranch}.')
|
||||
: s__(
|
||||
'mrWidgetCommitsAdded|%{commitCount} and %{mergeCommitCount} will be added to %{targetBranch}%{squashedCommits}.',
|
||||
);
|
||||
if (this.state === 'closed') {
|
||||
return s__('mrWidgetCommitsAdded|The changes were not merged into %{targetBranch}.');
|
||||
} else if (this.isMerged) {
|
||||
return s__(
|
||||
'mrWidgetCommitsAdded|Changes merged into %{targetBranch} with %{mergeCommitSha}%{squashedCommits}.',
|
||||
);
|
||||
}
|
||||
|
||||
return this.isFastForwardEnabled
|
||||
? s__('mrWidgetCommitsAdded|Adds %{commitCount} to %{targetBranch}.')
|
||||
? s__('mrWidgetCommitsAdded|%{commitCount} will be added to %{targetBranch}.')
|
||||
: s__(
|
||||
'mrWidgetCommitsAdded|Adds %{commitCount} and %{mergeCommitCount} to %{targetBranch}%{squashedCommits}.',
|
||||
'mrWidgetCommitsAdded|%{commitCount} and %{mergeCommitCount} will be added to %{targetBranch}%{squashedCommits}.',
|
||||
);
|
||||
},
|
||||
textDecorativeComponent() {
|
||||
return this.glFeatures.restructuredMrWidget ? 'span' : 'strong';
|
||||
},
|
||||
squashCommitMessage() {
|
||||
if (this.isMerged) {
|
||||
return s__('mergedCommitsAdded|(commits were squashed)');
|
||||
|
@ -93,25 +82,19 @@ export default {
|
|||
<span>
|
||||
<gl-sprintf :message="message">
|
||||
<template #commitCount>
|
||||
<component :is="textDecorativeComponent" class="commits-count-message">{{
|
||||
commitsCountMessage
|
||||
}}</component>
|
||||
<span class="commits-count-message">{{ commitsCountMessage }}</span>
|
||||
</template>
|
||||
<template #mergeCommitCount>
|
||||
<component :is="textDecorativeComponent">{{ $options.mergeCommitCount }}</component>
|
||||
<span>{{ $options.mergeCommitCount }}</span>
|
||||
</template>
|
||||
<template #targetBranch>
|
||||
<span class="label-branch">{{ targetBranchEscaped }}</span>
|
||||
</template>
|
||||
<template #squashedCommits>
|
||||
<template v-if="glFeatures.restructuredMrWidget && isSquashEnabled">
|
||||
{{ squashCommitMessage }}</template
|
||||
></template
|
||||
>
|
||||
<template v-if="isSquashEnabled"> {{ squashCommitMessage }}</template>
|
||||
</template>
|
||||
<template #mergeCommitSha>
|
||||
<template v-if="glFeatures.restructuredMrWidget"
|
||||
><span class="label-branch">{{ mergeCommitSha }}</span></template
|
||||
>
|
||||
<span class="label-branch">{{ mergeCommitSha }}</span>
|
||||
</template>
|
||||
</gl-sprintf>
|
||||
</span>
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
<script>
|
||||
import { GlSafeHtmlDirective as SafeHtml, GlLink, GlSprintf } from '@gitlab/ui';
|
||||
import { GlSafeHtmlDirective as SafeHtml, GlLink } from '@gitlab/ui';
|
||||
import { s__, n__ } from '~/locale';
|
||||
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
|
||||
|
||||
export default {
|
||||
name: 'MRWidgetRelatedLinks',
|
||||
|
@ -10,9 +9,7 @@ export default {
|
|||
},
|
||||
components: {
|
||||
GlLink,
|
||||
GlSprintf,
|
||||
},
|
||||
mixins: [glFeatureFlagMixin()],
|
||||
props: {
|
||||
relatedLinks: {
|
||||
type: Object,
|
||||
|
@ -67,42 +64,21 @@ export default {
|
|||
</script>
|
||||
<template>
|
||||
<section>
|
||||
<p
|
||||
v-if="relatedLinks.closing"
|
||||
:class="{ 'gl-display-inline gl-m-0': glFeatures.restructuredMrWidget }"
|
||||
>
|
||||
<p v-if="relatedLinks.closing" class="gl-display-inline gl-m-0">
|
||||
{{ closesText }}
|
||||
<span v-safe-html="relatedLinks.closing"></span>
|
||||
</p>
|
||||
<p
|
||||
v-if="relatedLinks.mentioned"
|
||||
:class="{ 'gl-display-inline gl-m-0': glFeatures.restructuredMrWidget }"
|
||||
>
|
||||
<span v-if="relatedLinks.closing && glFeatures.restructuredMrWidget">·</span>
|
||||
<p v-if="relatedLinks.mentioned" class="gl-display-inline gl-m-0">
|
||||
<span v-if="relatedLinks.closing">·</span>
|
||||
{{ n__('mrWidget|Mentions issue', 'mrWidget|Mentions issues', relatedLinks.mentionedCount) }}
|
||||
<span v-safe-html="relatedLinks.mentioned"></span>
|
||||
</p>
|
||||
<p
|
||||
v-if="shouldShowAssignToMeLink"
|
||||
:class="{ 'gl-display-inline gl-m-0': glFeatures.restructuredMrWidget }"
|
||||
>
|
||||
<p v-if="shouldShowAssignToMeLink" class="gl-display-inline gl-m-0">
|
||||
<span>
|
||||
<gl-link rel="nofollow" data-method="post" :href="relatedLinks.assignToMe">{{
|
||||
assignIssueText
|
||||
}}</gl-link>
|
||||
</span>
|
||||
</p>
|
||||
<div
|
||||
v-if="divergedCommitsCount > 0 && !glFeatures.restructuredMrWidget"
|
||||
class="diverged-commits-count"
|
||||
>
|
||||
<gl-sprintf :message="s__('mrWidget|The source branch is %{link} the target branch')">
|
||||
<template #link>
|
||||
<gl-link :href="targetBranchPath">{{
|
||||
n__('%d commit behind', '%d commits behind', divergedCommitsCount)
|
||||
}}</gl-link>
|
||||
</template>
|
||||
</gl-sprintf>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
|
|
@ -1,25 +1,17 @@
|
|||
<script>
|
||||
import { GlButton, GlLoadingIcon } from '@gitlab/ui';
|
||||
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
|
||||
import { GlLoadingIcon } from '@gitlab/ui';
|
||||
import ciIcon from '~/vue_shared/components/ci_icon.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
ciIcon,
|
||||
GlButton,
|
||||
GlLoadingIcon,
|
||||
},
|
||||
mixins: [glFeatureFlagMixin()],
|
||||
props: {
|
||||
status: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
showDisabledButton: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
isLoading() {
|
||||
|
@ -42,15 +34,5 @@ export default {
|
|||
</div>
|
||||
<ci-icon v-else :status="statusObj" :size="24" />
|
||||
</div>
|
||||
|
||||
<gl-button
|
||||
v-if="!glFeatures.restructuredMrWidget && showDisabledButton"
|
||||
category="primary"
|
||||
variant="confirm"
|
||||
data-testid="disabled-merge-button"
|
||||
:disabled="true"
|
||||
>
|
||||
{{ s__('mrWidget|Merge') }}
|
||||
</gl-button>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
<script>
|
||||
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
|
||||
|
||||
export default {
|
||||
mixins: [glFeatureFlagMixin()],
|
||||
props: {
|
||||
value: {
|
||||
type: String,
|
||||
|
@ -23,10 +20,7 @@ export default {
|
|||
<template>
|
||||
<li>
|
||||
<div class="commit-message-editor">
|
||||
<div
|
||||
:class="{ 'gl-mb-3': glFeatures.restructuredMrWidget }"
|
||||
class="d-flex flex-wrap align-items-center justify-content-between"
|
||||
>
|
||||
<div class="d-flex flex-wrap align-items-center justify-content-between gl-mb-3">
|
||||
<label class="col-form-label" :for="inputId">
|
||||
<strong>{{ label }}</strong>
|
||||
</label>
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
<script>
|
||||
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
|
||||
import statusIcon from '../mr_widget_status_icon.vue';
|
||||
|
||||
export default {
|
||||
|
@ -7,7 +6,6 @@ export default {
|
|||
components: {
|
||||
statusIcon,
|
||||
},
|
||||
mixins: [glFeatureFlagMixin()],
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
|
@ -16,7 +14,7 @@ export default {
|
|||
<status-icon status="warning" show-disabled-button />
|
||||
</div>
|
||||
<div class="media-body">
|
||||
<span :class="{ 'gl-ml-0! gl-text-body!': glFeatures.restructuredMrWidget }" class="bold">
|
||||
<span class="gl-ml-0! gl-text-body! bold">
|
||||
{{ s__('mrWidget|Merge unavailable: merge requests are read-only on archived projects.') }}
|
||||
</span>
|
||||
</div>
|
||||
|
|
|
@ -3,7 +3,6 @@ import { GlSkeletonLoader, GlIcon, GlButton, GlSprintf } from '@gitlab/ui';
|
|||
import autoMergeMixin from 'ee_else_ce/vue_merge_request_widget/mixins/auto_merge';
|
||||
import autoMergeEnabledQuery from 'ee_else_ce/vue_merge_request_widget/queries/states/auto_merge_enabled.query.graphql';
|
||||
import createFlash from '~/flash';
|
||||
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
|
||||
import { __ } from '~/locale';
|
||||
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
|
||||
import { AUTO_MERGE_STRATEGIES } from '../../constants';
|
||||
|
@ -78,19 +77,6 @@ export default {
|
|||
autoMergeStrategy() {
|
||||
return (this.glFeatures.mergeRequestWidgetGraphql ? this.state : this.mr).autoMergeStrategy;
|
||||
},
|
||||
canRemoveSourceBranch() {
|
||||
const { currentUserId } = this.mr;
|
||||
const mergeUserId = this.glFeatures.mergeRequestWidgetGraphql
|
||||
? getIdFromGraphQLId(this.state.mergeUser?.id)
|
||||
: this.mr.mergeUserId;
|
||||
const canRemoveSourceBranch = this.glFeatures.mergeRequestWidgetGraphql
|
||||
? this.state.userPermissions.removeSourceBranch
|
||||
: this.mr.canRemoveSourceBranch;
|
||||
|
||||
return (
|
||||
!this.shouldRemoveSourceBranch && canRemoveSourceBranch && mergeUserId === currentUserId
|
||||
);
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
cancelAutomaticMerge() {
|
||||
|
@ -175,24 +161,6 @@ export default {
|
|||
{{ cancelButtonText }}
|
||||
</gl-button>
|
||||
</h4>
|
||||
<section v-if="!glFeatures.restructuredMrWidget" class="mr-info-list">
|
||||
<p v-if="shouldRemoveSourceBranch">
|
||||
{{ s__('mrWidget|Deletes the source branch') }}
|
||||
</p>
|
||||
<p v-else class="gl-display-flex">
|
||||
<span class="gl-mr-3">{{ s__('mrWidget|Does not delete the source branch') }}</span>
|
||||
<gl-button
|
||||
v-if="canRemoveSourceBranch"
|
||||
:loading="isRemovingSourceBranch"
|
||||
size="small"
|
||||
class="js-remove-source-branch"
|
||||
data-testid="removeSourceBranchButton"
|
||||
@click="removeSourceBranch"
|
||||
>
|
||||
{{ s__('mrWidget|Delete source branch') }}
|
||||
</gl-button>
|
||||
</p>
|
||||
</section>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
<script>
|
||||
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
|
||||
import statusIcon from '../mr_widget_status_icon.vue';
|
||||
|
||||
export default {
|
||||
|
@ -7,14 +6,13 @@ export default {
|
|||
components: {
|
||||
statusIcon,
|
||||
},
|
||||
mixins: [glFeatureFlagMixin()],
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<div class="mr-widget-body media">
|
||||
<status-icon :show-disabled-button="true" status="loading" />
|
||||
<div class="media-body space-children">
|
||||
<span :class="{ 'gl-ml-0! gl-text-body!': glFeatures.restructuredMrWidget }" class="bold">
|
||||
<span class="gl-ml-0! gl-text-body! bold">
|
||||
{{ s__('mrWidget|Checking if merge request can be merged…') }}
|
||||
</span>
|
||||
</div>
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
<script>
|
||||
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
|
||||
import MrWidgetAuthorTime from '../mr_widget_author_time.vue';
|
||||
import statusIcon from '../mr_widget_status_icon.vue';
|
||||
|
||||
|
@ -9,7 +8,6 @@ export default {
|
|||
MrWidgetAuthorTime,
|
||||
statusIcon,
|
||||
},
|
||||
mixins: [glFeatureFlagMixin()],
|
||||
props: {
|
||||
/* TODO: This is providing all store and service down when it
|
||||
only needs metrics and targetBranch */
|
||||
|
@ -30,13 +28,6 @@ export default {
|
|||
:date-title="mr.metrics.closedAt"
|
||||
:date-readable="mr.metrics.readableClosedAt"
|
||||
/>
|
||||
|
||||
<section v-if="!glFeatures.restructuredMrWidget" class="mr-info-list">
|
||||
<p>
|
||||
{{ s__('mrWidget|The changes were not merged into') }}
|
||||
<a :href="mr.targetBranchPath" class="label-branch"> {{ mr.targetBranch }} </a>
|
||||
</p>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -97,18 +97,14 @@ export default {
|
|||
</gl-skeleton-loader>
|
||||
</div>
|
||||
<div v-else class="media-body space-children gl-display-flex gl-align-items-center">
|
||||
<span
|
||||
v-if="shouldBeRebased"
|
||||
:class="{ 'gl-ml-0! gl-text-body!': glFeatures.restructuredMrWidget }"
|
||||
class="bold"
|
||||
>
|
||||
<span v-if="shouldBeRebased" class="gl-ml-0! gl-text-body! bold">
|
||||
{{
|
||||
s__(`mrWidget|Merge blocked: fast-forward merge is not possible.
|
||||
To merge this request, first rebase locally.`)
|
||||
}}
|
||||
</span>
|
||||
<template v-else>
|
||||
<span :class="{ 'gl-ml-0! gl-text-body!': glFeatures.restructuredMrWidget }" class="bold">
|
||||
<span class="gl-ml-0! gl-text-body! bold">
|
||||
{{ s__('mrWidget|Merge blocked: merge conflicts must be resolved.') }}
|
||||
<span v-if="!canMerge">
|
||||
{{
|
||||
|
@ -121,14 +117,14 @@ export default {
|
|||
<gl-button
|
||||
v-if="showResolveButton"
|
||||
:href="mr.conflictResolutionPath"
|
||||
:size="glFeatures.restructuredMrWidget ? 'small' : 'medium'"
|
||||
size="small"
|
||||
data-testid="resolve-conflicts-button"
|
||||
>
|
||||
{{ s__('mrWidget|Resolve conflicts') }}
|
||||
</gl-button>
|
||||
<gl-button
|
||||
v-if="canMerge"
|
||||
:size="glFeatures.restructuredMrWidget ? 'small' : 'medium'"
|
||||
size="small"
|
||||
data-testid="merge-locally-button"
|
||||
class="js-check-out-modal-trigger"
|
||||
>
|
||||
|
|
|
@ -1,13 +1,10 @@
|
|||
<script>
|
||||
/* eslint-disable @gitlab/vue-require-i18n-strings */
|
||||
import { GlLoadingIcon, GlButton, GlTooltipDirective, GlIcon } from '@gitlab/ui';
|
||||
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
|
||||
import { GlButton, GlTooltipDirective, GlIcon } from '@gitlab/ui';
|
||||
import api from '~/api';
|
||||
import createFlash from '~/flash';
|
||||
import { s__, __ } from '~/locale';
|
||||
import { OPEN_REVERT_MODAL, OPEN_CHERRY_PICK_MODAL } from '~/projects/commit/constants';
|
||||
import modalEventHub from '~/projects/commit/event_hub';
|
||||
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
|
||||
import eventHub from '../../event_hub';
|
||||
import MrWidgetAuthorTime from '../mr_widget_author_time.vue';
|
||||
|
||||
|
@ -19,11 +16,8 @@ export default {
|
|||
components: {
|
||||
MrWidgetAuthorTime,
|
||||
GlIcon,
|
||||
ClipboardButton,
|
||||
GlLoadingIcon,
|
||||
GlButton,
|
||||
},
|
||||
mixins: [glFeatureFlagMixin()],
|
||||
props: {
|
||||
mr: {
|
||||
type: Object,
|
||||
|
@ -183,41 +177,6 @@ export default {
|
|||
{{ s__('mrWidget|Delete source branch') }}
|
||||
</gl-button>
|
||||
</div>
|
||||
<section
|
||||
v-if="!glFeatures.restructuredMrWidget"
|
||||
class="mr-info-list"
|
||||
data-qa-selector="merged_status_content"
|
||||
>
|
||||
<p>
|
||||
{{ s__('mrWidget|The changes were merged into') }}
|
||||
<span class="label-branch">
|
||||
<a :href="mr.targetBranchPath">{{ mr.targetBranch }}</a>
|
||||
</span>
|
||||
<template v-if="mr.mergeCommitSha">
|
||||
with
|
||||
<a
|
||||
:href="mr.mergeCommitPath"
|
||||
class="commit-sha js-mr-merged-commit-sha"
|
||||
v-text="mr.shortMergeCommitSha"
|
||||
>
|
||||
</a>
|
||||
<clipboard-button
|
||||
:title="__('Copy commit SHA')"
|
||||
:text="mr.mergeCommitSha"
|
||||
css-class="js-mr-merged-copy-sha"
|
||||
category="tertiary"
|
||||
size="small"
|
||||
/>
|
||||
</template>
|
||||
</p>
|
||||
<p v-if="mr.sourceBranchRemoved">
|
||||
{{ s__('mrWidget|The source branch has been deleted') }}
|
||||
</p>
|
||||
<p v-if="shouldShowSourceBranchRemoving">
|
||||
<gl-loading-icon size="sm" :inline="true" />
|
||||
<span> {{ s__('mrWidget|The source branch is being deleted') }} </span>
|
||||
</p>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<script>
|
||||
import { refreshUserMergeRequestCounts } from '~/commons/nav/user_merge_requests';
|
||||
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
|
||||
import simplePoll from '~/lib/utils/simple_poll';
|
||||
import MergeRequest from '~/merge_request';
|
||||
import eventHub from '../../event_hub';
|
||||
|
@ -15,7 +14,6 @@ export default {
|
|||
components: {
|
||||
statusIcon,
|
||||
},
|
||||
mixins: [glFeatureFlagMixin()],
|
||||
props: {
|
||||
mr: {
|
||||
type: Object,
|
||||
|
@ -90,14 +88,6 @@ export default {
|
|||
{{ mergeStatus.message }}
|
||||
<gl-emoji :data-name="mergeStatus.emoji" />
|
||||
</h4>
|
||||
<section v-if="!glFeatures.restructuredMrWidget" class="mr-info-list">
|
||||
<p>
|
||||
{{ s__('mrWidget|Merges changes into') }}
|
||||
<span class="label-branch">
|
||||
<a :href="mr.targetBranchPath">{{ mr.targetBranch }}</a>
|
||||
</span>
|
||||
</p>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -74,13 +74,7 @@ export default {
|
|||
<status-icon :show-disabled-button="true" status="warning" />
|
||||
|
||||
<div class="media-body space-children">
|
||||
<span
|
||||
:class="{
|
||||
'gl-ml-0! gl-text-body!': glFeatures.restructuredMrWidget,
|
||||
}"
|
||||
class="bold js-branch-text"
|
||||
data-testid="widget-content"
|
||||
>
|
||||
<span class="gl-ml-0! gl-text-body! bold js-branch-text" data-testid="widget-content">
|
||||
<gl-sprintf :message="warning">
|
||||
<template #code="{ content }">
|
||||
<code>{{ content }}</code>
|
||||
|
|
|
@ -14,7 +14,7 @@ export default {
|
|||
<div class="mr-widget-body media">
|
||||
<status-icon :show-disabled-button="true" status="warning" />
|
||||
<div class="media-body space-children">
|
||||
<span :class="{ 'gl-ml-0! gl-text-body!': glFeatures.restructuredMrWidget }" class="bold">
|
||||
<span class="gl-ml-0! gl-text-body! bold">
|
||||
{{
|
||||
s__(
|
||||
`mrWidget|Merge blocked: pipeline must succeed. It's waiting for a manual action to continue.`,
|
||||
|
|
|
@ -161,15 +161,13 @@ export default {
|
|||
<div class="rebase-state-find-class-convention media media-body space-children">
|
||||
<span
|
||||
v-if="rebaseInProgress || isMakingRequest"
|
||||
:class="{ 'gl-ml-0! gl-text-body!': glFeatures.restructuredMrWidget }"
|
||||
class="gl-font-weight-bold"
|
||||
class="gl-ml-0! gl-text-body! gl-font-weight-bold"
|
||||
data-testid="rebase-message"
|
||||
>{{ __('Rebase in progress') }}</span
|
||||
>
|
||||
<span
|
||||
v-if="!rebaseInProgress && !canPushToSourceBranch"
|
||||
:class="{ 'gl-text-body!': glFeatures.restructuredMrWidget }"
|
||||
class="gl-font-weight-bold gl-ml-0!"
|
||||
class="gl-text-body! gl-font-weight-bold gl-ml-0!"
|
||||
data-testid="rebase-message"
|
||||
>{{ fastForwardMergeText }}</span
|
||||
>
|
||||
|
@ -177,30 +175,9 @@ export default {
|
|||
v-if="!rebaseInProgress && canPushToSourceBranch && !isMakingRequest"
|
||||
class="accept-merge-holder clearfix js-toggle-container accept-action media space-children gl-align-items-center"
|
||||
>
|
||||
<gl-button
|
||||
v-if="!glFeatures.restructuredMrWidget"
|
||||
:loading="isMakingRequest"
|
||||
variant="confirm"
|
||||
data-qa-selector="mr_rebase_button"
|
||||
data-testid="standard-rebase-button"
|
||||
@click="rebase"
|
||||
>
|
||||
{{ __('Rebase') }}
|
||||
</gl-button>
|
||||
<gl-button
|
||||
v-if="!glFeatures.restructuredMrWidget && showRebaseWithoutCi"
|
||||
:loading="isMakingRequest"
|
||||
variant="confirm"
|
||||
category="secondary"
|
||||
data-testid="rebase-without-ci-button"
|
||||
@click="rebaseWithoutCi"
|
||||
>
|
||||
{{ __('Rebase without pipeline') }}
|
||||
</gl-button>
|
||||
<span
|
||||
v-if="!rebasingError"
|
||||
:class="{ 'gl-ml-0! gl-text-body!': glFeatures.restructuredMrWidget }"
|
||||
class="gl-font-weight-bold"
|
||||
class="gl-ml-0! gl-text-body! gl-font-weight-bold"
|
||||
data-testid="rebase-message"
|
||||
data-qa-selector="no_fast_forward_message_content"
|
||||
>{{
|
||||
|
@ -211,18 +188,18 @@ export default {
|
|||
rebasingError
|
||||
}}</span>
|
||||
<gl-button
|
||||
v-if="glFeatures.restructuredMrWidget"
|
||||
:loading="isMakingRequest"
|
||||
variant="confirm"
|
||||
size="small"
|
||||
data-qa-selector="mr_rebase_button"
|
||||
data-testid="standard-rebase-button"
|
||||
class="gl-ml-3!"
|
||||
@click="rebase"
|
||||
>
|
||||
{{ __('Rebase') }}
|
||||
</gl-button>
|
||||
<gl-button
|
||||
v-if="glFeatures.restructuredMrWidget && showRebaseWithoutCi"
|
||||
v-if="showRebaseWithoutCi"
|
||||
:loading="isMakingRequest"
|
||||
variant="confirm"
|
||||
size="small"
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
<script>
|
||||
import { GlLink, GlSprintf } from '@gitlab/ui';
|
||||
import { helpPagePath } from '~/helpers/help_page_helper';
|
||||
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
|
||||
import { s__ } from '~/locale';
|
||||
import statusIcon from '../mr_widget_status_icon.vue';
|
||||
|
||||
|
@ -12,7 +11,6 @@ export default {
|
|||
GlSprintf,
|
||||
statusIcon,
|
||||
},
|
||||
mixins: [glFeatureFlagMixin()],
|
||||
computed: {
|
||||
troubleshootingDocsPath() {
|
||||
return helpPagePath('ci/troubleshooting', { anchor: 'merge-request-status-messages' });
|
||||
|
@ -30,7 +28,7 @@ export default {
|
|||
<div class="mr-widget-body media">
|
||||
<status-icon :show-disabled-button="true" status="warning" />
|
||||
<div class="media-body space-children">
|
||||
<span :class="{ 'gl-ml-0! gl-text-body!': glFeatures.restructuredMrWidget }" class="bold">
|
||||
<span class="gl-ml-0! gl-text-body! bold">
|
||||
<gl-sprintf :message="$options.i18n.failedMessage">
|
||||
<template #link="{ content }">
|
||||
<gl-link :href="troubleshootingDocsPath" target="_blank">
|
||||
|
|
|
@ -31,12 +31,10 @@ import {
|
|||
import eventHub from '../../event_hub';
|
||||
import mergeRequestQueryVariablesMixin from '../../mixins/merge_request_query_variables';
|
||||
import MergeRequestStore from '../../stores/mr_widget_store';
|
||||
import statusIcon from '../mr_widget_status_icon.vue';
|
||||
import AddedCommitMessage from '../added_commit_message.vue';
|
||||
import RelatedLinks from '../mr_widget_related_links.vue';
|
||||
import CommitEdit from './commit_edit.vue';
|
||||
import CommitMessageDropdown from './commit_message_dropdown.vue';
|
||||
import CommitsHeader from './commits_header.vue';
|
||||
import SquashBeforeMerge from './squash_before_merge.vue';
|
||||
import MergeFailedPipelineConfirmationDialog from './merge_failed_pipeline_confirmation_dialog.vue';
|
||||
|
||||
|
@ -96,9 +94,7 @@ export default {
|
|||
},
|
||||
},
|
||||
components: {
|
||||
statusIcon,
|
||||
SquashBeforeMerge,
|
||||
CommitsHeader,
|
||||
CommitEdit,
|
||||
CommitMessageDropdown,
|
||||
GlIcon,
|
||||
|
@ -320,34 +316,24 @@ export default {
|
|||
showDangerMessageForMergeTrain() {
|
||||
return this.preferredAutoMergeStrategy === MT_MERGE_STRATEGY && this.isPipelineFailed;
|
||||
},
|
||||
restructuredWidgetShowMergeButtons() {
|
||||
if (this.glFeatures.restructuredMrWidget) {
|
||||
return (
|
||||
(this.isMergeAllowed || this.isAutoMergeAvailable) &&
|
||||
this.state.userPermissions.canMerge &&
|
||||
!this.mr.mergeOngoing &&
|
||||
!this.mr.autoMergeEnabled
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
shouldShowMergeControls() {
|
||||
return (
|
||||
(this.isMergeAllowed || this.isAutoMergeAvailable) &&
|
||||
(this.stateData.userPermissions?.canMerge || this.mr.canMerge) &&
|
||||
!this.mr.mergeOngoing &&
|
||||
!this.mr.autoMergeEnabled
|
||||
);
|
||||
},
|
||||
sourceBranchDeletedText() {
|
||||
if (this.glFeatures.restructuredMrWidget) {
|
||||
if (this.removeSourceBranch) {
|
||||
return this.mr.state === 'merged'
|
||||
? __('Deleted the source branch.')
|
||||
: __('Source branch will be deleted.');
|
||||
}
|
||||
|
||||
if (this.removeSourceBranch) {
|
||||
return this.mr.state === 'merged'
|
||||
? __('Did not delete the source branch.')
|
||||
: __('Source branch will not be deleted.');
|
||||
? __('Deleted the source branch.')
|
||||
: __('Source branch will be deleted.');
|
||||
}
|
||||
|
||||
return this.removeSourceBranch
|
||||
? __('Deletes the source branch.')
|
||||
: __('Does not delete the source branch.');
|
||||
return this.mr.state === 'merged'
|
||||
? __('Did not delete the source branch.')
|
||||
: __('Source branch will not be deleted.');
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
|
@ -525,10 +511,7 @@ export default {
|
|||
<template>
|
||||
<div
|
||||
data-testid="ready_to_merge_state"
|
||||
:class="{
|
||||
'gl-border-t-1 gl-border-t-solid gl-border-gray-100 gl-bg-gray-10 gl-pl-7 gl-rounded-bottom-left-base gl-rounded-bottom-right-base':
|
||||
glFeatures.restructuredMrWidget,
|
||||
}"
|
||||
class="gl-border-t-1 gl-border-t-solid gl-border-gray-100 gl-bg-gray-10 gl-pl-7 gl-rounded-bottom-left-base gl-rounded-bottom-right-base"
|
||||
>
|
||||
<div v-if="loading" class="mr-widget-body">
|
||||
<div class="gl-w-full mr-ready-to-merge-loader">
|
||||
|
@ -541,16 +524,10 @@ export default {
|
|||
</div>
|
||||
</div>
|
||||
<template v-else>
|
||||
<div
|
||||
class="mr-widget-body media"
|
||||
:class="{
|
||||
'mr-widget-body-line-height-1': glFeatures.restructuredMrWidget,
|
||||
}"
|
||||
>
|
||||
<status-icon v-if="!glFeatures.restructuredMrWidget" :status="iconClass" />
|
||||
<div class="mr-widget-body media mr-widget-body-line-height-1">
|
||||
<div class="media-body">
|
||||
<div class="mr-widget-body-controls gl-display-flex gl-align-items-center gl-flex-wrap">
|
||||
<gl-button-group v-if="restructuredWidgetShowMergeButtons" class="gl-align-self-start">
|
||||
<gl-button-group v-if="shouldShowMergeControls" class="gl-align-self-start">
|
||||
<gl-button
|
||||
size="medium"
|
||||
category="primary"
|
||||
|
@ -603,19 +580,14 @@ export default {
|
|||
<merge-train-helper-icon v-if="shouldRenderMergeTrainHelperIcon" class="gl-mx-3" />
|
||||
<div
|
||||
v-if="shouldShowMergeControls"
|
||||
:class="{ 'gl-w-full gl-order-n1 gl-mb-5': glFeatures.restructuredMrWidget }"
|
||||
class="gl-display-flex gl-align-items-center gl-flex-wrap"
|
||||
class="gl-display-flex gl-align-items-center gl-flex-wrap gl-w-full gl-order-n1 gl-mb-5"
|
||||
>
|
||||
<gl-form-checkbox
|
||||
v-if="canRemoveSourceBranch"
|
||||
id="remove-source-branch-input"
|
||||
v-model="removeSourceBranch"
|
||||
:disabled="isRemoveSourceBranchButtonDisabled"
|
||||
:class="{
|
||||
'gl-mx-3': !glFeatures.restructuredMrWidget,
|
||||
'gl-mr-5': glFeatures.restructuredMrWidget,
|
||||
}"
|
||||
class="js-remove-source-branch-checkbox gl-display-flex gl-align-items-center"
|
||||
class="js-remove-source-branch-checkbox gl-display-flex gl-align-items-center gl-mr-5"
|
||||
>
|
||||
{{ __('Delete source branch') }}
|
||||
</gl-form-checkbox>
|
||||
|
@ -626,16 +598,11 @@ export default {
|
|||
v-model="squashBeforeMerge"
|
||||
:help-path="mr.squashBeforeMergeHelpPath"
|
||||
:is-disabled="isSquashReadOnly"
|
||||
:class="{
|
||||
'gl-mx-3': !glFeatures.restructuredMrWidget,
|
||||
'gl-mr-5': glFeatures.restructuredMrWidget,
|
||||
}"
|
||||
class="gl-mr-5"
|
||||
/>
|
||||
|
||||
<gl-form-checkbox
|
||||
v-if="
|
||||
glFeatures.restructuredMrWidget && (shouldShowSquashEdit || shouldShowMergeEdit)
|
||||
"
|
||||
v-if="shouldShowSquashEdit || shouldShowMergeEdit"
|
||||
v-model="editCommitMessage"
|
||||
data-testid="widget_edit_commit_message"
|
||||
class="gl-display-flex gl-align-items-center"
|
||||
|
@ -644,198 +611,113 @@ export default {
|
|||
</gl-form-checkbox>
|
||||
</div>
|
||||
<div
|
||||
v-else-if="!glFeatures.restructuredMrWidget"
|
||||
class="bold js-resolve-mr-widget-items-message gl-ml-3"
|
||||
v-if="editCommitMessage"
|
||||
class="gl-w-full gl-order-n1"
|
||||
data-testid="edit_commit_message"
|
||||
>
|
||||
<div
|
||||
v-if="hasPipelineMustSucceedConflict"
|
||||
class="gl-display-flex gl-align-items-center"
|
||||
data-testid="pipeline-succeed-conflict"
|
||||
>
|
||||
<gl-sprintf :message="pipelineMustSucceedConflictText" />
|
||||
<gl-link
|
||||
:href="mr.pipelineMustSucceedDocsPath"
|
||||
target="_blank"
|
||||
class="gl-display-flex gl-ml-2"
|
||||
<ul class="border-top commits-list flex-list gl-list-style-none gl-p-0 gl-pt-4">
|
||||
<commit-edit
|
||||
v-if="shouldShowSquashEdit"
|
||||
:value="squashCommitMessage"
|
||||
:label="__('Squash commit message')"
|
||||
input-id="squash-message-edit"
|
||||
class="gl-m-0! gl-p-0!"
|
||||
@input="setSquashCommitMessage"
|
||||
>
|
||||
<gl-icon name="question" />
|
||||
</gl-link>
|
||||
</div>
|
||||
<gl-sprintf v-else :message="mergeDisabledText" />
|
||||
</div>
|
||||
<template v-if="glFeatures.restructuredMrWidget">
|
||||
<div
|
||||
v-if="editCommitMessage"
|
||||
class="gl-w-full gl-order-n1"
|
||||
data-testid="edit_commit_message"
|
||||
>
|
||||
<ul
|
||||
:class="{
|
||||
'content-list': !glFeatures.restructuredMrWidget,
|
||||
'gl-list-style-none gl-p-0 gl-pt-4': glFeatures.restructuredMrWidget,
|
||||
}"
|
||||
class="border-top commits-list flex-list"
|
||||
>
|
||||
<commit-edit
|
||||
v-if="shouldShowSquashEdit"
|
||||
:value="squashCommitMessage"
|
||||
:label="__('Squash commit message')"
|
||||
input-id="squash-message-edit"
|
||||
class="gl-m-0! gl-p-0!"
|
||||
@input="setSquashCommitMessage"
|
||||
>
|
||||
<template #header>
|
||||
<commit-message-dropdown :commits="commits" @input="setSquashCommitMessage" />
|
||||
</template>
|
||||
</commit-edit>
|
||||
<commit-edit
|
||||
v-if="shouldShowMergeEdit"
|
||||
:value="commitMessage"
|
||||
:label="__('Merge commit message')"
|
||||
input-id="merge-message-edit"
|
||||
class="gl-m-0! gl-p-0!"
|
||||
@input="setCommitMessage"
|
||||
/>
|
||||
<li class="gl-m-0! gl-p-0!">
|
||||
<p class="form-text text-muted">
|
||||
<gl-sprintf :message="commitTemplateHintText">
|
||||
<template #link="{ content }">
|
||||
<gl-link
|
||||
:href="commitTemplateHelpPage"
|
||||
class="inline-link"
|
||||
target="_blank"
|
||||
>
|
||||
{{ content }}
|
||||
</gl-link>
|
||||
</template>
|
||||
</gl-sprintf>
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div
|
||||
v-if="!restructuredWidgetShowMergeButtons"
|
||||
class="gl-w-full gl-order-n1 gl-text-gray-500"
|
||||
data-qa-selector="merged_status_content"
|
||||
>
|
||||
<strong v-if="mr.state !== 'closed'">
|
||||
{{ __('Merge details') }}
|
||||
</strong>
|
||||
<ul class="gl-pl-4 gl-m-0">
|
||||
<li v-if="mr.divergedCommitsCount > 0" class="gl-line-height-normal">
|
||||
<gl-sprintf
|
||||
:message="s__('mrWidget|The source branch is %{link} the target branch')"
|
||||
>
|
||||
<template #link>
|
||||
<gl-link :href="mr.targetBranchPath">{{
|
||||
n__('%d commit behind', '%d commits behind', mr.divergedCommitsCount)
|
||||
}}</gl-link>
|
||||
<template #header>
|
||||
<commit-message-dropdown :commits="commits" @input="setSquashCommitMessage" />
|
||||
</template>
|
||||
</commit-edit>
|
||||
<commit-edit
|
||||
v-if="shouldShowMergeEdit"
|
||||
:value="commitMessage"
|
||||
:label="__('Merge commit message')"
|
||||
input-id="merge-message-edit"
|
||||
class="gl-m-0! gl-p-0!"
|
||||
@input="setCommitMessage"
|
||||
/>
|
||||
<li class="gl-m-0! gl-p-0!">
|
||||
<p class="form-text text-muted">
|
||||
<gl-sprintf :message="commitTemplateHintText">
|
||||
<template #link="{ content }">
|
||||
<gl-link :href="commitTemplateHelpPage" class="inline-link" target="_blank">
|
||||
{{ content }}
|
||||
</gl-link>
|
||||
</template>
|
||||
</gl-sprintf>
|
||||
</li>
|
||||
<li class="gl-line-height-normal">
|
||||
<added-commit-message
|
||||
:state="mr.state"
|
||||
:merge-commit-sha="mr.shortMergeCommitSha"
|
||||
:is-squash-enabled="squashBeforeMerge"
|
||||
:is-fast-forward-enabled="!shouldShowMergeEdit"
|
||||
:commits-count="commitsCount"
|
||||
:target-branch="stateData.targetBranch"
|
||||
/>
|
||||
</li>
|
||||
<li v-if="mr.state !== 'closed'" class="gl-line-height-normal">
|
||||
{{ sourceBranchDeletedText }}
|
||||
</li>
|
||||
<li v-if="mr.relatedLinks" class="gl-line-height-normal">
|
||||
<related-links
|
||||
:state="mr.state"
|
||||
:related-links="mr.relatedLinks"
|
||||
:show-assign-to-me="false"
|
||||
class="mr-ready-merge-related-links gl-display-inline"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div
|
||||
v-else
|
||||
:class="{ 'gl-mb-5': restructuredWidgetShowMergeButtons }"
|
||||
class="gl-w-full gl-order-n1 gl-text-gray-500"
|
||||
>
|
||||
<added-commit-message
|
||||
:is-squash-enabled="squashBeforeMerge"
|
||||
:is-fast-forward-enabled="!shouldShowMergeEdit"
|
||||
:commits-count="commitsCount"
|
||||
:target-branch="stateData.targetBranch"
|
||||
/>
|
||||
<template v-if="mr.relatedLinks">
|
||||
·
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div
|
||||
v-if="!shouldShowMergeControls"
|
||||
class="gl-w-full gl-order-n1 gl-text-gray-500"
|
||||
data-qa-selector="merged_status_content"
|
||||
>
|
||||
<strong v-if="mr.state !== 'closed'">
|
||||
{{ __('Merge details') }}
|
||||
</strong>
|
||||
<ul class="gl-pl-4 gl-m-0">
|
||||
<li v-if="mr.divergedCommitsCount > 0" class="gl-line-height-normal">
|
||||
<gl-sprintf
|
||||
:message="s__('mrWidget|The source branch is %{link} the target branch')"
|
||||
>
|
||||
<template #link>
|
||||
<gl-link :href="mr.targetBranchPath">{{
|
||||
n__('%d commit behind', '%d commits behind', mr.divergedCommitsCount)
|
||||
}}</gl-link>
|
||||
</template>
|
||||
</gl-sprintf>
|
||||
</li>
|
||||
<li class="gl-line-height-normal">
|
||||
<added-commit-message
|
||||
:state="mr.state"
|
||||
:merge-commit-sha="mr.shortMergeCommitSha"
|
||||
:is-squash-enabled="squashBeforeMerge"
|
||||
:is-fast-forward-enabled="!shouldShowMergeEdit"
|
||||
:commits-count="commitsCount"
|
||||
:target-branch="stateData.targetBranch"
|
||||
/>
|
||||
</li>
|
||||
<li v-if="mr.state !== 'closed'" class="gl-line-height-normal">
|
||||
{{ sourceBranchDeletedText }}
|
||||
</li>
|
||||
<li v-if="mr.relatedLinks" class="gl-line-height-normal">
|
||||
<related-links
|
||||
:state="mr.state"
|
||||
:related-links="mr.relatedLinks"
|
||||
:show-assign-to-me="false"
|
||||
:diverged-commits-count="mr.divergedCommitsCount"
|
||||
:target-branch-path="mr.targetBranchPath"
|
||||
class="mr-ready-merge-related-links gl-display-inline"
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<div
|
||||
v-if="showDangerMessageForMergeTrain && !glFeatures.restructuredMrWidget"
|
||||
class="gl-mt-5 gl-text-gray-500"
|
||||
data-testid="failed-pipeline-merge-train-text"
|
||||
>
|
||||
{{ __('The latest pipeline for this merge request did not complete successfully.') }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div
|
||||
v-else
|
||||
:class="{ 'gl-mb-5': shouldShowMergeControls }"
|
||||
class="gl-w-full gl-order-n1 gl-text-gray-500"
|
||||
>
|
||||
<added-commit-message
|
||||
:is-squash-enabled="squashBeforeMerge"
|
||||
:is-fast-forward-enabled="!shouldShowMergeEdit"
|
||||
:commits-count="commitsCount"
|
||||
:target-branch="stateData.targetBranch"
|
||||
/>
|
||||
<template v-if="mr.relatedLinks">
|
||||
·
|
||||
<related-links
|
||||
:state="mr.state"
|
||||
:related-links="mr.relatedLinks"
|
||||
:show-assign-to-me="false"
|
||||
:diverged-commits-count="mr.divergedCommitsCount"
|
||||
:target-branch-path="mr.targetBranchPath"
|
||||
class="mr-ready-merge-related-links gl-display-inline"
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<template v-if="shouldShowMergeControls && !glFeatures.restructuredMrWidget">
|
||||
<div v-if="!shouldShowMergeEdit" class="mr-fast-forward-message">
|
||||
{{ __('Fast-forward merge without a merge commit') }}
|
||||
</div>
|
||||
<commits-header
|
||||
v-if="!glFeatures.restructuredMrWidget && (shouldShowSquashEdit || shouldShowMergeEdit)"
|
||||
:is-squash-enabled="squashBeforeMerge"
|
||||
:commits-count="commitsCount"
|
||||
:target-branch="stateData.targetBranch"
|
||||
:is-fast-forward-enabled="!shouldShowMergeEdit"
|
||||
:class="{ 'border-bottom': stateData.mergeError }"
|
||||
>
|
||||
<ul class="border-top content-list commits-list flex-list">
|
||||
<commit-edit
|
||||
v-if="shouldShowSquashEdit"
|
||||
:value="squashCommitMessage"
|
||||
:label="__('Squash commit message')"
|
||||
input-id="squash-message-edit"
|
||||
squash
|
||||
@input="setSquashCommitMessage"
|
||||
>
|
||||
<template #header>
|
||||
<commit-message-dropdown :commits="commits" @input="setSquashCommitMessage" />
|
||||
</template>
|
||||
</commit-edit>
|
||||
<commit-edit
|
||||
v-if="shouldShowMergeEdit"
|
||||
:value="commitMessage"
|
||||
:label="__('Merge commit message')"
|
||||
input-id="merge-message-edit"
|
||||
@input="setCommitMessage"
|
||||
/>
|
||||
<li>
|
||||
<p class="form-text text-muted">
|
||||
<gl-sprintf :message="commitTemplateHintText">
|
||||
<template #link="{ content }">
|
||||
<gl-link :href="commitTemplateHelpPage" class="inline-link" target="_blank">
|
||||
{{ content }}
|
||||
</gl-link>
|
||||
</template>
|
||||
</gl-sprintf>
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
</commits-header>
|
||||
</template>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<script>
|
||||
import { GlButton } from '@gitlab/ui';
|
||||
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
|
||||
import { I18N_SHA_MISMATCH } from '../../i18n';
|
||||
import statusIcon from '../mr_widget_status_icon.vue';
|
||||
|
||||
|
@ -13,7 +12,6 @@ export default {
|
|||
i18n: {
|
||||
I18N_SHA_MISMATCH,
|
||||
},
|
||||
mixins: [glFeatureFlagMixin()],
|
||||
props: {
|
||||
mr: {
|
||||
type: Object,
|
||||
|
@ -28,8 +26,7 @@ export default {
|
|||
<status-icon :show-disabled-button="false" status="warning" />
|
||||
<div class="media-body">
|
||||
<span
|
||||
:class="{ 'gl-ml-0! gl-text-body!': glFeatures.restructuredMrWidget }"
|
||||
class="gl-font-weight-bold"
|
||||
class="gl-ml-0! gl-text-body! gl-font-weight-bold"
|
||||
data-qa-selector="head_mismatch_content"
|
||||
>
|
||||
{{ $options.i18n.I18N_SHA_MISMATCH.warningMessage }}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<script>
|
||||
import { GlIcon, GlTooltipDirective, GlFormCheckbox, GlLink } from '@gitlab/ui';
|
||||
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
|
||||
import { SQUASH_BEFORE_MERGE } from '../../i18n';
|
||||
|
||||
export default {
|
||||
|
@ -12,7 +11,6 @@ export default {
|
|||
directives: {
|
||||
GlTooltip: GlTooltipDirective,
|
||||
},
|
||||
mixins: [glFeatureFlagsMixin()],
|
||||
i18n: {
|
||||
...SQUASH_BEFORE_MERGE,
|
||||
},
|
||||
|
@ -36,9 +34,6 @@ export default {
|
|||
tooltipTitle() {
|
||||
return this.isDisabled ? this.$options.i18n.tooltipTitle : null;
|
||||
},
|
||||
helpIconName() {
|
||||
return this.glFeatures.restructuredMrWidget ? 'question-o' : 'question';
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
@ -62,10 +57,10 @@ export default {
|
|||
v-gl-tooltip
|
||||
:href="helpPath"
|
||||
:title="$options.i18n.helpLabel"
|
||||
:class="{ 'gl-text-blue-600': glFeatures.restructuredMrWidget }"
|
||||
class="gl-text-blue-600"
|
||||
target="_blank"
|
||||
>
|
||||
<gl-icon :name="helpIconName" />
|
||||
<gl-icon name="question-o" />
|
||||
<span class="sr-only">
|
||||
{{ $options.i18n.helpLabel }}
|
||||
</span>
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<script>
|
||||
import { GlButton } from '@gitlab/ui';
|
||||
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
|
||||
import notesEventHub from '~/notes/event_hub';
|
||||
import statusIcon from '../mr_widget_status_icon.vue';
|
||||
|
||||
|
@ -10,7 +9,6 @@ export default {
|
|||
statusIcon,
|
||||
GlButton,
|
||||
},
|
||||
mixins: [glFeatureFlagMixin()],
|
||||
props: {
|
||||
mr: {
|
||||
type: Object,
|
||||
|
@ -29,22 +27,15 @@ export default {
|
|||
<div class="mr-widget-body media gl-flex-wrap">
|
||||
<status-icon show-disabled-button status="warning" />
|
||||
<div class="media-body">
|
||||
<span
|
||||
:class="{
|
||||
'gl-ml-0! gl-text-body!': glFeatures.restructuredMrWidget,
|
||||
'gl-display-block': !glFeatures.restructuredMrWidget,
|
||||
}"
|
||||
class="gl-ml-3 gl-font-weight-bold gl-w-100"
|
||||
>
|
||||
<span class="gl-ml-0! gl-text-body! gl-ml-3 gl-font-weight-bold gl-w-100">
|
||||
{{ s__('mrWidget|Merge blocked: all threads must be resolved.') }}
|
||||
</span>
|
||||
<gl-button
|
||||
data-testid="jump-to-first"
|
||||
class="gl-ml-3"
|
||||
size="small"
|
||||
:icon="glFeatures.restructuredMrWidget ? undefined : 'comment-next'"
|
||||
:variant="glFeatures.restructuredMrWidget ? 'confirm' : 'default'"
|
||||
:category="glFeatures.restructuredMrWidget ? 'secondary' : 'primary'"
|
||||
variant="confirm"
|
||||
category="secondary"
|
||||
@click="jumpToFirstUnresolvedDiscussion"
|
||||
>
|
||||
{{ s__('mrWidget|Jump to first unresolved thread') }}
|
||||
|
@ -54,7 +45,6 @@ export default {
|
|||
:href="mr.createIssueToResolveDiscussionsPath"
|
||||
class="js-create-issue gl-ml-3"
|
||||
size="small"
|
||||
:icon="glFeatures.restructuredMrWidget ? undefined : 'issue-new'"
|
||||
>
|
||||
{{ s__('mrWidget|Create issue to resolve all threads') }}
|
||||
</gl-button>
|
||||
|
|
|
@ -167,10 +167,7 @@ export default {
|
|||
<status-icon :show-disabled-button="canUpdate" status="warning" />
|
||||
<div class="media-body">
|
||||
<div class="float-left">
|
||||
<span
|
||||
:class="{ 'gl-ml-0! gl-text-body!': glFeatures.restructuredMrWidget }"
|
||||
class="gl-font-weight-bold"
|
||||
>
|
||||
<span class="gl-ml-0! gl-text-body! gl-font-weight-bold">
|
||||
{{
|
||||
__("Merge blocked: merge request must be marked as ready. It's still marked as draft.")
|
||||
}}
|
||||
|
|
|
@ -20,13 +20,6 @@ export default {
|
|||
this.mr.preventMerge,
|
||||
);
|
||||
},
|
||||
shouldShowMergeControls() {
|
||||
if (this.glFeatures.restructuredMrWidget) {
|
||||
return this.restructuredWidgetShowMergeButtons;
|
||||
}
|
||||
|
||||
return this.isMergeAllowed || this.isAutoMergeAvailable;
|
||||
},
|
||||
mergeDisabledText() {
|
||||
if (this.pipeline?.status === PIPELINE_SKIPPED_STATUS) {
|
||||
return MERGE_DISABLED_SKIPPED_PIPELINE_TEXT;
|
||||
|
|
|
@ -17,7 +17,6 @@ import { setFaviconOverlay } from '../lib/utils/favicon';
|
|||
import Loading from './components/loading.vue';
|
||||
import MrWidgetAlertMessage from './components/mr_widget_alert_message.vue';
|
||||
import MrWidgetPipelineContainer from './components/mr_widget_pipeline_container.vue';
|
||||
import WidgetRelatedLinks from './components/mr_widget_related_links.vue';
|
||||
import WidgetSuggestPipeline from './components/mr_widget_suggest_pipeline.vue';
|
||||
import SourceBranchRemovalStatus from './components/source_branch_removal_status.vue';
|
||||
import ArchivedState from './components/states/mr_widget_archived.vue';
|
||||
|
@ -61,7 +60,6 @@ export default {
|
|||
ExtensionsContainer,
|
||||
'mr-widget-suggest-pipeline': WidgetSuggestPipeline,
|
||||
MrWidgetPipelineContainer,
|
||||
'mr-widget-related-links': WidgetRelatedLinks,
|
||||
MrWidgetAlertMessage,
|
||||
'mr-widget-merged': MergedState,
|
||||
'mr-widget-closed': ClosedState,
|
||||
|
@ -73,9 +71,7 @@ export default {
|
|||
'mr-widget-nothing-to-merge': NothingToMergeState,
|
||||
'mr-widget-not-allowed': NotAllowedState,
|
||||
'mr-widget-missing-branch': MissingBranchState,
|
||||
'mr-widget-ready-to-merge': window.gon?.features?.restructuredMrWidget
|
||||
? () => import('./components/states/new_ready_to_merge.vue')
|
||||
: ReadyToMergeState,
|
||||
'mr-widget-ready-to-merge': () => import('./components/states/new_ready_to_merge.vue'),
|
||||
'sha-mismatch': ShaMismatch,
|
||||
'mr-widget-checking': CheckingState,
|
||||
'mr-widget-unresolved-discussions': UnresolvedDiscussionsState,
|
||||
|
@ -163,12 +159,6 @@ export default {
|
|||
shouldRenderCodeQuality() {
|
||||
return this.mr?.codequalityReportsPath;
|
||||
},
|
||||
shouldRenderRelatedLinks() {
|
||||
return (
|
||||
(Boolean(this.mr.relatedLinks) || this.mr.divergedCommitsCount > 0) &&
|
||||
!this.mr.isNothingToMergeState
|
||||
);
|
||||
},
|
||||
shouldRenderSourceBranchRemovalStatus() {
|
||||
return (
|
||||
!this.mr.canRemoveSourceBranch &&
|
||||
|
@ -239,9 +229,6 @@ export default {
|
|||
shouldShowCodeQualityExtension() {
|
||||
return window.gon?.features?.refactorCodeQualityExtension;
|
||||
},
|
||||
isRestructuredMrWidgetEnabled() {
|
||||
return window.gon?.features?.restructuredMrWidget;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
'mr.machineValue': {
|
||||
|
@ -638,23 +625,7 @@ export default {
|
|||
|
||||
<div class="mr-widget-section" data-qa-selector="mr_widget_content">
|
||||
<component :is="componentName" :mr="mr" :service="service" />
|
||||
<ready-to-merge
|
||||
v-if="isRestructuredMrWidgetEnabled && mr.commitsCount"
|
||||
:mr="mr"
|
||||
:service="service"
|
||||
/>
|
||||
<div v-else class="mr-widget-info">
|
||||
<mr-widget-related-links
|
||||
v-if="shouldRenderRelatedLinks"
|
||||
:state="mr.state"
|
||||
:related-links="mr.relatedLinks"
|
||||
:diverged-commits-count="mr.divergedCommitsCount"
|
||||
:target-branch-path="mr.targetBranchPath"
|
||||
class="mr-info-list gl-ml-7 gl-pb-5"
|
||||
/>
|
||||
|
||||
<source-branch-removal-status v-if="shouldRenderSourceBranchRemovalStatus" />
|
||||
</div>
|
||||
<ready-to-merge v-if="mr.commitsCount" :mr="mr" :service="service" />
|
||||
</div>
|
||||
</div>
|
||||
<mr-widget-pipeline-container
|
||||
|
|
|
@ -27,8 +27,6 @@ export default function deviseState() {
|
|||
return stateKey.shaMismatch;
|
||||
} else if (this.autoMergeEnabled && !this.mergeError) {
|
||||
return stateKey.autoMergeEnabled;
|
||||
} else if (!this.canMerge && !window.gon?.features?.restructuredMrWidget) {
|
||||
return stateKey.notAllowedToMerge;
|
||||
} else if (this.canBeMerged) {
|
||||
return stateKey.readyToMerge;
|
||||
}
|
||||
|
|
|
@ -34,7 +34,6 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
|
|||
before_action only: [:show] do
|
||||
push_frontend_feature_flag(:merge_request_widget_graphql, project)
|
||||
push_frontend_feature_flag(:core_security_mr_widget_counts, project)
|
||||
push_frontend_feature_flag(:restructured_mr_widget, project)
|
||||
push_frontend_feature_flag(:refactor_mr_widgets_extensions, project)
|
||||
push_frontend_feature_flag(:refactor_code_quality_extension, project)
|
||||
push_frontend_feature_flag(:refactor_mr_widget_test_summary, project)
|
||||
|
|
|
@ -47,6 +47,10 @@ class IssueEntity < IssuableEntity
|
|||
can?(request.current_user, :update_issue, issue)
|
||||
end
|
||||
|
||||
expose :can_set_issue_metadata do |issue|
|
||||
can?(request.current_user, :set_issue_metadata, issue)
|
||||
end
|
||||
|
||||
expose :can_award_emoji do |issue|
|
||||
can?(request.current_user, :award_emoji, issue)
|
||||
end
|
||||
|
|
|
@ -4,7 +4,8 @@
|
|||
= s_('GitLabPages|Configure pages')
|
||||
.card-body
|
||||
%p.gl-mb-0
|
||||
- docs_link_start = "<a href='#{help_page_path('user/project/pages/index')}' target='_blank' rel='noopener noreferrer'>".html_safe
|
||||
- samples_link_start = "<a href='https://gitlab.com/pages' target='_blank' rel='noopener noreferrer'>".html_safe
|
||||
- docs_link_start = "<a href='#{help_page_path('user/project/pages/index')}' target='_blank' rel='noopener noreferrer' data-track-action='click_link' data-track-label='pages_docs_link'>".html_safe
|
||||
- samples_link_start = "<a href='https://gitlab.com/pages' target='_blank' rel='noopener noreferrer' data-track-action='click_link' data-track-label='pages_samples_link>"
|
||||
.html_safe
|
||||
- link_end = '</a>'.html_safe
|
||||
= s_('GitLabPages|Your Pages site is not configured yet. See the %{docs_link_start}GitLab Pages documentation%{link_end} to learn how to upload your static site and have GitLab serve it. You can also take some inspiration from the %{samples_link_start}sample Pages projects%{link_end}.').html_safe % { docs_link_start: docs_link_start, samples_link_start: samples_link_start, link_end: link_end }
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
- project = @target_project || @project
|
||||
- presenter = local_assigns.fetch(:presenter, nil)
|
||||
|
||||
= form_errors(issuable)
|
||||
= form_errors(issuable, pajamas_alert: true)
|
||||
|
||||
- if @conflict
|
||||
= render Pajamas::AlertComponent.new(variant: :danger,
|
||||
|
|
|
@ -7,7 +7,7 @@ module WaitableWorker
|
|||
# Schedules multiple jobs and waits for them to be completed.
|
||||
def bulk_perform_and_wait(args_list)
|
||||
# Short-circuit: it's more efficient to do small numbers of jobs inline
|
||||
if args_list.size == 1
|
||||
if args_list.size == 1 && !always_async_project_authorizations_refresh?
|
||||
return bulk_perform_inline(args_list)
|
||||
end
|
||||
|
||||
|
@ -29,6 +29,10 @@ module WaitableWorker
|
|||
|
||||
bulk_perform_async(failed) if failed.present?
|
||||
end
|
||||
|
||||
def always_async_project_authorizations_refresh?
|
||||
Feature.enabled?(:always_async_project_authorizations_refresh)
|
||||
end
|
||||
end
|
||||
|
||||
def perform(*args)
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
name: restructured_mr_widget
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/68565
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/339181
|
||||
milestone: '14.3'
|
||||
name: always_async_project_authorizations_refresh
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/92333
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/367683
|
||||
milestone: '15.3'
|
||||
type: development
|
||||
group: group::code review
|
||||
default_enabled: true
|
||||
group: group::workspace
|
||||
default_enabled: false
|
|
@ -23,7 +23,7 @@ The following lists the currently supported OSs and their possible EOL dates.
|
|||
| Debian 10 | GitLab CE / GitLab EE 12.2.0 | amd64, arm64 | [Debian Install Documentation](https://about.gitlab.com/install/#debian) | 2024 | <https://wiki.debian.org/LTS> |
|
||||
| Debian 11 | GitLab CE / GitLab EE 14.6.0 | amd64, arm64 | [Debian Install Documentation](https://about.gitlab.com/install/#debian) | 2026 | <https://wiki.debian.org/LTS> |
|
||||
| OpenSUSE 15.3 | GitLab CE / GitLab EE 14.5.0 | x86_64, aarch64 | [OpenSUSE Install Documentation](https://about.gitlab.com/install/#opensuse-leap-15-3) | Nov 2022 | <https://en.opensuse.org/Lifetime> |
|
||||
| RHEL 8 | GitLab CE / GitLab EE 12.8.1 | x86_64, arm64 | [Use CentOS Install Documentation](https://about.gitlab.com/install/#centos-7) | May 2024 | [RHEL Details](https://access.redhat.com/support/policy/updates/errata/#Life_Cycle_Dates) |
|
||||
| RHEL 8 | GitLab CE / GitLab EE 12.8.1 | x86_64, arm64 | [Use CentOS Install Documentation](https://about.gitlab.com/install/#centos-7) | May 2029 | [RHEL Details](https://access.redhat.com/support/policy/updates/errata/#Life_Cycle_Dates) |
|
||||
| SLES 12 | GitLab EE 9.0.0 | x86_64 | [Use OpenSUSE Install Documentation](https://about.gitlab.com/install/#opensuse-leap-15-3) | Oct 2027 | <https://www.suse.com/lifecycle/> |
|
||||
| Oracle Linux | GitLab CE / GitLab EE 8.14.0 | x86_64 | [Use CentOS Install Documentation](https://about.gitlab.com/install/#centos-7) | Jul 2024 | <https://www.oracle.com/a/ocom/docs/elsp-lifetime-069338.pdf> |
|
||||
| Scientific Linux | GitLab CE / GitLab EE 8.14.0 | x86_64 | [Use CentOS Install Documentation](https://about.gitlab.com/install/#centos-7) | June 2024 | <https://scientificlinux.org/downloads/sl-versions/sl7/> |
|
||||
|
|
|
@ -40,6 +40,10 @@ is invalid, a tip is shown to help you fix the problem:
|
|||
|
||||
## Lint CI configuration
|
||||
|
||||
NOTE:
|
||||
The **Lint** tab is replaced with the **Validate** tab when [pipeline simulations](#simulate-a-cicd-pipeline)
|
||||
are enabled.
|
||||
|
||||
To test the validity of your GitLab CI/CD configuration before committing the changes,
|
||||
you can use the CI lint tool. To access it, go to **CI/CD > Editor** and select the **Lint** tab.
|
||||
|
||||
|
@ -51,6 +55,20 @@ reflected in the CI lint. It displays the same results as the existing [CI Lint
|
|||
|
||||
![Linting errors in a CI configuration](img/pipeline_editor_lint_v13_8.png)
|
||||
|
||||
## Simulate a CI/CD pipeline
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/337282) in GitLab 15.3 [with a flag](../../administration/feature_flags.md) named `simulate_pipeline`. Disabled by default.
|
||||
|
||||
FLAG:
|
||||
On self-managed GitLab, by default this feature is not available. To make it available,
|
||||
ask an administrator to [enable the feature flag](../../administration/feature_flags.md) named `simulate_pipeline`.
|
||||
The feature is not ready for production use. When this feature is enabled, it replaces the **Lint** tab.
|
||||
|
||||
To look for pipeline syntax and logic issues, you can simulate the creation of a
|
||||
GitLab CI/CD pipeline in the **Validate** tab. A pipeline simulation can help find
|
||||
problems such as incorrect `rules` and `needs` job dependencies, and is similar to
|
||||
simulations in the [CI Lint tool](../lint.md#simulate-a-pipeline).
|
||||
|
||||
## View included CI/CD configuration
|
||||
|
||||
> - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/7064) in GitLab 15.0 [with a flag](../../administration/feature_flags.md) named `pipeline_editor_file_tree`. Disabled by default.
|
||||
|
|
|
@ -104,6 +104,9 @@ for the section. For example:
|
|||
> `widget_message` [introduced](<link-to-issue>) in GitLab 14.3.
|
||||
```
|
||||
|
||||
If the API or attribute is deployed behind a feature flag,
|
||||
[include the feature flag information](feature_flags.md) in the version history.
|
||||
|
||||
## Deprecations
|
||||
|
||||
To document the deprecation of an API endpoint, follow the steps to
|
||||
|
|
|
@ -66,10 +66,10 @@ you should keep the documentation with the code in that repository.
|
|||
|
||||
Then you can use one of these approaches:
|
||||
|
||||
- (Recommended) [Add the repository to the list of products](https://gitlab.com/gitlab-org/gitlab-docs/-/blob/main/doc/development.md#add-a-new-product)
|
||||
- Recommended. [Add the repository to the list of products](https://gitlab.com/gitlab-org/gitlab-docs/-/blob/main/doc/development.md#add-a-new-product)
|
||||
published at <https://docs.gitlab.com>. The source of the documentation pages remains
|
||||
in the external repository, but the resulting pages are indexed and searchable on <https://docs.gitlab.com>.
|
||||
- (Recommended) [Add an entry in the global navigation](global_nav.md#add-a-navigation-entry) for
|
||||
- Recommended. [Add an entry in the global navigation](global_nav.md#add-a-navigation-entry) for
|
||||
<https://docs.gitlab.com> that links directly to the documentation in that external repository.
|
||||
The documentation pages are not indexed or searchable on <https://docs.gitlab.com>.
|
||||
View [an example](https://gitlab.com/gitlab-org/gitlab-docs/-/blob/fedb6378a3c92274ba3b6031df0d34455594e4cc/content/_data/navigation.yaml#L2944-L2946).
|
||||
|
|
|
@ -41,7 +41,7 @@ module Gitlab
|
|||
end
|
||||
|
||||
log_report(report_label(report), tms)
|
||||
@report_duration_counter.increment({ report: report_label(report) }, tms.real.to_i)
|
||||
@report_duration_counter.increment({ report: report_label(report) }, tms.real)
|
||||
|
||||
sleep sleep_between_reports_s
|
||||
end
|
||||
|
@ -63,7 +63,7 @@ module Gitlab
|
|||
message: 'finished',
|
||||
pid: $$,
|
||||
worker_id: worker_id,
|
||||
report: report_label,
|
||||
perf_report: report_label,
|
||||
duration_s: tms.real.round(2),
|
||||
cpu_s: tms.utime.round(2),
|
||||
sys_cpu_s: tms.stime.round(2)
|
||||
|
|
|
@ -12466,9 +12466,6 @@ msgstr ""
|
|||
msgid "Deletes the source branch"
|
||||
msgstr ""
|
||||
|
||||
msgid "Deletes the source branch."
|
||||
msgstr ""
|
||||
|
||||
msgid "Deleting"
|
||||
msgstr ""
|
||||
|
||||
|
@ -13732,9 +13729,6 @@ msgstr ""
|
|||
msgid "Documents reindexed: %{processed_documents} (%{percentage}%%)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Does not delete the source branch."
|
||||
msgstr ""
|
||||
|
||||
msgid "Domain"
|
||||
msgstr ""
|
||||
|
||||
|
@ -16021,9 +16015,6 @@ msgstr ""
|
|||
msgid "Fast timeout"
|
||||
msgstr ""
|
||||
|
||||
msgid "Fast-forward merge without a merge commit"
|
||||
msgstr ""
|
||||
|
||||
msgid "Faster releases. Better code. Less pain."
|
||||
msgstr ""
|
||||
|
||||
|
@ -38957,9 +38948,6 @@ msgstr ""
|
|||
msgid "The latest artifacts created by jobs in the most recent successful pipeline will be stored."
|
||||
msgstr ""
|
||||
|
||||
msgid "The latest pipeline for this merge request did not complete successfully."
|
||||
msgstr ""
|
||||
|
||||
msgid "The latest pipeline for this merge request did not succeed. The latest changes are unverified."
|
||||
msgstr ""
|
||||
|
||||
|
@ -39488,9 +39476,6 @@ msgstr ""
|
|||
msgid "There was an error removing the e-mail."
|
||||
msgstr ""
|
||||
|
||||
msgid "There was an error resetting group pipeline minutes."
|
||||
msgstr ""
|
||||
|
||||
msgid "There was an error resetting user pipeline minutes."
|
||||
msgstr ""
|
||||
|
||||
|
@ -46292,12 +46277,6 @@ msgstr ""
|
|||
msgid "mrWidgetCommitsAdded|1 merge commit"
|
||||
msgstr ""
|
||||
|
||||
msgid "mrWidgetCommitsAdded|Adds %{commitCount} and %{mergeCommitCount} to %{targetBranch}%{squashedCommits}."
|
||||
msgstr ""
|
||||
|
||||
msgid "mrWidgetCommitsAdded|Adds %{commitCount} to %{targetBranch}."
|
||||
msgstr ""
|
||||
|
||||
msgid "mrWidgetCommitsAdded|Changes merged into %{targetBranch} with %{mergeCommitSha}%{squashedCommits}."
|
||||
msgstr ""
|
||||
|
||||
|
@ -46414,9 +46393,6 @@ msgstr ""
|
|||
msgid "mrWidget|Delete source branch"
|
||||
msgstr ""
|
||||
|
||||
msgid "mrWidget|Deletes the source branch"
|
||||
msgstr ""
|
||||
|
||||
msgid "mrWidget|Deployment statistics are not available currently"
|
||||
msgstr ""
|
||||
|
||||
|
@ -46426,9 +46402,6 @@ msgstr ""
|
|||
msgid "mrWidget|Dismiss"
|
||||
msgstr ""
|
||||
|
||||
msgid "mrWidget|Does not delete the source branch"
|
||||
msgstr ""
|
||||
|
||||
msgid "mrWidget|Failed to load deployment statistics"
|
||||
msgstr ""
|
||||
|
||||
|
@ -46464,9 +46437,6 @@ msgid_plural "mrWidget|Mentions issues"
|
|||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
msgid "mrWidget|Merge"
|
||||
msgstr ""
|
||||
|
||||
msgid "mrWidget|Merge blocked: all required approvals must be given."
|
||||
msgstr ""
|
||||
|
||||
|
@ -46500,9 +46470,6 @@ msgstr ""
|
|||
msgid "mrWidget|Merged by"
|
||||
msgstr ""
|
||||
|
||||
msgid "mrWidget|Merges changes into"
|
||||
msgstr ""
|
||||
|
||||
msgid "mrWidget|Merging! Changes are being shipped…"
|
||||
msgstr ""
|
||||
|
||||
|
@ -46587,21 +46554,9 @@ msgstr ""
|
|||
msgid "mrWidget|The %{type} branch %{codeStart}%{name}%{codeEnd} does not exist."
|
||||
msgstr ""
|
||||
|
||||
msgid "mrWidget|The changes were merged into"
|
||||
msgstr ""
|
||||
|
||||
msgid "mrWidget|The changes were not merged into"
|
||||
msgstr ""
|
||||
|
||||
msgid "mrWidget|The source branch has been deleted"
|
||||
msgstr ""
|
||||
|
||||
msgid "mrWidget|The source branch is %{link} the target branch"
|
||||
msgstr ""
|
||||
|
||||
msgid "mrWidget|The source branch is being deleted"
|
||||
msgstr ""
|
||||
|
||||
msgid "mrWidget|This merge request failed to be merged automatically"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -71,7 +71,6 @@ module QA
|
|||
|
||||
view 'app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.vue' do
|
||||
element :cherry_pick_button
|
||||
element :merged_status_content
|
||||
element :revert_button
|
||||
end
|
||||
|
||||
|
|
|
@ -21,27 +21,6 @@ RSpec.describe "User merges a merge request", :js do
|
|||
end
|
||||
end
|
||||
|
||||
context "ff-only merge" do
|
||||
let(:project) { create(:project, :public, :repository, merge_requests_ff_only_enabled: true) }
|
||||
|
||||
before do
|
||||
stub_feature_flags(restructured_mr_widget: false)
|
||||
visit(merge_request_path(merge_request))
|
||||
end
|
||||
|
||||
context "when branch is rebased" do
|
||||
let!(:merge_request) { create(:merge_request, :rebased, source_project: project) }
|
||||
|
||||
it_behaves_like "fast forward merge a merge request"
|
||||
end
|
||||
|
||||
context "when branch is merged" do
|
||||
let!(:merge_request) { create(:merge_request, :merged_target, source_project: project) }
|
||||
|
||||
it_behaves_like "fast forward merge a merge request"
|
||||
end
|
||||
end
|
||||
|
||||
context 'sidebar merge requests counter' do
|
||||
let(:project) { create(:project, :public, :repository) }
|
||||
let!(:merge_request) { create(:merge_request, source_project: project) }
|
||||
|
|
|
@ -159,7 +159,7 @@ describe('noteActions', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('when a user has access to edit an issue', () => {
|
||||
describe('when a user can set metadata of an issue', () => {
|
||||
const testButtonClickTriggersAction = () => {
|
||||
axiosMock.onPut(`${TEST_HOST}/api/v4/projects/group/project/issues/1`).reply(() => {
|
||||
expect(actions.updateAssignees).toHaveBeenCalled();
|
||||
|
@ -176,7 +176,7 @@ describe('noteActions', () => {
|
|||
});
|
||||
store.state.noteableData = {
|
||||
current_user: {
|
||||
can_update: true,
|
||||
can_set_issue_metadata: true,
|
||||
},
|
||||
};
|
||||
store.state.userData = userDataMock;
|
||||
|
@ -191,6 +191,31 @@ describe('noteActions', () => {
|
|||
it('should be possible to unassign the comment author', testButtonClickTriggersAction);
|
||||
});
|
||||
|
||||
describe('when a user can update but not set metadata of an issue', () => {
|
||||
beforeEach(() => {
|
||||
wrapper = mountNoteActions(props, {
|
||||
targetType: () => 'issue',
|
||||
});
|
||||
store.state.noteableData = {
|
||||
current_user: {
|
||||
can_update: true,
|
||||
can_set_issue_metadata: false,
|
||||
},
|
||||
};
|
||||
store.state.userData = userDataMock;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
wrapper.destroy();
|
||||
axiosMock.restore();
|
||||
});
|
||||
|
||||
it('should not be possible to assign or unassign the comment author', () => {
|
||||
const assignUserButton = wrapper.find('[data-testid="assign-user"]');
|
||||
expect(assignUserButton.exists()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when a user does not have access to edit an issue', () => {
|
||||
const testButtonDoesNotRender = () => {
|
||||
const assignUserButton = wrapper.find('[data-testid="assign-user"]');
|
||||
|
|
|
@ -10,11 +10,6 @@ function factory(propsData) {
|
|||
targetBranch: 'main',
|
||||
...propsData,
|
||||
},
|
||||
provide: {
|
||||
glFeatures: {
|
||||
restructuredMrWidget: true.valueOf,
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,6 @@ describe('MR widget status icon component', () => {
|
|||
let wrapper;
|
||||
|
||||
const findLoadingIcon = () => wrapper.find(GlLoadingIcon);
|
||||
const findDisabledMergeButton = () => wrapper.find('[data-testid="disabled-merge-button"]');
|
||||
|
||||
const createWrapper = (props, mountFn = shallowMount) => {
|
||||
wrapper = mountFn(mrStatusIcon, {
|
||||
|
@ -41,20 +40,4 @@ describe('MR widget status icon component', () => {
|
|||
expect(wrapper.find('[data-testid="status_failed-icon"]').exists()).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('with disabled button', () => {
|
||||
it('renders a disabled button', () => {
|
||||
createWrapper({ status: 'failed', showDisabledButton: true });
|
||||
|
||||
expect(findDisabledMergeButton().exists()).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('without disabled button', () => {
|
||||
it('does not render a disabled button', () => {
|
||||
createWrapper({ status: 'failed' });
|
||||
|
||||
expect(findDisabledMergeButton().exists()).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -40,34 +40,6 @@ exports[`MRWidgetAutoMergeEnabled when graphql is disabled template should have
|
|||
|
||||
</gl-button-stub>
|
||||
</h4>
|
||||
|
||||
<section
|
||||
class="mr-info-list"
|
||||
>
|
||||
<p
|
||||
class="gl-display-flex"
|
||||
>
|
||||
<span
|
||||
class="gl-mr-3"
|
||||
>
|
||||
Does not delete the source branch
|
||||
</span>
|
||||
|
||||
<gl-button-stub
|
||||
buttontextclasses=""
|
||||
category="primary"
|
||||
class="js-remove-source-branch"
|
||||
data-testid="removeSourceBranchButton"
|
||||
icon=""
|
||||
size="small"
|
||||
variant="default"
|
||||
>
|
||||
|
||||
Delete source branch
|
||||
|
||||
</gl-button-stub>
|
||||
</p>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
@ -112,34 +84,6 @@ exports[`MRWidgetAutoMergeEnabled when graphql is enabled template should have c
|
|||
|
||||
</gl-button-stub>
|
||||
</h4>
|
||||
|
||||
<section
|
||||
class="mr-info-list"
|
||||
>
|
||||
<p
|
||||
class="gl-display-flex"
|
||||
>
|
||||
<span
|
||||
class="gl-mr-3"
|
||||
>
|
||||
Does not delete the source branch
|
||||
</span>
|
||||
|
||||
<gl-button-stub
|
||||
buttontextclasses=""
|
||||
category="primary"
|
||||
class="js-remove-source-branch"
|
||||
data-testid="removeSourceBranchButton"
|
||||
icon=""
|
||||
size="small"
|
||||
variant="default"
|
||||
>
|
||||
|
||||
Delete source branch
|
||||
|
||||
</gl-button-stub>
|
||||
</p>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
|
|
@ -5,7 +5,7 @@ exports[`PipelineFailed should render error message with a disabled merge button
|
|||
class="mr-widget-body media"
|
||||
>
|
||||
<status-icon-stub
|
||||
showdisabledbutton="true"
|
||||
show-disabled-button="true"
|
||||
status="warning"
|
||||
/>
|
||||
|
||||
|
@ -13,7 +13,7 @@ exports[`PipelineFailed should render error message with a disabled merge button
|
|||
class="media-body space-children"
|
||||
>
|
||||
<span
|
||||
class="bold"
|
||||
class="gl-ml-0! gl-text-body! bold"
|
||||
>
|
||||
<gl-sprintf-stub
|
||||
message="Merge blocked: pipeline must succeed. Push a commit that fixes the failure, or %{linkStart}learn about other solutions.%{linkEnd}"
|
||||
|
|
|
@ -18,11 +18,6 @@ describe('MRWidgetArchived', () => {
|
|||
expect(vm.$el.querySelector('.ci-status-icon')).not.toBeNull();
|
||||
});
|
||||
|
||||
it('renders a disabled button', () => {
|
||||
expect(vm.$el.querySelector('button').getAttribute('disabled')).toEqual('disabled');
|
||||
expect(vm.$el.querySelector('button').textContent.trim()).toEqual('Merge');
|
||||
});
|
||||
|
||||
it('renders information', () => {
|
||||
expect(vm.$el.querySelector('.bold').textContent.trim()).toEqual(
|
||||
'Merge unavailable: merge requests are read-only on archived projects.',
|
||||
|
|
|
@ -102,74 +102,6 @@ describe('MRWidgetAutoMergeEnabled', () => {
|
|||
});
|
||||
|
||||
describe('computed', () => {
|
||||
describe('canRemoveSourceBranch', () => {
|
||||
it('should return true when user is able to remove source branch', () => {
|
||||
factory({
|
||||
...defaultMrProps(),
|
||||
});
|
||||
|
||||
expect(wrapper.findByTestId('removeSourceBranchButton').exists()).toBe(true);
|
||||
});
|
||||
|
||||
it.each`
|
||||
mergeUserId | currentUserId
|
||||
${2} | ${1}
|
||||
${1} | ${2}
|
||||
`(
|
||||
'should return false when user id is not the same with who set the MWPS',
|
||||
({ mergeUserId, currentUserId }) => {
|
||||
factory({
|
||||
...defaultMrProps(),
|
||||
mergeUserId,
|
||||
currentUserId,
|
||||
});
|
||||
|
||||
expect(wrapper.findByTestId('removeSourceBranchButton').exists()).toBe(false);
|
||||
},
|
||||
);
|
||||
|
||||
it('should not find "Delete" button when shouldRemoveSourceBranch set to true', () => {
|
||||
factory({
|
||||
...defaultMrProps(),
|
||||
shouldRemoveSourceBranch: true,
|
||||
});
|
||||
|
||||
expect(wrapper.findByTestId('removeSourceBranchButton').exists()).toBe(false);
|
||||
});
|
||||
|
||||
it('should find "Delete" button when shouldRemoveSourceBranch overrides state.forceRemoveSourceBranch', () => {
|
||||
factory(
|
||||
{
|
||||
...defaultMrProps(),
|
||||
shouldRemoveSourceBranch: false,
|
||||
},
|
||||
{
|
||||
forceRemoveSourceBranch: true,
|
||||
},
|
||||
);
|
||||
|
||||
expect(wrapper.findByTestId('removeSourceBranchButton').exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('should find "Delete" button when shouldRemoveSourceBranch set to false', () => {
|
||||
factory({
|
||||
...defaultMrProps(),
|
||||
shouldRemoveSourceBranch: false,
|
||||
});
|
||||
|
||||
expect(wrapper.findByTestId('removeSourceBranchButton').exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false if user is not able to remove the source branch', () => {
|
||||
factory({
|
||||
...defaultMrProps(),
|
||||
canRemoveSourceBranch: false,
|
||||
});
|
||||
|
||||
expect(wrapper.findByTestId('removeSourceBranchButton').exists()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('cancelButtonText', () => {
|
||||
it('should return "Cancel" if MWPS is selected', () => {
|
||||
factory({
|
||||
|
@ -265,42 +197,6 @@ describe('MRWidgetAutoMergeEnabled', () => {
|
|||
expect(wrapper.find('.js-cancel-auto-merge').props('loading')).toBe(true);
|
||||
});
|
||||
|
||||
it('should show source branch will be deleted text when it source branch set to remove', () => {
|
||||
factory({
|
||||
...defaultMrProps(),
|
||||
shouldRemoveSourceBranch: true,
|
||||
});
|
||||
|
||||
const normalizedText = wrapper.text().replace(/\s+/g, ' ');
|
||||
|
||||
expect(normalizedText).toContain('Deletes the source branch');
|
||||
expect(normalizedText).not.toContain('Does not delete the source branch');
|
||||
});
|
||||
|
||||
it('should not show delete source branch button when user not able to delete source branch', () => {
|
||||
factory({
|
||||
...defaultMrProps(),
|
||||
currentUserId: 4,
|
||||
});
|
||||
|
||||
expect(wrapper.find('.js-remove-source-branch').exists()).toBe(false);
|
||||
});
|
||||
|
||||
it('should disable delete source branch button when the action is in progress', async () => {
|
||||
factory({
|
||||
...defaultMrProps(),
|
||||
});
|
||||
// setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
wrapper.setData({
|
||||
isRemovingSourceBranch: true,
|
||||
});
|
||||
|
||||
await nextTick();
|
||||
|
||||
expect(wrapper.find('.js-remove-source-branch').props('loading')).toBe(true);
|
||||
});
|
||||
|
||||
it('should render the status text as "...to merged automatically" if MWPS is selected', () => {
|
||||
factory({
|
||||
...defaultMrProps(),
|
||||
|
|
|
@ -15,10 +15,6 @@ describe('MRWidgetChecking', () => {
|
|||
vm.$destroy();
|
||||
});
|
||||
|
||||
it('renders disabled button', () => {
|
||||
expect(vm.$el.querySelector('button').getAttribute('disabled')).toEqual('disabled');
|
||||
});
|
||||
|
||||
it('renders loading icon', () => {
|
||||
expect(vm.$el.querySelector('.mr-widget-icon span').classList).toContain('gl-spinner');
|
||||
});
|
||||
|
|
|
@ -36,28 +36,4 @@ describe('MRWidgetClosed', () => {
|
|||
it('renders warning icon', () => {
|
||||
expect(vm.$el.querySelector('.js-ci-status-icon-warning')).not.toBeNull();
|
||||
});
|
||||
|
||||
it('renders closed by information with author and time', () => {
|
||||
expect(
|
||||
vm.$el.querySelector('.js-mr-widget-author').textContent.trim().replace(/\s\s+/g, ' '),
|
||||
).toContain('Closed by Administrator less than a minute ago');
|
||||
});
|
||||
|
||||
it('links to the user that closed the MR', () => {
|
||||
expect(vm.$el.querySelector('.author-link').getAttribute('href')).toEqual(
|
||||
'http://localhost:3000/root',
|
||||
);
|
||||
});
|
||||
|
||||
it('renders information about the changes not being merged', () => {
|
||||
expect(
|
||||
vm.$el.querySelector('.mr-info-list').textContent.trim().replace(/\s\s+/g, ' '),
|
||||
).toContain('The changes were not merged into so_long_jquery');
|
||||
});
|
||||
|
||||
it('renders link for target branch', () => {
|
||||
expect(vm.$el.querySelector('.label-branch').getAttribute('href')).toEqual(
|
||||
'/twitter/flight/commits/so_long_jquery',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import { shallowMount } from '@vue/test-utils';
|
||||
import { nextTick } from 'vue';
|
||||
import StatusIcon from '~/vue_merge_request_widget/components/mr_widget_status_icon.vue';
|
||||
import MrWidgetFailedToMerge from '~/vue_merge_request_widget/components/states/mr_widget_failed_to_merge.vue';
|
||||
import eventHub from '~/vue_merge_request_widget/event_hub';
|
||||
|
||||
|
@ -116,7 +115,6 @@ describe('MRWidgetFailedToMerge', () => {
|
|||
|
||||
it('renders warning icon and disabled merge button', () => {
|
||||
expect(wrapper.find('.js-ci-status-icon-warning')).not.toBeNull();
|
||||
expect(wrapper.find(StatusIcon).props('showDisabledButton')).toBe(true);
|
||||
});
|
||||
|
||||
it('renders given error', () => {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { getByRole } from '@testing-library/dom';
|
||||
import Vue, { nextTick } from 'vue';
|
||||
import Vue from 'vue';
|
||||
import mountComponent from 'helpers/vue_mount_component_helper';
|
||||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
import { OPEN_REVERT_MODAL, OPEN_CHERRY_PICK_MODAL } from '~/projects/commit/constants';
|
||||
|
@ -10,14 +10,6 @@ import eventHub from '~/vue_merge_request_widget/event_hub';
|
|||
describe('MRWidgetMerged', () => {
|
||||
let vm;
|
||||
const targetBranch = 'foo';
|
||||
const selectors = {
|
||||
get copyMergeShaButton() {
|
||||
return vm.$el.querySelector('button.js-mr-merged-copy-sha');
|
||||
},
|
||||
get mergeCommitShaLink() {
|
||||
return vm.$el.querySelector('a.js-mr-merged-commit-sha');
|
||||
},
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
jest.spyOn(document, 'dispatchEvent');
|
||||
|
@ -177,58 +169,11 @@ describe('MRWidgetMerged', () => {
|
|||
expect(vm.$el.textContent).toContain('Administrator');
|
||||
});
|
||||
|
||||
it('renders branch information', () => {
|
||||
expect(vm.$el.textContent).toContain('The changes were merged into');
|
||||
expect(vm.$el.textContent).toContain(targetBranch);
|
||||
});
|
||||
|
||||
it('renders information about branch being deleted', () => {
|
||||
expect(vm.$el.textContent).toContain('The source branch has been deleted');
|
||||
});
|
||||
|
||||
it('shows revert and cherry-pick buttons', () => {
|
||||
expect(vm.$el.textContent).toContain('Revert');
|
||||
expect(vm.$el.textContent).toContain('Cherry-pick');
|
||||
});
|
||||
|
||||
it('shows button to copy commit SHA to clipboard', () => {
|
||||
expect(selectors.copyMergeShaButton).not.toBe(null);
|
||||
expect(selectors.copyMergeShaButton.dataset.clipboardText).toBe(vm.mr.mergeCommitSha);
|
||||
});
|
||||
|
||||
it('hides button to copy commit SHA if SHA does not exist', async () => {
|
||||
vm.mr.mergeCommitSha = null;
|
||||
|
||||
await nextTick();
|
||||
|
||||
expect(selectors.copyMergeShaButton).toBe(null);
|
||||
expect(vm.$el.querySelector('.mr-info-list').innerText).not.toContain('with');
|
||||
});
|
||||
|
||||
it('shows merge commit SHA link', () => {
|
||||
expect(selectors.mergeCommitShaLink).not.toBe(null);
|
||||
expect(selectors.mergeCommitShaLink.text).toContain(vm.mr.shortMergeCommitSha);
|
||||
expect(selectors.mergeCommitShaLink.href).toBe(vm.mr.mergeCommitPath);
|
||||
});
|
||||
|
||||
it('should not show source branch deleted text', async () => {
|
||||
vm.mr.sourceBranchRemoved = false;
|
||||
|
||||
await nextTick();
|
||||
|
||||
expect(vm.$el.innerText).not.toContain('The source branch has been deleted');
|
||||
});
|
||||
|
||||
it('should show source branch deleting text', async () => {
|
||||
vm.mr.isRemovingSourceBranch = true;
|
||||
vm.mr.sourceBranchRemoved = false;
|
||||
|
||||
await nextTick();
|
||||
|
||||
expect(vm.$el.innerText).toContain('The source branch is being deleted');
|
||||
expect(vm.$el.innerText).not.toContain('The source branch has been deleted');
|
||||
});
|
||||
|
||||
it('should use mergedEvent mergedAt as tooltip title', () => {
|
||||
expect(vm.$el.querySelector('time').getAttribute('title')).toBe('Jan 24, 2018 1:02pm UTC');
|
||||
});
|
||||
|
|
|
@ -43,19 +43,6 @@ describe('MRWidgetMerging', () => {
|
|||
).toContain('Merging!');
|
||||
});
|
||||
|
||||
it('renders branch information', () => {
|
||||
expect(
|
||||
wrapper
|
||||
.find('.mr-info-list')
|
||||
.text()
|
||||
.trim()
|
||||
.replace(/\s\s+/g, ' ')
|
||||
.replace(/[\r\n]+/g, ' '),
|
||||
).toEqual('Merges changes into branch');
|
||||
|
||||
expect(wrapper.find('a').attributes('href')).toBe('/branch-path');
|
||||
});
|
||||
|
||||
describe('initiateMergePolling', () => {
|
||||
it('should call simplePoll', () => {
|
||||
wrapper.vm.initiateMergePolling();
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import { shallowMount } from '@vue/test-utils';
|
||||
import statusIcon from '~/vue_merge_request_widget/components/mr_widget_status_icon.vue';
|
||||
import PipelineFailed from '~/vue_merge_request_widget/components/states/pipeline_failed.vue';
|
||||
|
||||
describe('PipelineFailed', () => {
|
||||
|
@ -9,8 +8,6 @@ describe('PipelineFailed', () => {
|
|||
wrapper = shallowMount(PipelineFailed);
|
||||
};
|
||||
|
||||
const findStatusIcon = () => wrapper.find(statusIcon);
|
||||
|
||||
beforeEach(() => {
|
||||
createComponent();
|
||||
});
|
||||
|
@ -23,8 +20,4 @@ describe('PipelineFailed', () => {
|
|||
it('should render error message with a disabled merge button', () => {
|
||||
expect(wrapper.element).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('merge button should be disabled', () => {
|
||||
expect(findStatusIcon().props('showDisabledButton')).toBe(true);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -10,7 +10,6 @@ import readyToMergeQuery from 'ee_else_ce/vue_merge_request_widget/queries/state
|
|||
import simplePoll from '~/lib/utils/simple_poll';
|
||||
import CommitEdit from '~/vue_merge_request_widget/components/states/commit_edit.vue';
|
||||
import CommitMessageDropdown from '~/vue_merge_request_widget/components/states/commit_message_dropdown.vue';
|
||||
import CommitsHeader from '~/vue_merge_request_widget/components/states/commits_header.vue';
|
||||
import ReadyToMerge from '~/vue_merge_request_widget/components/states/ready_to_merge.vue';
|
||||
import SquashBeforeMerge from '~/vue_merge_request_widget/components/states/squash_before_merge.vue';
|
||||
import MergeFailedPipelineConfirmationDialog from '~/vue_merge_request_widget/components/states/merge_failed_pipeline_confirmation_dialog.vue';
|
||||
|
@ -60,6 +59,7 @@ const createTestMr = (customConfig) => {
|
|||
transitionStateMachine: (transition) => eventHub.$emit('StateMachineValueChanged', transition),
|
||||
translateStateToMachine: () => this.transitionStateMachine(),
|
||||
state: 'open',
|
||||
canMerge: true,
|
||||
};
|
||||
|
||||
Object.assign(mr, customConfig.mr);
|
||||
|
@ -90,7 +90,7 @@ const createReadyToMergeResponse = (customMr) => {
|
|||
const createComponent = (
|
||||
customConfig = {},
|
||||
mergeRequestWidgetGraphql = false,
|
||||
restructuredMrWidget = false,
|
||||
restructuredMrWidget = true,
|
||||
) => {
|
||||
wrapper = shallowMount(ReadyToMerge, {
|
||||
propsData: {
|
||||
|
@ -111,7 +111,6 @@ const createComponent = (
|
|||
};
|
||||
|
||||
const findCheckboxElement = () => wrapper.find(SquashBeforeMerge);
|
||||
const findCommitsHeaderElement = () => wrapper.find(CommitsHeader);
|
||||
const findCommitEditElements = () => wrapper.findAll(CommitEdit);
|
||||
const findCommitDropdownElement = () => wrapper.find(CommitMessageDropdown);
|
||||
const findFirstCommitEditLabel = () => findCommitEditElements().at(0).props('label');
|
||||
|
@ -575,71 +574,9 @@ describe('ReadyToMerge', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('commits count collapsible header', () => {
|
||||
it('should be rendered when fast-forward is disabled', () => {
|
||||
createComponent();
|
||||
|
||||
expect(findCommitsHeaderElement().exists()).toBeTruthy();
|
||||
});
|
||||
|
||||
describe('when fast-forward is enabled', () => {
|
||||
it('should be rendered if squash and squash before are enabled and there is more than 1 commit', () => {
|
||||
createComponent({
|
||||
mr: {
|
||||
ffOnlyEnabled: true,
|
||||
enableSquashBeforeMerge: true,
|
||||
squashIsSelected: true,
|
||||
commitsCount: 2,
|
||||
},
|
||||
});
|
||||
|
||||
expect(findCommitsHeaderElement().exists()).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should not be rendered if squash before merge is disabled', () => {
|
||||
createComponent({
|
||||
mr: {
|
||||
ffOnlyEnabled: true,
|
||||
enableSquashBeforeMerge: false,
|
||||
squash: true,
|
||||
commitsCount: 2,
|
||||
},
|
||||
});
|
||||
|
||||
expect(findCommitsHeaderElement().exists()).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should not be rendered if squash is disabled', () => {
|
||||
createComponent({
|
||||
mr: {
|
||||
ffOnlyEnabled: true,
|
||||
squash: false,
|
||||
enableSquashBeforeMerge: true,
|
||||
commitsCount: 2,
|
||||
},
|
||||
});
|
||||
|
||||
expect(findCommitsHeaderElement().exists()).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should not be rendered if commits count is 1', () => {
|
||||
createComponent({
|
||||
mr: {
|
||||
ffOnlyEnabled: true,
|
||||
squash: true,
|
||||
enableSquashBeforeMerge: true,
|
||||
commitsCount: 1,
|
||||
},
|
||||
});
|
||||
|
||||
expect(findCommitsHeaderElement().exists()).toBeFalsy();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('commits edit components', () => {
|
||||
describe('when fast-forward merge is enabled', () => {
|
||||
it('should not be rendered if squash is disabled', () => {
|
||||
it('should not be rendered if squash is disabled', async () => {
|
||||
createComponent({
|
||||
mr: {
|
||||
ffOnlyEnabled: true,
|
||||
|
@ -678,7 +615,7 @@ describe('ReadyToMerge', () => {
|
|||
expect(findCommitEditElements().length).toBe(0);
|
||||
});
|
||||
|
||||
it('should have one edit component if squash is enabled and there is more than 1 commit', () => {
|
||||
it('should have one edit component if squash is enabled and there is more than 1 commit', async () => {
|
||||
createComponent({
|
||||
mr: {
|
||||
ffOnlyEnabled: true,
|
||||
|
@ -688,18 +625,14 @@ describe('ReadyToMerge', () => {
|
|||
},
|
||||
});
|
||||
|
||||
await wrapper.find('[data-testid="widget_edit_commit_message"]').vm.$emit('input', true);
|
||||
|
||||
expect(findCommitEditElements().length).toBe(1);
|
||||
expect(findFirstCommitEditLabel()).toBe('Squash commit message');
|
||||
});
|
||||
});
|
||||
|
||||
it('should have one edit component when squash is disabled', () => {
|
||||
createComponent();
|
||||
|
||||
expect(findCommitEditElements().length).toBe(1);
|
||||
});
|
||||
|
||||
it('should have two edit components when squash is enabled and there is more than 1 commit', () => {
|
||||
it('should have two edit components when squash is enabled and there is more than 1 commit', async () => {
|
||||
createComponent({
|
||||
mr: {
|
||||
commitsCount: 2,
|
||||
|
@ -708,6 +641,8 @@ describe('ReadyToMerge', () => {
|
|||
},
|
||||
});
|
||||
|
||||
await wrapper.find('[data-testid="widget_edit_commit_message"]').vm.$emit('input', true);
|
||||
|
||||
expect(findCommitEditElements().length).toBe(2);
|
||||
});
|
||||
|
||||
|
@ -737,11 +672,12 @@ describe('ReadyToMerge', () => {
|
|||
},
|
||||
});
|
||||
await nextTick();
|
||||
await wrapper.find('[data-testid="widget_edit_commit_message"]').vm.$emit('input', true);
|
||||
|
||||
expect(findCommitEditElements().length).toBe(2);
|
||||
});
|
||||
|
||||
it('should have one edit components when squash is enabled and there is 1 commit only', () => {
|
||||
it('should have one edit components when squash is enabled and there is 1 commit only', async () => {
|
||||
createComponent({
|
||||
mr: {
|
||||
commitsCount: 1,
|
||||
|
@ -750,16 +686,12 @@ describe('ReadyToMerge', () => {
|
|||
},
|
||||
});
|
||||
|
||||
await wrapper.find('[data-testid="widget_edit_commit_message"]').vm.$emit('input', true);
|
||||
|
||||
expect(findCommitEditElements().length).toBe(1);
|
||||
});
|
||||
|
||||
it('should have correct edit merge commit label', () => {
|
||||
createComponent();
|
||||
|
||||
expect(findFirstCommitEditLabel()).toBe('Merge commit message');
|
||||
});
|
||||
|
||||
it('should have correct edit squash commit label', () => {
|
||||
it('should have correct edit squash commit label', async () => {
|
||||
createComponent({
|
||||
mr: {
|
||||
commitsCount: 2,
|
||||
|
@ -768,6 +700,8 @@ describe('ReadyToMerge', () => {
|
|||
},
|
||||
});
|
||||
|
||||
await wrapper.find('[data-testid="widget_edit_commit_message"]').vm.$emit('input', true);
|
||||
|
||||
expect(findFirstCommitEditLabel()).toBe('Squash commit message');
|
||||
});
|
||||
});
|
||||
|
@ -779,48 +713,26 @@ describe('ReadyToMerge', () => {
|
|||
expect(findCommitDropdownElement().exists()).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should be rendered if squash is enabled and there is more than 1 commit', () => {
|
||||
it('should be rendered if squash is enabled and there is more than 1 commit', async () => {
|
||||
createComponent({
|
||||
mr: { enableSquashBeforeMerge: true, squashIsSelected: true, commitsCount: 2 },
|
||||
});
|
||||
|
||||
await wrapper.find('[data-testid="widget_edit_commit_message"]').vm.$emit('input', true);
|
||||
|
||||
expect(findCommitDropdownElement().exists()).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
it('renders a tip including a link to docs on templates', () => {
|
||||
it('renders a tip including a link to docs on templates', async () => {
|
||||
createComponent();
|
||||
|
||||
await wrapper.find('[data-testid="widget_edit_commit_message"]').vm.$emit('input', true);
|
||||
|
||||
expect(findTipLink().exists()).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Merge request project settings', () => {
|
||||
describe('when the merge commit merge method is enabled', () => {
|
||||
beforeEach(() => {
|
||||
createComponent({
|
||||
mr: { ffOnlyEnabled: false },
|
||||
});
|
||||
});
|
||||
|
||||
it('should not show fast forward message', () => {
|
||||
expect(wrapper.find('.mr-fast-forward-message').exists()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when the fast-forward merge method is enabled', () => {
|
||||
beforeEach(() => {
|
||||
createComponent({
|
||||
mr: { ffOnlyEnabled: true },
|
||||
});
|
||||
});
|
||||
|
||||
it('should show fast forward message', () => {
|
||||
expect(wrapper.find('.mr-fast-forward-message').exists()).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Merge button when pipeline has failed', () => {
|
||||
beforeEach(() => {
|
||||
createComponent({
|
||||
|
@ -872,6 +784,7 @@ describe('ReadyToMerge', () => {
|
|||
createDefaultGqlComponent();
|
||||
|
||||
await waitForPromises();
|
||||
await wrapper.find('[data-testid="widget_edit_commit_message"]').vm.$emit('input', true);
|
||||
|
||||
expect(finderFn()).toBe(initialValue);
|
||||
});
|
||||
|
@ -879,6 +792,7 @@ describe('ReadyToMerge', () => {
|
|||
it('should have updated value after graphql refetch', async () => {
|
||||
createDefaultGqlComponent();
|
||||
await waitForPromises();
|
||||
await wrapper.find('[data-testid="widget_edit_commit_message"]').vm.$emit('input', true);
|
||||
|
||||
triggerApprovalUpdated();
|
||||
await waitForPromises();
|
||||
|
@ -889,6 +803,7 @@ describe('ReadyToMerge', () => {
|
|||
it('should not update if user has touched', async () => {
|
||||
createDefaultGqlComponent();
|
||||
await waitForPromises();
|
||||
await wrapper.find('[data-testid="widget_edit_commit_message"]').vm.$emit('input', true);
|
||||
|
||||
const input = wrapper.find(inputId);
|
||||
input.element.value = USER_COMMIT_MESSAGE;
|
||||
|
|
|
@ -85,8 +85,6 @@ describe('Wip', () => {
|
|||
expect(el.innerText).toContain(
|
||||
"Merge blocked: merge request must be marked as ready. It's still marked as draft.",
|
||||
);
|
||||
expect(el.querySelector('button').getAttribute('disabled')).toBeTruthy();
|
||||
expect(el.querySelector('button').innerText).toContain('Merge');
|
||||
expect(el.querySelector('.js-remove-draft').innerText.replace(/\s\s+/g, ' ')).toContain(
|
||||
'Mark as ready',
|
||||
);
|
||||
|
|
|
@ -20,7 +20,6 @@ import {
|
|||
import { SUCCESS } from '~/vue_merge_request_widget/components/deployment/constants';
|
||||
import eventHub from '~/vue_merge_request_widget/event_hub';
|
||||
import MrWidgetOptions from '~/vue_merge_request_widget/mr_widget_options.vue';
|
||||
import { stateKey } from '~/vue_merge_request_widget/stores/state_maps';
|
||||
import StatusIcon from '~/vue_merge_request_widget/components/extensions/status_icon.vue';
|
||||
import securityReportMergeRequestDownloadPathsQuery from '~/vue_shared/security_reports/graphql/queries/security_report_merge_request_download_paths.query.graphql';
|
||||
import { faviconDataUrl, overlayDataUrl } from '../lib/utils/mock_data';
|
||||
|
@ -135,18 +134,6 @@ describe('MrWidgetOptions', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('shouldRenderRelatedLinks', () => {
|
||||
it('should return false for the initial data', () => {
|
||||
expect(wrapper.vm.shouldRenderRelatedLinks).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should return true if there is relatedLinks in MR', () => {
|
||||
Vue.set(wrapper.vm.mr, 'relatedLinks', {});
|
||||
|
||||
expect(wrapper.vm.shouldRenderRelatedLinks).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('shouldRenderSourceBranchRemovalStatus', () => {
|
||||
beforeEach(() => {
|
||||
wrapper.vm.mr.state = 'readyToMerge';
|
||||
|
@ -519,61 +506,6 @@ describe('MrWidgetOptions', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('rendering relatedLinks', () => {
|
||||
beforeEach(() => {
|
||||
return createComponent({
|
||||
...mockData,
|
||||
issues_links: {
|
||||
closing: `
|
||||
<a class="close-related-link" href="#">
|
||||
Close
|
||||
</a>
|
||||
`,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
wrapper.destroy();
|
||||
});
|
||||
|
||||
it('renders if there are relatedLinks', () => {
|
||||
expect(wrapper.find('.close-related-link').exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('does not render if state is nothingToMerge', async () => {
|
||||
wrapper.vm.mr.state = stateKey.nothingToMerge;
|
||||
await nextTick();
|
||||
expect(wrapper.find('.close-related-link').exists()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('rendering source branch removal status', () => {
|
||||
it('renders when user cannot remove branch and branch should be removed', async () => {
|
||||
wrapper.vm.mr.canRemoveSourceBranch = false;
|
||||
wrapper.vm.mr.shouldRemoveSourceBranch = true;
|
||||
wrapper.vm.mr.state = 'readyToMerge';
|
||||
|
||||
await nextTick();
|
||||
const tooltip = wrapper.find('[data-testid="question-o-icon"]');
|
||||
|
||||
expect(wrapper.text()).toContain('Deletes the source branch');
|
||||
expect(tooltip.attributes('title')).toBe(
|
||||
'A user with write access to the source branch selected this option',
|
||||
);
|
||||
});
|
||||
|
||||
it('does not render in merged state', async () => {
|
||||
wrapper.vm.mr.canRemoveSourceBranch = false;
|
||||
wrapper.vm.mr.shouldRemoveSourceBranch = true;
|
||||
wrapper.vm.mr.state = 'merged';
|
||||
|
||||
await nextTick();
|
||||
expect(wrapper.text()).toContain('The source branch has been deleted');
|
||||
expect(wrapper.text()).not.toContain('Deletes the source branch');
|
||||
});
|
||||
});
|
||||
|
||||
describe('rendering deployments', () => {
|
||||
const changes = [
|
||||
{
|
||||
|
@ -1062,7 +994,7 @@ describe('MrWidgetOptions', () => {
|
|||
|
||||
await createComponent();
|
||||
|
||||
expect(pollRequest).toHaveBeenCalledTimes(6);
|
||||
expect(pollRequest).toHaveBeenCalledTimes(4);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -1100,14 +1032,14 @@ describe('MrWidgetOptions', () => {
|
|||
registerExtension(pollingErrorExtension);
|
||||
await createComponent();
|
||||
|
||||
expect(pollRequest).toHaveBeenCalledTimes(6);
|
||||
expect(pollRequest).toHaveBeenCalledTimes(4);
|
||||
});
|
||||
|
||||
it('captures sentry error and displays error when poll has failed', async () => {
|
||||
registerExtension(pollingErrorExtension);
|
||||
await createComponent();
|
||||
|
||||
expect(Sentry.captureException).toHaveBeenCalledTimes(5);
|
||||
expect(Sentry.captureException).toHaveBeenCalled();
|
||||
expect(Sentry.captureException).toHaveBeenCalledWith(new Error('Fetch error'));
|
||||
expect(wrapper.findComponent(StatusIcon).props('iconName')).toBe('failed');
|
||||
});
|
||||
|
@ -1126,7 +1058,7 @@ describe('MrWidgetOptions', () => {
|
|||
expect(
|
||||
wrapper.find('[data-testid="widget-extension"] [data-testid="toggle-button"]').exists(),
|
||||
).toBe(false);
|
||||
expect(Sentry.captureException).toHaveBeenCalledTimes(5);
|
||||
expect(Sentry.captureException).toHaveBeenCalled();
|
||||
expect(Sentry.captureException).toHaveBeenCalledWith(new Error('Fetch error'));
|
||||
expect(wrapper.findComponent(StatusIcon).props('iconName')).toBe('failed');
|
||||
});
|
||||
|
|
|
@ -25,10 +25,6 @@ describe('getStateKey', () => {
|
|||
|
||||
expect(bound()).toEqual('readyToMerge');
|
||||
|
||||
context.canMerge = false;
|
||||
|
||||
expect(bound()).toEqual('notAllowedToMerge');
|
||||
|
||||
context.autoMergeEnabled = true;
|
||||
context.hasMergeableDiscussionsState = true;
|
||||
|
||||
|
@ -105,22 +101,4 @@ describe('getStateKey', () => {
|
|||
|
||||
expect(bound()).toEqual('rebase');
|
||||
});
|
||||
|
||||
it.each`
|
||||
canMerge | isSHAMismatch | stateKey
|
||||
${true} | ${true} | ${'shaMismatch'}
|
||||
${false} | ${true} | ${'notAllowedToMerge'}
|
||||
${false} | ${false} | ${'notAllowedToMerge'}
|
||||
`(
|
||||
'returns $stateKey when canMerge is $canMerge and isSHAMismatch is $isSHAMismatch',
|
||||
({ canMerge, isSHAMismatch, stateKey }) => {
|
||||
const bound = getStateKey.bind({
|
||||
canMerge,
|
||||
isSHAMismatch,
|
||||
commitsCount: 2,
|
||||
});
|
||||
|
||||
expect(bound()).toEqual(stateKey);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
|
|
@ -153,11 +153,6 @@ RSpec.describe Gitlab::GitAccess, :aggregate_failures do
|
|||
end
|
||||
|
||||
it 'logs' do
|
||||
allow(Gitlab::AppJsonLogger).to receive(:info).with(
|
||||
hash_including(
|
||||
"class" => "AuthorizedProjectUpdate::ProjectRecalculatePerUserWorker"
|
||||
)
|
||||
)
|
||||
expect(Gitlab::AppJsonLogger).to receive(:info).with(
|
||||
message: 'Actor was :ci',
|
||||
project_id: project.id
|
||||
|
@ -750,11 +745,6 @@ RSpec.describe Gitlab::GitAccess, :aggregate_failures do
|
|||
it { expect { pull_access_check }.not_to raise_error }
|
||||
|
||||
it 'logs' do
|
||||
expect(Gitlab::AppJsonLogger).to receive(:info).with(
|
||||
hash_including(
|
||||
"class" => "AuthorizedProjectUpdate::ProjectRecalculatePerUserWorker"
|
||||
)
|
||||
).once
|
||||
expect(Gitlab::AppJsonLogger).to receive(:info).with(
|
||||
message: 'Actor was :ci',
|
||||
project_id: project.id
|
||||
|
|
|
@ -36,14 +36,14 @@ RSpec.describe Gitlab::Memory::ReportsDaemon do
|
|||
message: 'finished',
|
||||
pid: Process.pid,
|
||||
worker_id: 'worker_1',
|
||||
report: 'jemalloc_stats'
|
||||
perf_report: 'jemalloc_stats'
|
||||
)).twice
|
||||
|
||||
daemon.send(:run_thread)
|
||||
end
|
||||
|
||||
it 'sets real time duration gauge' do
|
||||
expect(report_duration_counter).to receive(:increment).with({ report: 'jemalloc_stats' }, an_instance_of(Integer))
|
||||
expect(report_duration_counter).to receive(:increment).with({ report: 'jemalloc_stats' }, an_instance_of(Float))
|
||||
|
||||
daemon.send(:run_thread)
|
||||
end
|
||||
|
|
|
@ -39,6 +39,13 @@ RSpec.describe IssueEntity do
|
|||
expect(subject).to include(:time_estimate, :total_time_spent, :human_time_estimate, :human_total_time_spent)
|
||||
end
|
||||
|
||||
describe 'current_user' do
|
||||
it 'has the exprected permissions' do
|
||||
expect(subject[:current_user]).to include(:can_create_note, :can_update, :can_set_issue_metadata,
|
||||
:can_award_emoji)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when issue got moved' do
|
||||
let(:public_project) { create(:project, :public) }
|
||||
let(:member) { create(:user) }
|
||||
|
|
|
@ -129,6 +129,12 @@ module Ci
|
|||
let!(:build2_project2) { create(:ci_build, :pending, :queued, pipeline: pipeline2) }
|
||||
let!(:build1_project3) { create(:ci_build, :pending, :queued, pipeline: pipeline3) }
|
||||
|
||||
it 'picks builds one-by-one' do
|
||||
expect(Ci::Build).to receive(:find).with(pending_job.id).and_call_original
|
||||
|
||||
expect(execute(shared_runner)).to eq(build1_project1)
|
||||
end
|
||||
|
||||
context 'when using fair scheduling' do
|
||||
context 'when all builds are pending' do
|
||||
it 'prefers projects without builds first' do
|
||||
|
@ -739,16 +745,6 @@ module Ci
|
|||
end
|
||||
end
|
||||
|
||||
context 'when a long queue is created' do
|
||||
it 'picks builds one-by-one' do
|
||||
expect(Ci::Build).to receive(:find).with(pending_job.id).and_call_original
|
||||
|
||||
expect(execute(specific_runner)).to eq(pending_job)
|
||||
end
|
||||
|
||||
include_examples 'handles runner assignment'
|
||||
end
|
||||
|
||||
context 'when using pending builds table' do
|
||||
include_examples 'handles runner assignment'
|
||||
|
||||
|
|
|
@ -34,7 +34,10 @@ RSpec.describe MergeRequests::ReloadDiffsService, :use_clean_rails_memory_store_
|
|||
|
||||
context 'cache clearing' do
|
||||
it 'clears the cache for older diffs on the merge request' do
|
||||
expect_any_instance_of(Redis).to receive(:del).once.and_call_original
|
||||
redis = instance_double(Redis)
|
||||
expect(Gitlab::Redis::Cache).to receive(:with).and_yield(redis)
|
||||
|
||||
expect(redis).to receive(:del).once
|
||||
expect(Rails.cache).to receive(:delete).once.and_call_original
|
||||
|
||||
subject.execute
|
||||
|
|
|
@ -208,6 +208,7 @@ RSpec.configure do |config|
|
|||
|
||||
include StubFeatureFlags
|
||||
include StubSnowplow
|
||||
include StubMember
|
||||
|
||||
if ENV['CI'] || ENV['RETRIES']
|
||||
# This includes the first try, i.e. tests will be run 4 times before failing.
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module StubMember
|
||||
def self.included(base)
|
||||
GroupMember.prepend(StubbedMember::GroupMember)
|
||||
ProjectMember.prepend(StubbedMember::ProjectMember)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,64 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# Extend the ProjectMember & GroupMember class with the ability to
|
||||
# to run project_authorizations refresh jobs inline.
|
||||
|
||||
# This is needed so that calls like `group.add_member(user)` or `create(:project_member)`
|
||||
# in the specs can be run without including `:sidekiq_inline` trait.
|
||||
module StubbedMember
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
module ClearDeduplicationData
|
||||
private
|
||||
|
||||
def clear_deduplication_data!
|
||||
Gitlab::Redis::Queues.with do |redis|
|
||||
redis.scan_each(match: '*duplicate*').each do |key|
|
||||
redis.del(key)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
module GroupMember
|
||||
include ClearDeduplicationData
|
||||
|
||||
private
|
||||
|
||||
def refresh_member_authorized_projects(blocking:)
|
||||
return super unless blocking
|
||||
|
||||
# First, we remove all the keys associated with deduplication from Redis.
|
||||
# We can't perform a full flush with `Gitlab::Redis::Queues.with(&:flushdb)`
|
||||
# because that is going to remove other, unrelated enqueued jobs as well,
|
||||
# and that is going to fail some specs.
|
||||
clear_deduplication_data!
|
||||
|
||||
# then we run `super`, which will enqueue a project authorizations refresh job
|
||||
super
|
||||
|
||||
# then we drain (run) the jobs that were enqueued, but only for the worker class we are interested in.
|
||||
AuthorizedProjectsWorker.drain
|
||||
ensure
|
||||
clear_deduplication_data!
|
||||
end
|
||||
end
|
||||
|
||||
module ProjectMember
|
||||
include ClearDeduplicationData
|
||||
|
||||
private
|
||||
|
||||
def refresh_member_authorized_projects(blocking:)
|
||||
return super unless blocking
|
||||
|
||||
clear_deduplication_data!
|
||||
|
||||
super
|
||||
|
||||
AuthorizedProjectUpdate::ProjectRecalculatePerUserWorker.drain
|
||||
ensure
|
||||
clear_deduplication_data!
|
||||
end
|
||||
end
|
||||
end
|
|
@ -30,19 +30,33 @@ RSpec.describe WaitableWorker do
|
|||
|
||||
describe '.bulk_perform_and_wait' do
|
||||
context '1 job' do
|
||||
it 'inlines the job' do
|
||||
args_list = [[1]]
|
||||
expect(worker).to receive(:bulk_perform_inline).with(args_list).and_call_original
|
||||
expect(Gitlab::AppJsonLogger).to(
|
||||
receive(:info).with(a_hash_including('message' => 'running inline',
|
||||
'class' => 'Gitlab::Foo::Bar::DummyWorker',
|
||||
'job_status' => 'running',
|
||||
'queue' => 'foo_bar_dummy'))
|
||||
.once)
|
||||
it 'runs the jobs asynchronously' do
|
||||
arguments = [[1]]
|
||||
|
||||
worker.bulk_perform_and_wait(args_list)
|
||||
expect(worker).to receive(:bulk_perform_async).with(arguments)
|
||||
|
||||
expect(worker.counter).to eq(1)
|
||||
worker.bulk_perform_and_wait(arguments)
|
||||
end
|
||||
|
||||
context 'when the feature flag `always_async_project_authorizations_refresh` is turned off' do
|
||||
before do
|
||||
stub_feature_flags(always_async_project_authorizations_refresh: false)
|
||||
end
|
||||
|
||||
it 'inlines the job' do
|
||||
args_list = [[1]]
|
||||
expect(worker).to receive(:bulk_perform_inline).with(args_list).and_call_original
|
||||
expect(Gitlab::AppJsonLogger).to(
|
||||
receive(:info).with(a_hash_including('message' => 'running inline',
|
||||
'class' => 'Gitlab::Foo::Bar::DummyWorker',
|
||||
'job_status' => 'running',
|
||||
'queue' => 'foo_bar_dummy'))
|
||||
.once)
|
||||
|
||||
worker.bulk_perform_and_wait(args_list)
|
||||
|
||||
expect(worker.counter).to eq(1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in New Issue