Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
b02d831a00
commit
0d1b0d5d03
|
|
@ -24,26 +24,6 @@ Are there any other stages or teams involved that need to be kept in the loop?
|
|||
- The Delivery Team
|
||||
-->
|
||||
|
||||
## The Rollout Plan
|
||||
|
||||
- Partial Rollout on GitLab.com with testing groups
|
||||
- Rollout on GitLab.com for a certain period (How long)
|
||||
- Percentage Rollout on GitLab.com
|
||||
- Rollout Feature for everyone as soon as it's ready
|
||||
|
||||
<!-- Which dashboards from https://dashboards.gitlab.net are most relevant? Sentry errors reports can also be useful to review -->
|
||||
|
||||
## Testing Groups/Projects/Users
|
||||
|
||||
<!-- If applicable, any groups/projects that are happy to have this feature turned on early. Some organizations may wish to test big changes they are interested in with a small subset of users ahead of time for example. -->
|
||||
|
||||
- `gitlab-org/gitlab` project
|
||||
- `gitlab-org/gitlab-foss` project
|
||||
- `gitlab-com/www-gitlab-com` project
|
||||
- `gitlab-org`/`gitlab-com` groups
|
||||
- ...
|
||||
|
||||
|
||||
## Expectations
|
||||
|
||||
### What are we expecting to happen?
|
||||
|
|
@ -62,17 +42,30 @@ Are there any other stages or teams involved that need to be kept in the loop?
|
|||
|
||||
### Rollout on non-production environments
|
||||
|
||||
- [ ] Ensure that the feature MRs have been deployed to non-production environments.
|
||||
- Ensure that the feature MRs have been deployed to non-production environments.
|
||||
- [ ] `/chatops run auto_deploy status <merge-commit-of-your-feature>`
|
||||
- [ ] Enable the feature globally on non-production environments.
|
||||
- [ ] `/chatops run feature set <feature-flag-name> true --dev`
|
||||
- [ ] `/chatops run feature set <feature-flag-name> true --staging`
|
||||
- [ ] Verify that the feature works as expected. Posting the QA result in this issue is preferable.
|
||||
|
||||
### Preparation before production rollout
|
||||
### Specific rollout on production
|
||||
|
||||
- [ ] Ensure that the feature MRs have been deployed to both production and canary.
|
||||
- Ensure that the feature MRs have been deployed to both production and canary.
|
||||
- [ ] `/chatops run auto_deploy status <merge-commit-of-your-feature>`
|
||||
- If you're using [project-actor](https://docs.gitlab.com/ee/development/feature_flags/#feature-actors), you must enable the feature on these entries:
|
||||
- [ ] `/chatops run feature set --project=gitlab-org/gitlab <feature-flag-name> true`
|
||||
- [ ] `/chatops run feature set --project=gitlab-org/gitlab-foss <feature-flag-name> true`
|
||||
- [ ] `/chatops run feature set --project=gitlab-com/www-gitlab-com <feature-flag-name> true`
|
||||
- If you're using [group-actor](https://docs.gitlab.com/ee/development/feature_flags/#feature-actors), you must enable the feature on these entries:
|
||||
- [ ] `/chatops run feature set --group=gitlab-org <feature-flag-name> true`
|
||||
- [ ] `/chatops run feature set --group=gitlab-com <feature-flag-name> true`
|
||||
- If you're using [user-actor](https://docs.gitlab.com/ee/development/feature_flags/#feature-actors), you must enable the feature on these entries:
|
||||
- [ ] `/chatops run feature set --user=<your-username> <feature-flag-name> true`
|
||||
- [ ] Verify that the feature works on the specific entries. Posting the QA result in this issue is preferable.
|
||||
|
||||
### Preparation before global rollout
|
||||
|
||||
- [ ] Check if the feature flag change needs to be accompanied with a
|
||||
[change management issue](https://about.gitlab.com/handbook/engineering/infrastructure/change-management/#feature-flags-and-the-change-management-process).
|
||||
Cross link the issue here if it does.
|
||||
|
|
@ -86,19 +79,13 @@ Are there any other stages or teams involved that need to be kept in the loop?
|
|||
|
||||
All `/chatops` commands that target production should be done in the `#production` slack channel for visibility.
|
||||
|
||||
- [ ] Confirm the feature flag is enabled on `staging` without incident
|
||||
- [ ] Roll out the feature to targeted testing projects/groups first
|
||||
- [ ] `/chatops run feature set --project=gitlab-org/gitlab <feature-flag-name> true`
|
||||
- [ ] `/chatops run feature set --project=gitlab-org/gitlab-foss <feature-flag-name> true`
|
||||
- [ ] `/chatops run feature set --project=gitlab-com/www-gitlab-com <feature-flag-name> true`
|
||||
|
||||
- [ ] [Incrementally roll out](https://docs.gitlab.com/ee/development/feature_flags/controls.html#process) the feature.
|
||||
- If the feature flag in code has [an actor](https://docs.gitlab.com/ee/development/feature_flags/#feature-actors), perform **actor-based** rollout.
|
||||
- [ ] `/chatops run feature set <feature-flag-name> <rollout-percentage> --actors`
|
||||
- If the feature flag in code does **NOT** have [an actor](https://docs.gitlab.com/ee/development/feature_flags/#feature-actors), perform time-based rollout (**random** rollout).
|
||||
- [ ] `/chatops run feature set <feature-flag-name> <rollout-percentage>`
|
||||
- [ ] Verify the change has the desired outcome with the limited rollout before enabling the feature globally on production.
|
||||
- [ ] Enable the feature globally on production environment. `/chatops run feature set <feature-flag-name> true`
|
||||
- Enable the feature globally on production environment.
|
||||
- [ ] `/chatops run feature set <feature-flag-name> true`
|
||||
- [ ] Announce on [the feature issue](ISSUE LINK) that the feature has been globally enabled.
|
||||
- [ ] Wait for [at least one day for the verification term](https://about.gitlab.com/handbook/product-development-flow/feature-flag-lifecycle/#including-a-feature-behind-feature-flag-in-the-final-release).
|
||||
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
a47a975ef7d4ef51e0d68c5662d5cb3bb5b83b76
|
||||
2b424740fc73419f40bd74c2f05db3d7ef774198
|
||||
|
|
|
|||
|
|
@ -205,7 +205,7 @@ export default {
|
|||
:disabled="isSubmitButtonDisabled"
|
||||
:loading="isSubmitting"
|
||||
type="submit"
|
||||
class="js-add-issuable-form-add-button float-left"
|
||||
class="float-left"
|
||||
data-qa-selector="add_issue_button"
|
||||
>
|
||||
{{ __('Add') }}
|
||||
|
|
|
|||
|
|
@ -111,7 +111,6 @@ export default {
|
|||
:disabled="removeDisabled"
|
||||
data-testid="removeBtn"
|
||||
type="button"
|
||||
class="js-issue-token-remove-button"
|
||||
@click="onRemoveRequest"
|
||||
>
|
||||
<gl-icon name="close" />
|
||||
|
|
|
|||
|
|
@ -107,9 +107,6 @@ export default {
|
|||
onAutoCompleteToggled(isOpen) {
|
||||
this.isAutoCompleteOpen = isOpen;
|
||||
},
|
||||
onInputWrapperClick() {
|
||||
this.$refs.input.focus();
|
||||
},
|
||||
onInput() {
|
||||
const { value } = this.$refs.input;
|
||||
const caretPos = this.$refs.input.selectionStart;
|
||||
|
|
@ -185,26 +182,23 @@ export default {
|
|||
<div
|
||||
ref="issuableFormWrapper"
|
||||
:class="{ focus: isInputFocused }"
|
||||
class="add-issuable-form-input-wrapper form-control gl-field-error-outline"
|
||||
class="add-issuable-form-input-wrapper form-control gl-field-error-outline gl-h-auto gl-p-3 gl-pb-2"
|
||||
role="button"
|
||||
@click="onIssuableFormWrapperClick"
|
||||
>
|
||||
<ul class="add-issuable-form-input-token-list">
|
||||
<!--
|
||||
We need to ensure this key changes any time the pendingReferences array is updated
|
||||
else two consecutive pending ref strings in an array with the same name will collide
|
||||
and cause odd behavior when one is removed.
|
||||
-->
|
||||
<ul
|
||||
class="gl-display-flex gl-flex-wrap gl-align-items-baseline gl-list-style-none gl-m-0 gl-p-0"
|
||||
>
|
||||
<li
|
||||
v-for="(reference, index) in references"
|
||||
:key="`related-issues-token-${reference}`"
|
||||
class="js-add-issuable-form-token-list-item add-issuable-form-token-list-item"
|
||||
:key="reference"
|
||||
class="gl-max-w-full gl-mb-2 gl-mr-2"
|
||||
>
|
||||
<issue-token
|
||||
:id-key="index"
|
||||
:display-reference="reference.text || reference"
|
||||
:can-remove="true"
|
||||
:is-condensed="true"
|
||||
can-remove
|
||||
is-condensed
|
||||
:path-id-separator="pathIdSeparator"
|
||||
event-namespace="pendingIssuable"
|
||||
@pendingIssuableRemoveRequest="
|
||||
|
|
@ -214,14 +208,15 @@ export default {
|
|||
"
|
||||
/>
|
||||
</li>
|
||||
<li class="add-issuable-form-input-list-item">
|
||||
<li class="gl-mb-2 gl-flex-grow-1">
|
||||
<input
|
||||
:id="inputId"
|
||||
ref="input"
|
||||
:value="inputValue"
|
||||
:placeholder="inputPlaceholder"
|
||||
:aria-label="inputPlaceholder"
|
||||
type="text"
|
||||
class="js-add-issuable-form-input add-issuable-form-input"
|
||||
class="gl-w-full gl-border-none gl-outline-0"
|
||||
data-qa-selector="add_issue_field"
|
||||
autocomplete="off"
|
||||
@input="onInput"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<script>
|
||||
import { GlIcon, GlLink, GlLoadingIcon } from '@gitlab/ui';
|
||||
import { GlIcon, GlLink, GlLoadingIcon, GlSafeHtmlDirective as SafeHtml } from '@gitlab/ui';
|
||||
import $ from 'jquery';
|
||||
import '~/behaviors/markdown/render_gfm';
|
||||
import { handleLocationHash } from '~/lib/utils/common_utils';
|
||||
|
|
@ -22,6 +22,9 @@ export default {
|
|||
GlLink,
|
||||
GlLoadingIcon,
|
||||
},
|
||||
directives: {
|
||||
SafeHtml,
|
||||
},
|
||||
props: {
|
||||
blob: {
|
||||
type: Object,
|
||||
|
|
@ -59,11 +62,7 @@ export default {
|
|||
</div>
|
||||
<div class="blob-viewer" data-qa-selector="blob_viewer_content" itemprop="about">
|
||||
<gl-loading-icon v-if="loading > 0" size="md" color="dark" class="my-4 mx-auto" />
|
||||
<div
|
||||
v-else-if="readme"
|
||||
ref="readme"
|
||||
v-html="readme.html /* eslint-disable-line vue/no-v-html */"
|
||||
></div>
|
||||
<div v-else-if="readme" ref="readme" v-safe-html="readme.html"></div>
|
||||
</div>
|
||||
</article>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -1,11 +1,18 @@
|
|||
<script>
|
||||
import { GlBadge } from '@gitlab/ui';
|
||||
import { GlTooltipDirective } from '@gitlab/ui';
|
||||
import RunnerTypeBadge from '../runner_type_badge.vue';
|
||||
import RunnerStateLockedBadge from '../runner_state_locked_badge.vue';
|
||||
import RunnerStatePausedBadge from '../runner_state_paused_badge.vue';
|
||||
import { I18N_LOCKED_RUNNER_DESCRIPTION, I18N_PAUSED_RUNNER_DESCRIPTION } from '../../constants';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
GlBadge,
|
||||
RunnerTypeBadge,
|
||||
RunnerStateLockedBadge,
|
||||
RunnerStatePausedBadge,
|
||||
},
|
||||
directives: {
|
||||
GlTooltip: GlTooltipDirective,
|
||||
},
|
||||
props: {
|
||||
runner: {
|
||||
|
|
@ -24,19 +31,17 @@ export default {
|
|||
return !this.runner.active;
|
||||
},
|
||||
},
|
||||
i18n: {
|
||||
I18N_LOCKED_RUNNER_DESCRIPTION,
|
||||
I18N_PAUSED_RUNNER_DESCRIPTION,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<runner-type-badge :type="runnerType" size="sm" />
|
||||
|
||||
<gl-badge v-if="locked" variant="warning" size="sm">
|
||||
{{ s__('Runners|locked') }}
|
||||
</gl-badge>
|
||||
|
||||
<gl-badge v-if="paused" variant="danger" size="sm">
|
||||
{{ s__('Runners|paused') }}
|
||||
</gl-badge>
|
||||
<runner-state-locked-badge v-if="locked" size="sm" />
|
||||
<runner-state-paused-badge v-if="paused" size="sm" />
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,25 @@
|
|||
<script>
|
||||
import { GlBadge, GlTooltipDirective } from '@gitlab/ui';
|
||||
import { I18N_LOCKED_RUNNER_DESCRIPTION } from '../constants';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
GlBadge,
|
||||
},
|
||||
directives: {
|
||||
GlTooltip: GlTooltipDirective,
|
||||
},
|
||||
i18n: {
|
||||
I18N_LOCKED_RUNNER_DESCRIPTION,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<gl-badge
|
||||
v-gl-tooltip="$options.i18n.I18N_LOCKED_RUNNER_DESCRIPTION"
|
||||
variant="warning"
|
||||
v-bind="$attrs"
|
||||
>
|
||||
{{ s__('Runners|locked') }}
|
||||
</gl-badge>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
<script>
|
||||
import { GlBadge, GlTooltipDirective } from '@gitlab/ui';
|
||||
import { I18N_PAUSED_RUNNER_DESCRIPTION } from '../constants';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
GlBadge,
|
||||
},
|
||||
directives: {
|
||||
GlTooltip: GlTooltipDirective,
|
||||
},
|
||||
i18n: {
|
||||
I18N_PAUSED_RUNNER_DESCRIPTION,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<gl-badge
|
||||
v-gl-tooltip="$options.i18n.I18N_PAUSED_RUNNER_DESCRIPTION"
|
||||
variant="danger"
|
||||
v-bind="$attrs"
|
||||
>
|
||||
{{ s__('Runners|paused') }}
|
||||
</gl-badge>
|
||||
</template>
|
||||
|
|
@ -1,20 +1,30 @@
|
|||
<script>
|
||||
import { GlBadge } from '@gitlab/ui';
|
||||
import { GlBadge, GlTooltipDirective } from '@gitlab/ui';
|
||||
import { s__ } from '~/locale';
|
||||
import { INSTANCE_TYPE, GROUP_TYPE, PROJECT_TYPE } from '../constants';
|
||||
import {
|
||||
INSTANCE_TYPE,
|
||||
GROUP_TYPE,
|
||||
PROJECT_TYPE,
|
||||
I18N_INSTANCE_RUNNER_DESCRIPTION,
|
||||
I18N_GROUP_RUNNER_DESCRIPTION,
|
||||
I18N_PROJECT_RUNNER_DESCRIPTION,
|
||||
} from '../constants';
|
||||
|
||||
const BADGE_DATA = {
|
||||
[INSTANCE_TYPE]: {
|
||||
variant: 'success',
|
||||
text: s__('Runners|shared'),
|
||||
tooltip: I18N_INSTANCE_RUNNER_DESCRIPTION,
|
||||
},
|
||||
[GROUP_TYPE]: {
|
||||
variant: 'success',
|
||||
text: s__('Runners|group'),
|
||||
tooltip: I18N_GROUP_RUNNER_DESCRIPTION,
|
||||
},
|
||||
[PROJECT_TYPE]: {
|
||||
variant: 'info',
|
||||
text: s__('Runners|specific'),
|
||||
tooltip: I18N_PROJECT_RUNNER_DESCRIPTION,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
@ -22,6 +32,9 @@ export default {
|
|||
components: {
|
||||
GlBadge,
|
||||
},
|
||||
directives: {
|
||||
GlTooltip: GlTooltipDirective,
|
||||
},
|
||||
props: {
|
||||
type: {
|
||||
type: String,
|
||||
|
|
@ -40,7 +53,7 @@ export default {
|
|||
};
|
||||
</script>
|
||||
<template>
|
||||
<gl-badge v-if="badge" :variant="badge.variant" v-bind="$attrs">
|
||||
<gl-badge v-if="badge" v-gl-tooltip="badge.tooltip" :variant="badge.variant" v-bind="$attrs">
|
||||
{{ badge.text }}
|
||||
</gl-badge>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -1,18 +1,36 @@
|
|||
<script>
|
||||
import { GlBadge } from '@gitlab/ui';
|
||||
import { INSTANCE_TYPE, GROUP_TYPE, PROJECT_TYPE } from '../constants';
|
||||
import {
|
||||
INSTANCE_TYPE,
|
||||
GROUP_TYPE,
|
||||
PROJECT_TYPE,
|
||||
I18N_INSTANCE_RUNNER_DESCRIPTION,
|
||||
I18N_GROUP_RUNNER_DESCRIPTION,
|
||||
I18N_PROJECT_RUNNER_DESCRIPTION,
|
||||
I18N_LOCKED_RUNNER_DESCRIPTION,
|
||||
I18N_PAUSED_RUNNER_DESCRIPTION,
|
||||
} from '../constants';
|
||||
import RunnerTypeBadge from './runner_type_badge.vue';
|
||||
import RunnerStateLockedBadge from './runner_state_locked_badge.vue';
|
||||
import RunnerStatePausedBadge from './runner_state_paused_badge.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
GlBadge,
|
||||
RunnerTypeBadge,
|
||||
RunnerStateLockedBadge,
|
||||
RunnerStatePausedBadge,
|
||||
},
|
||||
runnerTypes: {
|
||||
INSTANCE_TYPE,
|
||||
GROUP_TYPE,
|
||||
PROJECT_TYPE,
|
||||
},
|
||||
i18n: {
|
||||
I18N_INSTANCE_RUNNER_DESCRIPTION,
|
||||
I18N_GROUP_RUNNER_DESCRIPTION,
|
||||
I18N_PROJECT_RUNNER_DESCRIPTION,
|
||||
I18N_LOCKED_RUNNER_DESCRIPTION,
|
||||
I18N_PAUSED_RUNNER_DESCRIPTION,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
|
|
@ -32,27 +50,23 @@ export default {
|
|||
<ul>
|
||||
<li>
|
||||
<runner-type-badge :type="$options.runnerTypes.INSTANCE_TYPE" size="sm" />
|
||||
- {{ __('Runs jobs from all unassigned projects.') }}
|
||||
- {{ $options.i18n.I18N_INSTANCE_RUNNER_DESCRIPTION }}
|
||||
</li>
|
||||
<li>
|
||||
<runner-type-badge :type="$options.runnerTypes.GROUP_TYPE" size="sm" />
|
||||
- {{ __('Runs jobs from all unassigned projects in its group.') }}
|
||||
- {{ $options.i18n.I18N_GROUP_RUNNER_DESCRIPTION }}
|
||||
</li>
|
||||
<li>
|
||||
<runner-type-badge :type="$options.runnerTypes.PROJECT_TYPE" size="sm" />
|
||||
- {{ __('Runs jobs from assigned projects.') }}
|
||||
- {{ $options.i18n.I18N_PROJECT_RUNNER_DESCRIPTION }}
|
||||
</li>
|
||||
<li>
|
||||
<gl-badge variant="warning" size="sm">
|
||||
{{ s__('Runners|locked') }}
|
||||
</gl-badge>
|
||||
- {{ __('Cannot be assigned to other projects.') }}
|
||||
<runner-state-locked-badge size="sm" />
|
||||
- {{ $options.i18n.I18N_LOCKED_RUNNER_DESCRIPTION }}
|
||||
</li>
|
||||
<li>
|
||||
<gl-badge variant="danger" size="sm">
|
||||
{{ s__('Runners|paused') }}
|
||||
</gl-badge>
|
||||
- {{ __('Not available to run jobs.') }}
|
||||
<runner-state-paused-badge size="sm" />
|
||||
- {{ $options.i18n.I18N_PAUSED_RUNNER_DESCRIPTION }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -7,6 +7,14 @@ export const GROUP_RUNNER_COUNT_LIMIT = 1000;
|
|||
export const I18N_FETCH_ERROR = s__('Runners|Something went wrong while fetching runner data.');
|
||||
export const I18N_DETAILS_TITLE = s__('Runners|Runner #%{runner_id}');
|
||||
|
||||
export const I18N_INSTANCE_RUNNER_DESCRIPTION = s__('Runners|Available to all projects');
|
||||
export const I18N_GROUP_RUNNER_DESCRIPTION = s__(
|
||||
'Runners|Available to all projects and subgroups in the group',
|
||||
);
|
||||
export const I18N_PROJECT_RUNNER_DESCRIPTION = s__('Runners|Associated with one or more projects');
|
||||
export const I18N_LOCKED_RUNNER_DESCRIPTION = s__('Runners|You cannot assign to other projects');
|
||||
export const I18N_PAUSED_RUNNER_DESCRIPTION = s__('Runners|Not available to run jobs');
|
||||
|
||||
export const RUNNER_TAG_BADGE_VARIANT = 'info';
|
||||
export const RUNNER_TAG_BG_CLASS = 'gl-bg-blue-100';
|
||||
|
||||
|
|
|
|||
|
|
@ -160,7 +160,12 @@ export default {
|
|||
wclass="report-block-list"
|
||||
class="report-block-container"
|
||||
>
|
||||
<li v-for="data in fullData" :key="data.id" class="gl-display-flex gl-align-items-center">
|
||||
<li
|
||||
v-for="data in fullData"
|
||||
:key="data.id"
|
||||
class="gl-display-flex gl-align-items-center"
|
||||
data-testid="extension-list-item"
|
||||
>
|
||||
<status-icon v-if="data.icon" :icon-name="data.icon.name" :size="12" />
|
||||
<div class="gl-mt-2 gl-mb-2 gl-flex-wrap gl-align-self-center gl-display-flex">
|
||||
<div v-safe-html="data.text" class="gl-mr-4"></div>
|
||||
|
|
|
|||
|
|
@ -746,33 +746,14 @@
|
|||
}
|
||||
}
|
||||
|
||||
.add-issuable-form-input-token-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: baseline;
|
||||
list-style: none;
|
||||
margin-bottom: 0;
|
||||
padding-left: 0;
|
||||
}
|
||||
.add-issuable-form-input-wrapper {
|
||||
&.focus {
|
||||
border-color: $blue-300;
|
||||
box-shadow: 0 0 4px $dropdown-input-focus-shadow;
|
||||
}
|
||||
|
||||
.add-issuable-form-token-list-item {
|
||||
max-width: 100%;
|
||||
margin-bottom: $gl-vert-padding;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.add-issuable-form-input-list-item {
|
||||
flex: 1;
|
||||
min-width: 200px;
|
||||
margin-bottom: $gl-vert-padding;
|
||||
}
|
||||
|
||||
.add-issuable-form-input {
|
||||
width: 100%;
|
||||
border: 0;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
.gl-show-field-errors &.form-control:not(textarea) {
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,17 +18,21 @@ class Projects::TagsController < Projects::ApplicationController
|
|||
params[:sort] = params[:sort].presence || sort_value_recently_updated
|
||||
|
||||
@sort = params[:sort]
|
||||
@tags = TagsFinder.new(@repository, params).execute
|
||||
@tags = Kaminari.paginate_array(@tags).page(params[:page])
|
||||
|
||||
@tags, @tags_loading_error = TagsFinder.new(@repository, params).execute
|
||||
|
||||
@tags = Kaminari.paginate_array(@tags).page(params[:page])
|
||||
tag_names = @tags.map(&:name)
|
||||
@tags_pipelines = @project.ci_pipelines.latest_successful_for_refs(tag_names)
|
||||
|
||||
@releases = project.releases.where(tag: tag_names)
|
||||
@tag_pipeline_statuses = Ci::CommitStatusesFinder.new(@project, @repository, current_user, @tags).execute
|
||||
|
||||
respond_to do |format|
|
||||
format.html
|
||||
format.atom { render layout: 'xml.atom' }
|
||||
status = @tags_loading_error ? :service_unavailable : :ok
|
||||
|
||||
format.html { render status: status }
|
||||
format.atom { render layout: 'xml.atom', status: status }
|
||||
end
|
||||
end
|
||||
# rubocop: enable CodeReuse/ActiveRecord
|
||||
|
|
|
|||
|
|
@ -284,9 +284,9 @@ class ProjectsController < Projects::ApplicationController
|
|||
end
|
||||
|
||||
if find_tags && @repository.tag_count.nonzero?
|
||||
tags = TagsFinder.new(@repository, params).execute.take(100).map(&:name)
|
||||
tags, _ = TagsFinder.new(@repository, params).execute
|
||||
|
||||
options['Tags'] = tags
|
||||
options['Tags'] = tags.take(100).map(&:name)
|
||||
end
|
||||
|
||||
# If reference is commit id - we should add it to branch/tag selectbox
|
||||
|
|
|
|||
|
|
@ -7,6 +7,9 @@ class TagsFinder < GitRefsFinder
|
|||
|
||||
def execute
|
||||
tags = repository.tags_sorted_by(sort)
|
||||
by_search(tags)
|
||||
|
||||
[by_search(tags), nil]
|
||||
rescue Gitlab::Git::CommandError => e
|
||||
[[], e]
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ module Ci
|
|||
end
|
||||
|
||||
def upcoming_processables
|
||||
if unordered? || Feature.disabled?(:ci_resource_group_process_modes, project, default_enabled: :yaml)
|
||||
if unordered?
|
||||
processables.waiting_for_resource
|
||||
elsif oldest_first?
|
||||
processables.waiting_for_resource_or_upcoming
|
||||
|
|
|
|||
|
|
@ -1,14 +1,17 @@
|
|||
#js-authenticate-token-2fa
|
||||
%a.gl-button.btn.btn-block.btn-confirm#js-login-2fa-device{ href: '#' }= _("Sign in via 2FA code")
|
||||
|
||||
-# haml-lint:disable InlineJavaScript
|
||||
%script#js-authenticate-token-2fa-in-progress{ type: "text/template" }
|
||||
%p= _("Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now.")
|
||||
|
||||
-# haml-lint:disable InlineJavaScript
|
||||
%script#js-authenticate-token-2fa-error{ type: "text/template" }
|
||||
%div
|
||||
%p <%= error_message %> (<%= error_name %>)
|
||||
%a.btn.btn-default.gl-button.btn-block#js-token-2fa-try-again= _("Try again?")
|
||||
|
||||
-# haml-lint:disable InlineJavaScript
|
||||
%script#js-authenticate-token-2fa-authenticated{ type: "text/template" }
|
||||
%div
|
||||
%p= _("We heard back from your device. You have been authenticated.")
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
#js-register-token-2fa
|
||||
|
||||
-# haml-lint:disable InlineJavaScript
|
||||
%script#js-register-2fa-message{ type: "text/template" }
|
||||
%p <%= message %>
|
||||
|
||||
-# haml-lint:disable InlineJavaScript
|
||||
%script#js-register-token-2fa-setup{ type: "text/template" }
|
||||
- if current_user.two_factor_otp_enabled?
|
||||
.row.gl-mb-3
|
||||
|
|
@ -17,12 +19,14 @@
|
|||
.col-md-8
|
||||
%p= _("You need to register a two-factor authentication app before you can set up a device.")
|
||||
|
||||
-# haml-lint:disable InlineJavaScript
|
||||
%script#js-register-token-2fa-error{ type: "text/template" }
|
||||
%div
|
||||
%p
|
||||
%span <%= error_message %> (<%= error_name %>)
|
||||
%a.btn.btn-default.gl-button#js-token-2fa-try-again= _("Try again?")
|
||||
|
||||
-# haml-lint:disable InlineJavaScript
|
||||
%script#js-register-token-2fa-registered{ type: "text/template" }
|
||||
.row.gl-mb-3
|
||||
.col-md-12
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
%li
|
||||
%h2.breadcrumbs-sub-title{ data: { qa_selector: 'breadcrumb_sub_title_content' } }
|
||||
= link_to @breadcrumb_title, breadcrumb_title_link
|
||||
-# haml-lint:disable InlineJavaScript
|
||||
%script{ type: 'application/ld+json' }
|
||||
:plain
|
||||
#{schema_breadcrumb_json}
|
||||
|
|
|
|||
|
|
@ -31,4 +31,5 @@
|
|||
.form-actions
|
||||
= button_tag 'Create branch', class: 'gl-button btn btn-confirm'
|
||||
= link_to _('Cancel'), project_branches_path(@project), class: 'gl-button btn btn-default btn-cancel'
|
||||
-# haml-lint:disable InlineJavaScript
|
||||
%script#availableRefs{ type: "application/json" }= @project.repository.ref_names.to_json.html_safe
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@
|
|||
= render "projects/merge_requests/tabs/pane", id: "notes", class: "notes voting_notes" do
|
||||
.row
|
||||
%section.col-md-12
|
||||
-# haml-lint:disable InlineJavaScript
|
||||
%script.js-notes-data{ type: "application/json" }= initial_notes_data(true).to_json.html_safe
|
||||
.issuable-discussion.js-vue-notes-event
|
||||
- if @merge_request.description.present?
|
||||
|
|
|
|||
|
|
@ -12,5 +12,6 @@
|
|||
%code
|
||||
= @event.as_json_wo_empty
|
||||
|
||||
-# haml-lint:disable InlineJavaScript
|
||||
:javascript
|
||||
#{render 'tracker'}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,9 @@
|
|||
|
||||
= render_if_exists 'projects/commits/mirror_status'
|
||||
|
||||
- if @tags_loading_error
|
||||
= render 'shared/errors/gitaly_unavailable', reason: s_('TagsPage|Unable to load tags')
|
||||
|
||||
.tags
|
||||
- if @tags.any?
|
||||
%ul.flex-list.content-list
|
||||
|
|
|
|||
|
|
@ -54,4 +54,5 @@
|
|||
.form-actions.gl-display-flex
|
||||
= button_tag s_('TagsPage|Create tag'), class: 'gl-button btn btn-confirm gl-mr-3', data: { qa_selector: "create_tag_button" }
|
||||
= link_to s_('TagsPage|Cancel'), project_tags_path(@project), class: 'gl-button btn btn-default btn-cancel'
|
||||
-# haml-lint:disable InlineJavaScript
|
||||
%script#availableRefs{ type: "application/json" }= @project.repository.ref_names.to_json.html_safe
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
.gl-alert.gl-alert-danger.gl-mb-5.gl-mt-5
|
||||
.gl-alert-container
|
||||
= sprite_icon('error', size: 16, css_class: 'gl-icon gl-alert-icon gl-alert-icon-no-title')
|
||||
.gl-alert-content
|
||||
.gl-alert-title
|
||||
= reason
|
||||
.gl-alert-body
|
||||
= s_('The git server, Gitaly, is not available at this time. Please contact your administrator.')
|
||||
|
|
@ -7,6 +7,7 @@
|
|||
- can_edit_issuable = issuable_sidebar.dig(:current_user, :can_edit)
|
||||
- add_page_startup_api_call "#{issuable_sidebar[:issuable_json_path]}?serializer=sidebar_extras"
|
||||
- reviewers = local_assigns.fetch(:reviewers, nil)
|
||||
- in_group_context_with_iterations = @project.group.present? && issuable_sidebar[:supports_iterations]
|
||||
|
||||
%aside.right-sidebar.js-right-sidebar.js-issuable-sidebar{ data: { signed: { in: signed_in }, issuable_type: issuable_type }, class: sidebar_gutter_collapsed_class, 'aria-live' => 'polite', 'aria-label': issuable_type }
|
||||
.issuable-sidebar
|
||||
|
|
@ -28,11 +29,11 @@
|
|||
= render_if_exists 'shared/issuable/sidebar_item_epic', issuable_sidebar: issuable_sidebar, group_path: @project.group.full_path, project_path: issuable_sidebar[:project_full_path], issue_iid: issuable_sidebar[:iid], issuable_type: issuable_type
|
||||
|
||||
- if issuable_sidebar[:supports_milestone]
|
||||
.block.milestone{ :class => ("gl-border-b-0!" if issuable_sidebar[:supports_iterations]), data: { qa_selector: 'milestone_block' } }
|
||||
.block.milestone{ :class => ("gl-border-b-0!" if in_group_context_with_iterations), data: { qa_selector: 'milestone_block' } }
|
||||
.js-milestone-select{ data: { can_edit: can_edit_issuable.to_s, project_path: issuable_sidebar[:project_full_path], issue_iid: issuable_sidebar[:iid] } }
|
||||
|
||||
- if @project.group.present? && issuable_sidebar[:supports_iterations]
|
||||
.block{ class: 'gl-pt-0!', data: { qa_selector: 'iteration_container' } }
|
||||
- if in_group_context_with_iterations
|
||||
.block{ class: 'gl-pt-0! gl-collapse-empty', data: { qa_selector: 'iteration_container', testid: 'iteration_container' } }<
|
||||
= render_if_exists 'shared/issuable/iteration_select', can_edit: can_edit_issuable.to_s, group_path: @project.group.full_path, project_path: issuable_sidebar[:project_full_path], issue_iid: issuable_sidebar[:iid], issuable_type: issuable_type
|
||||
|
||||
- if issuable_sidebar[:supports_time_tracking]
|
||||
|
|
@ -55,11 +56,13 @@
|
|||
.js-sidebar-status-entry-point{ data: sidebar_status_data(issuable_sidebar, @project) }
|
||||
|
||||
- if issuable_sidebar.has_key?(:confidential)
|
||||
-# haml-lint:disable InlineJavaScript
|
||||
%script#js-confidential-issue-data{ type: "application/json" }= { is_confidential: issuable_sidebar[:confidential], is_editable: can_edit_issuable }.to_json.html_safe
|
||||
#js-confidential-entry-point
|
||||
|
||||
= render_if_exists 'shared/issuable/sidebar_cve_id_request', issuable_sidebar: issuable_sidebar
|
||||
|
||||
-# haml-lint:disable InlineJavaScript
|
||||
%script#js-lock-issue-data{ type: "application/json" }= { is_locked: !!issuable_sidebar[:discussion_locked], is_editable: can_edit_issuable }.to_json.html_safe
|
||||
#js-lock-entry-point
|
||||
|
||||
|
|
|
|||
|
|
@ -25,4 +25,5 @@
|
|||
= sprite_icon('lock', css_class: 'icon')
|
||||
%span
|
||||
= html_escape(_("This %{issuable} is locked. Only %{strong_open}project members%{strong_close} can comment.")) % { issuable: issuable.class.to_s.titleize.downcase, strong_open: '<strong>'.html_safe, strong_close: '</strong>'.html_safe }
|
||||
-# haml-lint:disable InlineJavaScript
|
||||
%script.js-notes-data{ type: "application/json" }= initial_notes_data(autocomplete).to_json.html_safe
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
name: advanced_search_multi_project_select
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/62606
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/333011
|
||||
milestone: '14.0'
|
||||
milestone: '14.4'
|
||||
type: development
|
||||
group: group::global search
|
||||
default_enabled: false
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
name: ci_resource_group_process_modes
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/67015
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/340380
|
||||
milestone: '14.3'
|
||||
name: refactor_mr_widgets_extensions
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/70993
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/341759
|
||||
milestone: '14.4'
|
||||
type: development
|
||||
group: group::release
|
||||
group: group::code review
|
||||
default_enabled: false
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
name: refactor_mr_widgets_extensions_user
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/70993
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/341759
|
||||
milestone: '14.4'
|
||||
type: development
|
||||
group: group::code review
|
||||
default_enabled: false
|
||||
|
|
@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/341849
|
|||
milestone: '14.4'
|
||||
type: development
|
||||
group: group::source code
|
||||
default_enabled: false
|
||||
default_enabled: true
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
stage: Release
|
||||
group: Release
|
||||
stage: Manage
|
||||
group: Optimize
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
|
||||
type: reference, api
|
||||
---
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
stage: Release
|
||||
group: Release
|
||||
stage: Manage
|
||||
group: Optimize
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
|
||||
type: reference, api
|
||||
---
|
||||
|
|
|
|||
|
|
@ -66,13 +66,9 @@ Only one resource can be attached to a resource group.
|
|||
|
||||
## Process modes
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/202186) in GitLab 14.3.
|
||||
|
||||
FLAG:
|
||||
On self-managed GitLab, by default this feature is not available.
|
||||
To make it available, ask an administrator to [enable the `ci_resource_group_process_modes` flag](../../administration/feature_flags.md).
|
||||
On GitLab.com, this feature is not available.
|
||||
The feature is not ready for production use.
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/202186) in GitLab 14.3.
|
||||
> - [Feature flag `ci_resource_group_process_modes`](https://gitlab.com/gitlab-org/gitlab/-/issues/340380) removed in GitLab 14.4.
|
||||
> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/202186) in GitLab 14.4.
|
||||
|
||||
You can choose a process mode to strategically control the job concurrency for your deployment preferences.
|
||||
The following modes are supported:
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ GitLab uses [Redis](https://redis.io) for the following distinct purposes:
|
|||
- To manage the shared application state.
|
||||
- To store CI trace chunks.
|
||||
- As a Pub/Sub queue backend for ActionCable.
|
||||
- CI trace chunk storage.
|
||||
- Rate limiting state storage.
|
||||
|
||||
In most environments (including the GDK), all of these point to the same
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
unless Rails.env.production?
|
||||
require_dependency 'haml_lint/haml_visitor'
|
||||
require_dependency 'haml_lint/linter'
|
||||
require_dependency 'haml_lint/linter_registry'
|
||||
require 'haml_lint/haml_visitor'
|
||||
require 'haml_lint/linter'
|
||||
require 'haml_lint/linter_registry'
|
||||
|
||||
module HamlLint
|
||||
class Linter::InlineJavaScript < Linter
|
||||
|
|
|
|||
|
|
@ -32,7 +32,6 @@ module API
|
|||
values: ::Ci::ResourceGroup.process_modes.keys
|
||||
end
|
||||
put ':id/resource_groups/:key' do
|
||||
not_found! unless ::Feature.enabled?(:ci_resource_group_process_modes, user_project, default_enabled: :yaml)
|
||||
authorize! :update_resource_group, resource_group
|
||||
|
||||
if resource_group.update(declared_params(include_missing: false))
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ module API
|
|||
use :pagination
|
||||
end
|
||||
get ':id/repository/tags', feature_category: :source_code_management do
|
||||
tags = ::TagsFinder.new(user_project.repository,
|
||||
tags, _ = ::TagsFinder.new(user_project.repository,
|
||||
sort: "#{params[:order_by]}_#{params[:sort]}",
|
||||
search: params[:search]).execute
|
||||
|
||||
|
|
|
|||
|
|
@ -6252,9 +6252,6 @@ msgstr ""
|
|||
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
|
||||
msgstr ""
|
||||
|
||||
msgid "Cannot be assigned to other projects."
|
||||
msgstr ""
|
||||
|
||||
msgid "Cannot be merged automatically"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -23169,9 +23166,6 @@ msgstr ""
|
|||
msgid "Not available for protected branches"
|
||||
msgstr ""
|
||||
|
||||
msgid "Not available to run jobs."
|
||||
msgstr ""
|
||||
|
||||
msgid "Not confidential"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -29214,6 +29208,15 @@ msgstr ""
|
|||
msgid "Runners|Are you sure you want to delete this runner?"
|
||||
msgstr ""
|
||||
|
||||
msgid "Runners|Associated with one or more projects"
|
||||
msgstr ""
|
||||
|
||||
msgid "Runners|Available to all projects"
|
||||
msgstr ""
|
||||
|
||||
msgid "Runners|Available to all projects and subgroups in the group"
|
||||
msgstr ""
|
||||
|
||||
msgid "Runners|Can run untagged jobs"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -29274,6 +29277,9 @@ msgstr ""
|
|||
msgid "Runners|New runner, has not connected yet"
|
||||
msgstr ""
|
||||
|
||||
msgid "Runners|Not available to run jobs"
|
||||
msgstr ""
|
||||
|
||||
msgid "Runners|Not connected"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -29397,6 +29403,9 @@ msgstr ""
|
|||
msgid "Runners|You can set up a specific runner to be used by multiple projects but you cannot make this a shared runner."
|
||||
msgstr ""
|
||||
|
||||
msgid "Runners|You cannot assign to other projects"
|
||||
msgstr ""
|
||||
|
||||
msgid "Runners|You have used %{quotaUsed} out of %{quotaLimit} of your shared Runners pipeline minutes."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -29427,15 +29436,6 @@ msgstr ""
|
|||
msgid "Runs a number of housekeeping tasks within the current repository, such as compressing file revisions and removing unreachable objects."
|
||||
msgstr ""
|
||||
|
||||
msgid "Runs jobs from all unassigned projects in its group."
|
||||
msgstr ""
|
||||
|
||||
msgid "Runs jobs from all unassigned projects."
|
||||
msgstr ""
|
||||
|
||||
msgid "Runs jobs from assigned projects."
|
||||
msgstr ""
|
||||
|
||||
msgid "SAML"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -33197,6 +33197,9 @@ msgstr ""
|
|||
msgid "TagsPage|This tag has no release notes."
|
||||
msgstr ""
|
||||
|
||||
msgid "TagsPage|Unable to load tags"
|
||||
msgstr ""
|
||||
|
||||
msgid "TagsPage|Use git tag command to add a new one:"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -33779,6 +33782,9 @@ msgstr ""
|
|||
msgid "The form contains the following warning:"
|
||||
msgstr ""
|
||||
|
||||
msgid "The git server, Gitaly, is not available at this time. Please contact your administrator."
|
||||
msgstr ""
|
||||
|
||||
msgid "The global settings require you to enable Two-Factor Authentication for your account."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -39775,6 +39781,11 @@ msgstr ""
|
|||
msgid "ciReport|Investigate this vulnerability by creating an issue"
|
||||
msgstr ""
|
||||
|
||||
msgid "ciReport|Load performance test metrics detected %{strongStart}%{changesFound}%{strongEnd} change"
|
||||
msgid_plural "ciReport|Load performance test metrics detected %{strongStart}%{changesFound}%{strongEnd} changes"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
msgid "ciReport|Load performance test metrics: "
|
||||
msgstr ""
|
||||
|
||||
|
|
|
|||
|
|
@ -55,9 +55,9 @@
|
|||
"@babel/preset-env": "^7.10.1",
|
||||
"@gitlab/at.js": "1.5.7",
|
||||
"@gitlab/favicon-overlay": "2.0.0",
|
||||
"@gitlab/svgs": "1.213.0",
|
||||
"@gitlab/svgs": "1.215.0",
|
||||
"@gitlab/tributejs": "1.0.0",
|
||||
"@gitlab/ui": "32.15.0",
|
||||
"@gitlab/ui": "32.18.0",
|
||||
"@gitlab/visual-review-tools": "1.6.1",
|
||||
"@rails/actioncable": "6.1.4-1",
|
||||
"@rails/ujs": "6.1.4-1",
|
||||
|
|
|
|||
|
|
@ -14,6 +14,22 @@ module QA
|
|||
:name,
|
||||
:full_path
|
||||
|
||||
# Get group projects
|
||||
#
|
||||
# @return [Array<QA::Resource::Project>]
|
||||
def projects
|
||||
parse_body(api_get_from("#{api_get_path}/projects")).map do |project|
|
||||
Project.init do |resource|
|
||||
resource.api_client = api_client
|
||||
resource.group = self
|
||||
resource.id = project[:id]
|
||||
resource.name = project[:name]
|
||||
resource.description = project[:description]
|
||||
resource.path_with_namespace = project[:path_with_namespace]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Get group labels
|
||||
#
|
||||
# @return [Array<QA::Resource::GroupLabel>]
|
||||
|
|
|
|||
|
|
@ -358,6 +358,46 @@ module QA
|
|||
parse_body(response)
|
||||
end
|
||||
|
||||
# Object comparison
|
||||
#
|
||||
# @param [QA::Resource::Project] other
|
||||
# @return [Boolean]
|
||||
def ==(other)
|
||||
other.is_a?(Project) && comparable_project == other.comparable_project
|
||||
end
|
||||
|
||||
# Override inspect for a better rspec failure diff output
|
||||
#
|
||||
# @return [String]
|
||||
def inspect
|
||||
JSON.pretty_generate(comparable_project)
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
# Return subset of fields for comparing projects
|
||||
#
|
||||
# @return [Hash]
|
||||
def comparable_project
|
||||
reload! if api_response.nil?
|
||||
|
||||
api_resource.slice(
|
||||
:name,
|
||||
:path,
|
||||
:description,
|
||||
:tag_list,
|
||||
:archived,
|
||||
:issues_enabled,
|
||||
:merge_request_enabled,
|
||||
:wiki_enabled,
|
||||
:jobs_enabled,
|
||||
:snippets_enabled,
|
||||
:shared_runners_enabled,
|
||||
:request_access_enabled,
|
||||
:avatar_url
|
||||
)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def transform_api_resource(api_resource)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,76 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module QA
|
||||
RSpec.describe 'Manage', :requires_admin do
|
||||
describe 'Bulk project import' do
|
||||
let!(:staging?) { Runtime::Scenario.gitlab_address.include?('staging.gitlab.com') }
|
||||
|
||||
let(:import_wait_duration) { { max_duration: 300, sleep_interval: 2 } }
|
||||
let(:admin_api_client) { Runtime::API::Client.as_admin }
|
||||
let(:user) do
|
||||
Resource::User.fabricate_via_api! do |usr|
|
||||
usr.api_client = admin_api_client
|
||||
usr.hard_delete_on_api_removal = true
|
||||
end
|
||||
end
|
||||
|
||||
let(:api_client) { Runtime::API::Client.new(user: user) }
|
||||
|
||||
let(:sandbox) do
|
||||
Resource::Sandbox.fabricate_via_api! do |group|
|
||||
group.api_client = admin_api_client
|
||||
end
|
||||
end
|
||||
|
||||
let(:source_group) do
|
||||
Resource::Sandbox.fabricate_via_api! do |group|
|
||||
group.api_client = api_client
|
||||
group.path = "source-group-for-import-#{SecureRandom.hex(4)}"
|
||||
end
|
||||
end
|
||||
|
||||
let(:source_project) do
|
||||
Resource::Project.fabricate_via_api! do |project|
|
||||
project.api_client = api_client
|
||||
project.group = source_group
|
||||
end
|
||||
end
|
||||
|
||||
let(:imported_group) do
|
||||
Resource::BulkImportGroup.fabricate_via_api! do |group|
|
||||
group.api_client = api_client
|
||||
group.sandbox = sandbox
|
||||
group.source_group_path = source_group.path
|
||||
end
|
||||
end
|
||||
|
||||
before do
|
||||
Runtime::Feature.enable(:bulk_import_projects)
|
||||
Runtime::Feature.enable(:top_level_group_creation_enabled) if staging?
|
||||
|
||||
sandbox.add_member(user, Resource::Members::AccessLevel::MAINTAINER)
|
||||
|
||||
source_project # fabricate source group and project
|
||||
end
|
||||
|
||||
after do
|
||||
user.remove_via_api!
|
||||
ensure
|
||||
Runtime::Feature.disable(:bulk_import_projects)
|
||||
Runtime::Feature.disable(:top_level_group_creation_enabled) if staging?
|
||||
end
|
||||
|
||||
context 'with project' do
|
||||
it 'successfully imports project' do
|
||||
expect { imported_group.import_status }.to eventually_eq('finished').within(import_wait_duration)
|
||||
|
||||
imported_projects = imported_group.reload!.projects
|
||||
aggregate_failures do
|
||||
expect(imported_projects.count).to eq(1)
|
||||
expect(imported_projects.first).to eq(source_project)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -17,6 +17,25 @@ RSpec.describe Projects::TagsController do
|
|||
expect(assigns(:tags).map(&:name)).to include('v1.1.0', 'v1.0.0')
|
||||
end
|
||||
|
||||
context 'when Gitaly is unavailable' do
|
||||
where(:format) do
|
||||
[:html, :atom]
|
||||
end
|
||||
|
||||
with_them do
|
||||
it 'returns 503 status code' do
|
||||
expect_next_instance_of(TagsFinder) do |finder|
|
||||
expect(finder).to receive(:execute).and_return([[], Gitlab::Git::CommandError.new])
|
||||
end
|
||||
|
||||
get :index, params: { namespace_id: project.namespace.to_param, project_id: project }, format: format
|
||||
|
||||
expect(assigns(:tags)).to eq([])
|
||||
expect(response).to have_gitlab_http_status(:service_unavailable)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it 'returns releases matching those tags' do
|
||||
subject
|
||||
|
||||
|
|
|
|||
|
|
@ -231,8 +231,8 @@ RSpec.describe 'Related issues', :js do
|
|||
|
||||
it 'add related issue' do
|
||||
click_button 'Add a related issue'
|
||||
find('.js-add-issuable-form-input').set "#{issue_b.to_reference(project)} "
|
||||
find('.js-add-issuable-form-add-button').click
|
||||
fill_in 'Paste issue link', with: "#{issue_b.to_reference(project)} "
|
||||
click_button 'Add'
|
||||
|
||||
wait_for_requests
|
||||
|
||||
|
|
@ -248,8 +248,8 @@ RSpec.describe 'Related issues', :js do
|
|||
|
||||
it 'add cross-project related issue' do
|
||||
click_button 'Add a related issue'
|
||||
find('.js-add-issuable-form-input').set "#{issue_project_b_a.to_reference(project)} "
|
||||
find('.js-add-issuable-form-add-button').click
|
||||
fill_in 'Paste issue link', with: "#{issue_project_b_a.to_reference(project)} "
|
||||
click_button 'Add'
|
||||
|
||||
wait_for_requests
|
||||
|
||||
|
|
@ -262,8 +262,8 @@ RSpec.describe 'Related issues', :js do
|
|||
|
||||
it 'pressing enter should submit the form' do
|
||||
click_button 'Add a related issue'
|
||||
find('.js-add-issuable-form-input').set "#{issue_project_b_a.to_reference(project)} "
|
||||
find('.js-add-issuable-form-input').native.send_key(:enter)
|
||||
fill_in 'Paste issue link', with: "#{issue_project_b_a.to_reference(project)} "
|
||||
find_field('Paste issue link').native.send_key(:enter)
|
||||
|
||||
wait_for_requests
|
||||
|
||||
|
|
@ -276,9 +276,9 @@ RSpec.describe 'Related issues', :js do
|
|||
|
||||
it 'disallows duplicate entries' do
|
||||
click_button 'Add a related issue'
|
||||
find('.js-add-issuable-form-input').set 'duplicate duplicate duplicate'
|
||||
fill_in 'Paste issue link', with: 'duplicate duplicate duplicate'
|
||||
|
||||
items = all('.js-add-issuable-form-token-list-item')
|
||||
items = all('.issue-token')
|
||||
expect(items.count).to eq(1)
|
||||
expect(items[0].text).to eq('duplicate')
|
||||
|
||||
|
|
@ -289,28 +289,34 @@ RSpec.describe 'Related issues', :js do
|
|||
it 'allows us to remove pending issues' do
|
||||
# Tests against https://gitlab.com/gitlab-org/gitlab/issues/11625
|
||||
click_button 'Add a related issue'
|
||||
find('.js-add-issuable-form-input').set 'issue1 issue2 issue3 '
|
||||
fill_in 'Paste issue link', with: 'issue1 issue2 issue3 '
|
||||
|
||||
items = all('.js-add-issuable-form-token-list-item')
|
||||
items = all('.issue-token')
|
||||
expect(items.count).to eq(3)
|
||||
expect(items[0].text).to eq('issue1')
|
||||
expect(items[1].text).to eq('issue2')
|
||||
expect(items[2].text).to eq('issue3')
|
||||
|
||||
# Remove pending issues left to right to make sure none get stuck
|
||||
items[0].find('.js-issue-token-remove-button').click
|
||||
items = all('.js-add-issuable-form-token-list-item')
|
||||
within items[0] do
|
||||
click_button 'Remove'
|
||||
end
|
||||
items = all('.issue-token')
|
||||
expect(items.count).to eq(2)
|
||||
expect(items[0].text).to eq('issue2')
|
||||
expect(items[1].text).to eq('issue3')
|
||||
|
||||
items[0].find('.js-issue-token-remove-button').click
|
||||
items = all('.js-add-issuable-form-token-list-item')
|
||||
within items[0] do
|
||||
click_button 'Remove'
|
||||
end
|
||||
items = all('.issue-token')
|
||||
expect(items.count).to eq(1)
|
||||
expect(items[0].text).to eq('issue3')
|
||||
|
||||
items[0].find('.js-issue-token-remove-button').click
|
||||
items = all('.js-add-issuable-form-token-list-item')
|
||||
within items[0] do
|
||||
click_button 'Remove'
|
||||
end
|
||||
items = all('.issue-token')
|
||||
expect(items.count).to eq(0)
|
||||
end
|
||||
end
|
||||
|
|
@ -352,8 +358,8 @@ RSpec.describe 'Related issues', :js do
|
|||
|
||||
it 'add related issue' do
|
||||
click_button 'Add a related issue'
|
||||
find('.js-add-issuable-form-input').set "##{issue_d.iid} "
|
||||
find('.js-add-issuable-form-add-button').click
|
||||
fill_in 'Paste issue link', with: "##{issue_d.iid} "
|
||||
click_button 'Add'
|
||||
|
||||
wait_for_requests
|
||||
|
||||
|
|
@ -368,8 +374,8 @@ RSpec.describe 'Related issues', :js do
|
|||
|
||||
it 'add invalid related issue' do
|
||||
click_button 'Add a related issue'
|
||||
find('.js-add-issuable-form-input').set "#9999999 "
|
||||
find('.js-add-issuable-form-add-button').click
|
||||
fill_in 'Paste issue link', with: '#9999999 '
|
||||
click_button 'Add'
|
||||
|
||||
wait_for_requests
|
||||
|
||||
|
|
@ -383,8 +389,8 @@ RSpec.describe 'Related issues', :js do
|
|||
|
||||
it 'add unauthorized related issue' do
|
||||
click_button 'Add a related issue'
|
||||
find('.js-add-issuable-form-input').set "#{issue_project_unauthorized_a.to_reference(project)} "
|
||||
find('.js-add-issuable-form-add-button').click
|
||||
fill_in 'Paste issue link', with: "#{issue_project_unauthorized_a.to_reference(project)} "
|
||||
click_button 'Add'
|
||||
|
||||
wait_for_requests
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ RSpec.describe Ci::CommitStatusesFinder, '#execute' do
|
|||
let_it_be(:user) { create(:user) }
|
||||
|
||||
context 'tag refs' do
|
||||
let_it_be(:tags) { TagsFinder.new(project.repository, {}).execute }
|
||||
let_it_be(:tags) { project.repository.tags }
|
||||
|
||||
let(:subject) { described_class.new(project, project.repository, user, tags).execute }
|
||||
|
||||
|
|
@ -131,7 +131,7 @@ RSpec.describe Ci::CommitStatusesFinder, '#execute' do
|
|||
end
|
||||
|
||||
context 'CI pipelines visible to' do
|
||||
let_it_be(:tags) { TagsFinder.new(project.repository, {}).execute }
|
||||
let_it_be(:tags) { project.repository.tags }
|
||||
|
||||
let(:subject) { described_class.new(project, project.repository, user, tags).execute }
|
||||
|
||||
|
|
@ -161,7 +161,7 @@ RSpec.describe Ci::CommitStatusesFinder, '#execute' do
|
|||
|
||||
context 'when not a member of a private project' do
|
||||
let(:private_project) { create(:project, :private, :repository) }
|
||||
let(:private_tags) { TagsFinder.new(private_tags.repository, {}).execute }
|
||||
let(:private_tags) { private_tags.repository.tags }
|
||||
let(:private_subject) { described_class.new(private_project, private_project.repository, user, tags).execute }
|
||||
|
||||
before do
|
||||
|
|
|
|||
|
|
@ -3,93 +3,76 @@
|
|||
require 'spec_helper'
|
||||
|
||||
RSpec.describe TagsFinder do
|
||||
let(:user) { create(:user) }
|
||||
let(:project) { create(:project, :repository) }
|
||||
let(:repository) { project.repository }
|
||||
let_it_be(:user) { create(:user) }
|
||||
let_it_be(:project) { create(:project, :repository) }
|
||||
let_it_be(:repository) { project.repository }
|
||||
|
||||
def load_tags(params)
|
||||
tags_finder = described_class.new(repository, params)
|
||||
tags, error = tags_finder.execute
|
||||
|
||||
expect(error).to eq(nil)
|
||||
|
||||
tags
|
||||
end
|
||||
|
||||
describe '#execute' do
|
||||
context 'sort only' do
|
||||
it 'sorts by name' do
|
||||
tags_finder = described_class.new(repository, {})
|
||||
|
||||
result = tags_finder.execute
|
||||
|
||||
expect(result.first.name).to eq("v1.0.0")
|
||||
expect(load_tags({}).first.name).to eq("v1.0.0")
|
||||
end
|
||||
|
||||
it 'sorts by recently_updated' do
|
||||
tags_finder = described_class.new(repository, { sort: 'updated_desc' })
|
||||
|
||||
result = tags_finder.execute
|
||||
recently_updated_tag = repository.tags.max do |a, b|
|
||||
repository.commit(a.dereferenced_target).committed_date <=> repository.commit(b.dereferenced_target).committed_date
|
||||
end
|
||||
|
||||
expect(result.first.name).to eq(recently_updated_tag.name)
|
||||
params = { sort: 'updated_desc' }
|
||||
|
||||
expect(load_tags(params).first.name).to eq(recently_updated_tag.name)
|
||||
end
|
||||
|
||||
it 'sorts by last_updated' do
|
||||
tags_finder = described_class.new(repository, { sort: 'updated_asc' })
|
||||
params = { sort: 'updated_asc' }
|
||||
|
||||
result = tags_finder.execute
|
||||
|
||||
expect(result.first.name).to eq('v1.0.0')
|
||||
expect(load_tags(params).first.name).to eq('v1.0.0')
|
||||
end
|
||||
end
|
||||
|
||||
context 'filter only' do
|
||||
it 'filters tags by name' do
|
||||
tags_finder = described_class.new(repository, { search: '1.0.0' })
|
||||
|
||||
result = tags_finder.execute
|
||||
result = load_tags({ search: '1.0.0' })
|
||||
|
||||
expect(result.first.name).to eq('v1.0.0')
|
||||
expect(result.count).to eq(1)
|
||||
end
|
||||
|
||||
it 'does not find any tags with that name' do
|
||||
tags_finder = described_class.new(repository, { search: 'hey' })
|
||||
|
||||
result = tags_finder.execute
|
||||
|
||||
expect(result.count).to eq(0)
|
||||
expect(load_tags({ search: 'hey' }).count).to eq(0)
|
||||
end
|
||||
|
||||
it 'filters tags by name that begins with' do
|
||||
params = { search: '^v1.0' }
|
||||
tags_finder = described_class.new(repository, params)
|
||||
|
||||
result = tags_finder.execute
|
||||
result = load_tags({ search: '^v1.0' })
|
||||
|
||||
expect(result.first.name).to eq('v1.0.0')
|
||||
expect(result.count).to eq(1)
|
||||
end
|
||||
|
||||
it 'filters tags by name that ends with' do
|
||||
params = { search: '0.0$' }
|
||||
tags_finder = described_class.new(repository, params)
|
||||
|
||||
result = tags_finder.execute
|
||||
result = load_tags({ search: '0.0$' })
|
||||
|
||||
expect(result.first.name).to eq('v1.0.0')
|
||||
expect(result.count).to eq(1)
|
||||
end
|
||||
|
||||
it 'filters tags by nonexistent name that begins with' do
|
||||
params = { search: '^nope' }
|
||||
tags_finder = described_class.new(repository, params)
|
||||
|
||||
result = tags_finder.execute
|
||||
result = load_tags({ search: '^nope' })
|
||||
|
||||
expect(result.count).to eq(0)
|
||||
end
|
||||
|
||||
it 'filters tags by nonexistent name that ends with' do
|
||||
params = { search: 'nope$' }
|
||||
tags_finder = described_class.new(repository, params)
|
||||
|
||||
result = tags_finder.execute
|
||||
|
||||
result = load_tags({ search: 'nope$' })
|
||||
expect(result.count).to eq(0)
|
||||
end
|
||||
end
|
||||
|
|
@ -97,7 +80,7 @@ RSpec.describe TagsFinder do
|
|||
context 'filter and sort' do
|
||||
let(:tags_to_compare) { %w[v1.0.0 v1.1.0] }
|
||||
|
||||
subject { described_class.new(repository, params).execute.select { |tag| tags_to_compare.include?(tag.name) } }
|
||||
subject { load_tags(params).select { |tag| tags_to_compare.include?(tag.name) } }
|
||||
|
||||
context 'when sort by updated_desc' do
|
||||
let(:params) { { sort: 'updated_desc', search: 'v1' } }
|
||||
|
|
@ -117,5 +100,17 @@ RSpec.describe TagsFinder do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when Gitaly is unavailable' do
|
||||
it 'returns empty list of tags' do
|
||||
expect(Gitlab::GitalyClient).to receive(:call).and_raise(GRPC::Unavailable)
|
||||
|
||||
tags_finder = described_class.new(repository, {})
|
||||
tags, error = tags_finder.execute
|
||||
|
||||
expect(error).to be_a(Gitlab::Git::CommandError)
|
||||
expect(tags).to eq([])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { mount, shallowMount } from '@vue/test-utils';
|
||||
import AddIssuableForm from '~/related_issues/components/add_issuable_form.vue';
|
||||
import IssueToken from '~/related_issues/components/issue_token.vue';
|
||||
import { issuableTypesMap, linkedIssueTypesMap, PathIdSeparator } from '~/related_issues/constants';
|
||||
|
||||
const issuable1 = {
|
||||
|
|
@ -22,7 +23,7 @@ const issuable2 = {
|
|||
|
||||
const pathIdSeparator = PathIdSeparator.Issue;
|
||||
|
||||
const findFormInput = (wrapper) => wrapper.find('.js-add-issuable-form-input').element;
|
||||
const findFormInput = (wrapper) => wrapper.find('input').element;
|
||||
|
||||
const findRadioInput = (inputs, value) =>
|
||||
inputs.filter((input) => input.element.value === value)[0];
|
||||
|
|
@ -105,11 +106,11 @@ describe('AddIssuableForm', () => {
|
|||
});
|
||||
|
||||
it('should put input value in place', () => {
|
||||
expect(findFormInput(wrapper).value).toEqual(inputValue);
|
||||
expect(findFormInput(wrapper).value).toBe(inputValue);
|
||||
});
|
||||
|
||||
it('should render pending issuables items', () => {
|
||||
expect(wrapper.findAll('.js-add-issuable-form-token-list-item').length).toEqual(2);
|
||||
expect(wrapper.findAllComponents(IssueToken)).toHaveLength(2);
|
||||
});
|
||||
|
||||
it('should not have disabled submit button', () => {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,45 @@
|
|||
import { GlBadge } from '@gitlab/ui';
|
||||
import { shallowMount } from '@vue/test-utils';
|
||||
import RunnerStateLockedBadge from '~/runner/components/runner_state_locked_badge.vue';
|
||||
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
|
||||
|
||||
describe('RunnerTypeBadge', () => {
|
||||
let wrapper;
|
||||
|
||||
const findBadge = () => wrapper.findComponent(GlBadge);
|
||||
const getTooltip = () => getBinding(findBadge().element, 'gl-tooltip');
|
||||
|
||||
const createComponent = ({ props = {} } = {}) => {
|
||||
wrapper = shallowMount(RunnerStateLockedBadge, {
|
||||
propsData: {
|
||||
...props,
|
||||
},
|
||||
directives: {
|
||||
GlTooltip: createMockDirective(),
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
createComponent();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
wrapper.destroy();
|
||||
});
|
||||
|
||||
it('renders locked state', () => {
|
||||
expect(wrapper.text()).toBe('locked');
|
||||
expect(findBadge().props('variant')).toBe('warning');
|
||||
});
|
||||
|
||||
it('renders tooltip', () => {
|
||||
expect(getTooltip().value).toBeDefined();
|
||||
});
|
||||
|
||||
it('passes arbitrary attributes to the badge', () => {
|
||||
createComponent({ props: { size: 'sm' } });
|
||||
|
||||
expect(findBadge().props('size')).toBe('sm');
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
import { GlBadge } from '@gitlab/ui';
|
||||
import { shallowMount } from '@vue/test-utils';
|
||||
import RunnerStatePausedBadge from '~/runner/components/runner_state_paused_badge.vue';
|
||||
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
|
||||
|
||||
describe('RunnerTypeBadge', () => {
|
||||
let wrapper;
|
||||
|
||||
const findBadge = () => wrapper.findComponent(GlBadge);
|
||||
const getTooltip = () => getBinding(findBadge().element, 'gl-tooltip');
|
||||
|
||||
const createComponent = ({ props = {} } = {}) => {
|
||||
wrapper = shallowMount(RunnerStatePausedBadge, {
|
||||
propsData: {
|
||||
...props,
|
||||
},
|
||||
directives: {
|
||||
GlTooltip: createMockDirective(),
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
createComponent();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
wrapper.destroy();
|
||||
});
|
||||
|
||||
it('renders paused state', () => {
|
||||
expect(wrapper.text()).toBe('paused');
|
||||
expect(findBadge().props('variant')).toBe('danger');
|
||||
});
|
||||
|
||||
it('renders tooltip', () => {
|
||||
expect(getTooltip().value).toBeDefined();
|
||||
});
|
||||
|
||||
it('passes arbitrary attributes to the badge', () => {
|
||||
createComponent({ props: { size: 'sm' } });
|
||||
|
||||
expect(findBadge().props('size')).toBe('sm');
|
||||
});
|
||||
});
|
||||
|
|
@ -1,18 +1,23 @@
|
|||
import { GlBadge } from '@gitlab/ui';
|
||||
import { shallowMount } from '@vue/test-utils';
|
||||
import RunnerTypeBadge from '~/runner/components/runner_type_badge.vue';
|
||||
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
|
||||
import { INSTANCE_TYPE, GROUP_TYPE, PROJECT_TYPE } from '~/runner/constants';
|
||||
|
||||
describe('RunnerTypeBadge', () => {
|
||||
let wrapper;
|
||||
|
||||
const findBadge = () => wrapper.findComponent(GlBadge);
|
||||
const getTooltip = () => getBinding(findBadge().element, 'gl-tooltip');
|
||||
|
||||
const createComponent = ({ props = {} } = {}) => {
|
||||
wrapper = shallowMount(RunnerTypeBadge, {
|
||||
propsData: {
|
||||
...props,
|
||||
},
|
||||
directives: {
|
||||
GlTooltip: createMockDirective(),
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -20,16 +25,24 @@ describe('RunnerTypeBadge', () => {
|
|||
wrapper.destroy();
|
||||
});
|
||||
|
||||
it.each`
|
||||
describe.each`
|
||||
type | text | variant
|
||||
${INSTANCE_TYPE} | ${'shared'} | ${'success'}
|
||||
${GROUP_TYPE} | ${'group'} | ${'success'}
|
||||
${PROJECT_TYPE} | ${'specific'} | ${'info'}
|
||||
`('displays $type runner with as "$text" with a $variant variant ', ({ type, text, variant }) => {
|
||||
createComponent({ props: { type } });
|
||||
`('displays $type runner', ({ type, text, variant }) => {
|
||||
beforeEach(() => {
|
||||
createComponent({ props: { type } });
|
||||
});
|
||||
|
||||
expect(findBadge().text()).toBe(text);
|
||||
expect(findBadge().props('variant')).toBe(variant);
|
||||
it(`as "${text}" with a ${variant} variant`, () => {
|
||||
expect(findBadge().text()).toBe(text);
|
||||
expect(findBadge().props('variant')).toBe(variant);
|
||||
});
|
||||
|
||||
it('with a tooltip', () => {
|
||||
expect(getTooltip().value).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
it('validation fails for an incorrect type', () => {
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ RSpec.describe Gitlab::Git::WrapsGitalyErrors do
|
|||
mapping = {
|
||||
GRPC::NotFound => Gitlab::Git::Repository::NoRepository,
|
||||
GRPC::InvalidArgument => ArgumentError,
|
||||
GRPC::DeadlineExceeded => Gitlab::Git::CommandTimedOut,
|
||||
GRPC::BadStatus => Gitlab::Git::CommandError
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -117,14 +117,6 @@ RSpec.describe Ci::ResourceGroup do
|
|||
expect(subject[3]).to eq(build_2_waiting_for_resource)
|
||||
expect(subject[4..5]).to contain_exactly(build_2_created, build_2_scheduled)
|
||||
end
|
||||
|
||||
context 'when ci_resource_group_process_modes feature flag is disabled' do
|
||||
it 'returns correct jobs in an indeterministic order' do
|
||||
stub_feature_flags(ci_resource_group_process_modes: false)
|
||||
|
||||
expect(subject).to contain_exactly(build_1_waiting_for_resource, build_2_waiting_for_resource)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when process mode is newest_first' do
|
||||
|
|
@ -136,14 +128,6 @@ RSpec.describe Ci::ResourceGroup do
|
|||
expect(subject[3]).to eq(build_1_waiting_for_resource)
|
||||
expect(subject[4..5]).to contain_exactly(build_1_created, build_1_scheduled)
|
||||
end
|
||||
|
||||
context 'when ci_resource_group_process_modes feature flag is disabled' do
|
||||
it 'returns correct jobs in an indeterministic order' do
|
||||
stub_feature_flags(ci_resource_group_process_modes: false)
|
||||
|
||||
expect(subject).to contain_exactly(build_1_waiting_for_resource, build_2_waiting_for_resource)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when process mode is unknown' do
|
||||
|
|
|
|||
|
|
@ -62,18 +62,6 @@ RSpec.describe API::Ci::ResourceGroups do
|
|||
expect(json_response['process_mode']).to eq('oldest_first')
|
||||
end
|
||||
|
||||
context 'when ci_resource_group_process_modes feature flag is disabled' do
|
||||
before do
|
||||
stub_feature_flags(ci_resource_group_process_modes: false)
|
||||
end
|
||||
|
||||
it 'returns not found' do
|
||||
subject
|
||||
|
||||
expect(response).to have_gitlab_http_status(:not_found)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with invalid parameter' do
|
||||
let(:params) { { process_mode: :unknown } }
|
||||
|
||||
|
|
|
|||
|
|
@ -3,10 +3,11 @@
|
|||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'projects/tags/index.html.haml' do
|
||||
let(:project) { create(:project, :repository) }
|
||||
let(:tags) { TagsFinder.new(project.repository, {}).execute }
|
||||
let(:git_tag) { project.repository.tags.last }
|
||||
let(:release) { create(:release, project: project, sha: git_tag.target_commit.sha) }
|
||||
let_it_be(:project) { create(:project, :repository) }
|
||||
let_it_be(:tags) { project.repository.tags }
|
||||
let_it_be(:git_tag) { project.repository.tags.last }
|
||||
let_it_be(:release) { create(:release, project: project, sha: git_tag.target_commit.sha) }
|
||||
|
||||
let(:pipeline) { create(:ci_pipeline, :success, project: project, ref: git_tag.name, sha: release.sha) }
|
||||
|
||||
before do
|
||||
|
|
@ -86,4 +87,17 @@ RSpec.describe 'projects/tags/index.html.haml' do
|
|||
expect(page.all('.tags .content-list li')).not_to have_css 'svg.s24'
|
||||
end
|
||||
end
|
||||
|
||||
context 'when Gitaly is unavailable' do
|
||||
it 'renders an error' do
|
||||
assign(:tags_loading_error, GRPC::Unavailable.new)
|
||||
|
||||
content = render
|
||||
|
||||
expect(content).to include("Unable to load tags")
|
||||
expect(content).to include(
|
||||
"The git server, Gitaly, is not available at this time. Please contact your administrator."
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
16
yarn.lock
16
yarn.lock
|
|
@ -904,20 +904,20 @@
|
|||
stylelint-declaration-strict-value "1.7.7"
|
||||
stylelint-scss "3.18.0"
|
||||
|
||||
"@gitlab/svgs@1.213.0":
|
||||
version "1.213.0"
|
||||
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.213.0.tgz#fcd9794049d2b15f5796dbab2a3d501679153582"
|
||||
integrity sha512-3d9EGpEkPDeW92Xx3FueFCJFZ/yL+uv5MWCUHmSt1tP9YmUhMXw/51c43c5+V17FuCyvhJS5tm3aEg3VYoWIRA==
|
||||
"@gitlab/svgs@1.215.0":
|
||||
version "1.215.0"
|
||||
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.215.0.tgz#f2760bbb0a38b26346e1b755e63fb63eba005edd"
|
||||
integrity sha512-/bc0+EOYPQlPCMbfyOkMLxDKBn+ewEBlmTRmFwf7mXvfIRszdJPY8XCx/fJIEQwDr8+k4E28ktFnLZGnaFhCnw==
|
||||
|
||||
"@gitlab/tributejs@1.0.0":
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@gitlab/tributejs/-/tributejs-1.0.0.tgz#672befa222aeffc83e7d799b0500a7a4418e59b8"
|
||||
integrity sha512-nmKw1+hB6MHvlmPz63yPwVs1qQkycHwsKgxpEbzmky16Y6mL4EJMk3w1b8QlOAF/AIAzjCERPhe/R4MJiohbZw==
|
||||
|
||||
"@gitlab/ui@32.15.0":
|
||||
version "32.15.0"
|
||||
resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-32.15.0.tgz#292518f1c52ef22d73cfded9d6f9f6d48a47efee"
|
||||
integrity sha512-n7SwTA5Je+s/66cTXBhRdlxiJILGA+mXX6aevUFXzFvTn4a4yVb1wx4mmaMA/EB3vUxb8+u/z61CYZ4pd5JIbw==
|
||||
"@gitlab/ui@32.18.0":
|
||||
version "32.18.0"
|
||||
resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-32.18.0.tgz#cd340f050fe0183218f6233328aca2369bd6e449"
|
||||
integrity sha512-bDMmsNB9VMBX2JbezyJWfk02t0aFfAT9Ez4ALTDUJLb5/Q9GKByfE5sLycms6L1aZxzP6r1jypnu5DD0eT92eg==
|
||||
dependencies:
|
||||
"@babel/standalone" "^7.0.0"
|
||||
bootstrap-vue "2.19.0"
|
||||
|
|
|
|||
Loading…
Reference in New Issue