Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
ef96d56ed3
commit
0a559c913e
74 changed files with 505 additions and 227 deletions
|
@ -9,5 +9,5 @@
|
|||
<!-- Describe the audit event you are proposing should be added, including any details of what should be captured, how, and why. -->
|
||||
|
||||
/label ~"Category:Audit Events"
|
||||
/label ~"feature"
|
||||
/label ~"type::feature"
|
||||
/label ~"group::compliance"
|
||||
|
|
|
@ -2,10 +2,10 @@
|
|||
Please read this!
|
||||
|
||||
Before opening a new issue, make sure to search for keywords in the issues
|
||||
filtered by the "regression" or "bug" label:
|
||||
filtered by the "regression" or "type::bug" label:
|
||||
|
||||
- https://gitlab.com/gitlab-org/gitlab/issues?label_name%5B%5D=regression
|
||||
- https://gitlab.com/gitlab-org/gitlab/issues?label_name%5B%5D=bug
|
||||
- https://gitlab.com/gitlab-org/gitlab/issues?label_name%5B%5D=type::bug
|
||||
|
||||
and verify the issue you're about to submit isn't a duplicate.
|
||||
--->
|
||||
|
@ -82,4 +82,4 @@ will also determine whether the bug is fixed in a more recent version. -->
|
|||
|
||||
<!-- If you can, link to the line of code that might be responsible for the problem. -->
|
||||
|
||||
/label ~bug
|
||||
/label ~"type::bug"
|
||||
|
|
|
@ -17,4 +17,4 @@ The changes need to become an official part of the product.
|
|||
- [ ] After the flag removal is deployed, [clean up the feature/experiment feature flags](https://docs.gitlab.com/ee/development/feature_flags/controls.html#cleaning-up) by running chatops command in `#production` channel
|
||||
- [ ] Ensure the corresponding [Experiment Tracking](https://gitlab.com/groups/gitlab-org/-/boards/1352542?label_name[]=devops%3A%3Agrowth&label_name[]=growth%20experiment&label_name[]=experiment%20tracking) issue is updated
|
||||
|
||||
/label ~"feature" ~"feature::maintenance" ~"workflow::scheduling" ~"growth experiment" ~"feature flag"
|
||||
/label ~"type::maintenance" ~"workflow::scheduling" ~"growth experiment" ~"feature flag"
|
||||
|
|
|
@ -7,4 +7,4 @@
|
|||
<!-- Consider adding related issues and epics to this issue. You can also reference the Feature Proposal Template (https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitlab/issue_templates/Feature%20proposal%20-%20detailed.md) for additional details to consider adding to this issue. Additionally, as a data oriented organization, when your feature exits planning breakdown, consider adding the `What does success look like, and how can we measure that?` section.
|
||||
-->
|
||||
|
||||
/label ~feature::addition ~"group::" ~"section::" ~"Category:" ~"GitLab Core"/~"GitLab Premium"/~"GitLab Ultimate"
|
||||
/label ~"type::feature" ~feature::addition ~"group::" ~"section::" ~"Category:" ~"GitLab Core"/~"GitLab Premium"/~"GitLab Ultimate"
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
|
||||
|
||||
/label ~"feature" ~"group::" ~"section::" ~"Category::" ~"GitLab Free"/~"GitLab Premium"/~"GitLab Ultimate"
|
||||
/label ~"type::feature" ~"group::" ~"section::" ~"Category::" ~"GitLab Free"/~"GitLab Premium"/~"GitLab Ultimate"
|
||||
|
||||
|
||||
<!--- Use the following resources to find the appropriate labels:
|
||||
|
|
|
@ -112,6 +112,4 @@ Use the following resources to find the appropriate labels:
|
|||
-->
|
||||
/label ~devops:: ~group: ~Category:
|
||||
/label ~"GitLab Free"/~"GitLab Premium"/~"GitLab Ultimate"
|
||||
/label ~feature
|
||||
/label ~documentation
|
||||
/label ~direction
|
||||
/label ~"type::feature" ~documentation ~direction
|
||||
|
|
|
@ -53,4 +53,4 @@ See also:
|
|||
-->
|
||||
|
||||
/label ~"infradev"
|
||||
/label ~"bug"
|
||||
/label ~"type::bug"
|
||||
|
|
|
@ -41,9 +41,9 @@ please list them here.
|
|||
<!--
|
||||
Please select the appropriate label from the following:
|
||||
~"feature::addition"
|
||||
~"feature::maintenance"
|
||||
~"type::maintenance"
|
||||
~"tooling::pipelines"
|
||||
~"tooling::workflow"
|
||||
-->
|
||||
|
||||
/label ~"feature::maintenance"
|
||||
/label ~"type::maintenance"
|
||||
|
|
|
@ -29,5 +29,5 @@
|
|||
|
||||
### Team
|
||||
|
||||
- [ ] Add ~"workflow::planning breakdown" ~feature and the corresponding `~devops::<stage>` and `~group::<group>` labels.
|
||||
- [ ] Add ~"workflow::planning breakdown" ~"type::feature" and the corresponding `~devops::<stage>` and `~group::<group>` labels.
|
||||
- [ ] Ping the PM and EM.
|
||||
|
|
|
@ -20,10 +20,10 @@
|
|||
|
||||
If you are only adding documentation, do not add any of the following labels:
|
||||
|
||||
- `~"feature"`
|
||||
- `~"type::feature"`
|
||||
- `~"frontend"`
|
||||
- `~"backend"`
|
||||
- `~"bug"`
|
||||
- `~"type::bug"`
|
||||
- `~"database"`
|
||||
|
||||
These labels cause the MR to be added to code verification QA issues.
|
||||
|
|
|
@ -24,5 +24,5 @@ Please link to the respective test case in the testcases project
|
|||
|
||||
/label ~"Quality:test-gap" ~"Quality:EE test gaps"
|
||||
|
||||
<!-- Select the appropriate feature label, ~"feature::addition" for tests added for new features, ~"feature::maintenance" for tests added for existing features -->
|
||||
/label ~"feature::addition" ~"feature::maintenance"
|
||||
<!-- Select the appropriate feature label, ~"feature::addition" for tests added for new features, ~"type::maintenance" for tests added for existing features -->
|
||||
/label ~"feature::addition" ~"type::maintenance"
|
||||
|
|
|
@ -35,4 +35,4 @@ This will help keep track of expected cost increases to the [GitLab project aver
|
|||
|
||||
- [ ] Consider communicating these changes to the broader team following the [communication guideline for pipeline changes](https://about.gitlab.com/handbook/engineering/quality/engineering-productivity/#pipeline-changes)
|
||||
|
||||
/label ~tooling ~"tooling::pipelines" ~"Engineering Productivity"
|
||||
/label ~"type::tooling" ~"tooling::pipelines" ~"Engineering Productivity"
|
||||
|
|
|
@ -30,7 +30,7 @@ the noise (due to constantly failing tests, flaky tests, and so on) so that new
|
|||
- [ ] To ensure a faster turnaround, ask in the `#quality` Slack channel for someone to review and merge the merge request, rather than assigning it directly.
|
||||
|
||||
<!-- Base labels. -->
|
||||
/label ~"Quality" ~"QA" ~"feature" ~"feature::maintenance"
|
||||
/label ~"Quality" ~"QA" ~"type::maintenance"
|
||||
|
||||
<!--
|
||||
Choose the stage that appears in the test path, e.g. ~"devops::create" for
|
||||
|
|
|
@ -1 +1 @@
|
|||
ba8bc12dd0ff83fc726c6c09ee0cb0ebc311a748
|
||||
d99f9cbac9164647666f1778eb912568c261813d
|
||||
|
|
|
@ -36,6 +36,7 @@ import {
|
|||
TOKEN_TYPE_LABEL,
|
||||
TOKEN_TYPE_MILESTONE,
|
||||
TOKEN_TYPE_MY_REACTION,
|
||||
TOKEN_TYPE_RELEASE,
|
||||
TOKEN_TYPE_TYPE,
|
||||
TOKEN_TYPE_WEIGHT,
|
||||
UPDATED_DESC,
|
||||
|
@ -65,6 +66,7 @@ import {
|
|||
TOKEN_TITLE_LABEL,
|
||||
TOKEN_TITLE_MILESTONE,
|
||||
TOKEN_TITLE_MY_REACTION,
|
||||
TOKEN_TITLE_RELEASE,
|
||||
TOKEN_TITLE_TYPE,
|
||||
TOKEN_TITLE_WEIGHT,
|
||||
} from '~/vue_shared/components/filtered_search_bar/constants';
|
||||
|
@ -88,6 +90,8 @@ const LabelToken = () =>
|
|||
import('~/vue_shared/components/filtered_search_bar/tokens/label_token.vue');
|
||||
const MilestoneToken = () =>
|
||||
import('~/vue_shared/components/filtered_search_bar/tokens/milestone_token.vue');
|
||||
const ReleaseToken = () =>
|
||||
import('~/vue_shared/components/filtered_search_bar/tokens/release_token.vue');
|
||||
const WeightToken = () =>
|
||||
import('~/vue_shared/components/filtered_search_bar/tokens/weight_token.vue');
|
||||
|
||||
|
@ -165,6 +169,9 @@ export default {
|
|||
newIssuePath: {
|
||||
default: '',
|
||||
},
|
||||
releasesPath: {
|
||||
default: '',
|
||||
},
|
||||
rssPath: {
|
||||
default: '',
|
||||
},
|
||||
|
@ -317,7 +324,6 @@ export default {
|
|||
title: TOKEN_TITLE_MILESTONE,
|
||||
icon: 'clock',
|
||||
token: MilestoneToken,
|
||||
unique: true,
|
||||
fetchMilestones: this.fetchMilestones,
|
||||
},
|
||||
{
|
||||
|
@ -341,6 +347,16 @@ export default {
|
|||
},
|
||||
];
|
||||
|
||||
if (this.isProject) {
|
||||
tokens.push({
|
||||
type: TOKEN_TYPE_RELEASE,
|
||||
title: TOKEN_TITLE_RELEASE,
|
||||
icon: 'rocket',
|
||||
token: ReleaseToken,
|
||||
fetchReleases: this.fetchReleases,
|
||||
});
|
||||
}
|
||||
|
||||
if (this.isSignedIn) {
|
||||
tokens.push({
|
||||
type: TOKEN_TYPE_MY_REACTION,
|
||||
|
@ -371,7 +387,6 @@ export default {
|
|||
title: TOKEN_TITLE_ITERATION,
|
||||
icon: 'iteration',
|
||||
token: IterationToken,
|
||||
unique: true,
|
||||
fetchIterations: this.fetchIterations,
|
||||
});
|
||||
}
|
||||
|
@ -457,6 +472,9 @@ export default {
|
|||
fetchEmojis(search) {
|
||||
return this.fetchWithCache(this.autocompleteAwardEmojisPath, 'emojis', 'name', search);
|
||||
},
|
||||
fetchReleases(search) {
|
||||
return this.fetchWithCache(this.releasesPath, 'releases', 'tag', search);
|
||||
},
|
||||
fetchLabels(search) {
|
||||
return this.$apollo
|
||||
.query({
|
||||
|
|
|
@ -166,6 +166,7 @@ const LABEL_PRIORITY_ASC_SORT = 'label_priority_asc';
|
|||
const POPULARITY_ASC_SORT = 'popularity_asc';
|
||||
const WEIGHT_DESC_SORT = 'weight_desc';
|
||||
const BLOCKING_ISSUES_DESC_SORT = 'blocking_issues_desc';
|
||||
const TITLE_ASC_SORT = 'title_asc';
|
||||
const TITLE_DESC_SORT = 'title_desc';
|
||||
|
||||
export const urlSortParams = {
|
||||
|
@ -187,7 +188,7 @@ export const urlSortParams = {
|
|||
[WEIGHT_ASC]: WEIGHT,
|
||||
[WEIGHT_DESC]: WEIGHT_DESC_SORT,
|
||||
[BLOCKING_ISSUES_DESC]: BLOCKING_ISSUES_DESC_SORT,
|
||||
[TITLE_ASC]: TITLE,
|
||||
[TITLE_ASC]: TITLE_ASC_SORT,
|
||||
[TITLE_DESC]: TITLE_DESC_SORT,
|
||||
};
|
||||
|
||||
|
@ -211,6 +212,7 @@ export const TOKEN_TYPE_ASSIGNEE = 'assignee_username';
|
|||
export const TOKEN_TYPE_MILESTONE = 'milestone';
|
||||
export const TOKEN_TYPE_LABEL = 'labels';
|
||||
export const TOKEN_TYPE_TYPE = 'type';
|
||||
export const TOKEN_TYPE_RELEASE = 'release';
|
||||
export const TOKEN_TYPE_MY_REACTION = 'my_reaction_emoji';
|
||||
export const TOKEN_TYPE_CONFIDENTIAL = 'confidential';
|
||||
export const TOKEN_TYPE_ITERATION = 'iteration';
|
||||
|
@ -291,6 +293,21 @@ export const filters = {
|
|||
},
|
||||
},
|
||||
},
|
||||
[TOKEN_TYPE_RELEASE]: {
|
||||
[API_PARAM]: {
|
||||
[NORMAL_FILTER]: 'releaseTag',
|
||||
[SPECIAL_FILTER]: 'releaseTagWildcardId',
|
||||
},
|
||||
[URL_PARAM]: {
|
||||
[OPERATOR_IS]: {
|
||||
[NORMAL_FILTER]: 'release_tag',
|
||||
[SPECIAL_FILTER]: 'release_tag',
|
||||
},
|
||||
[OPERATOR_IS_NOT]: {
|
||||
[NORMAL_FILTER]: 'not[release_tag]',
|
||||
},
|
||||
},
|
||||
},
|
||||
[TOKEN_TYPE_MY_REACTION]: {
|
||||
[API_PARAM]: {
|
||||
[NORMAL_FILTER]: 'myReactionEmoji',
|
||||
|
|
|
@ -137,6 +137,7 @@ export function mountIssuesListApp() {
|
|||
newIssuePath,
|
||||
projectImportJiraPath,
|
||||
quickActionsHelpPath,
|
||||
releasesPath,
|
||||
resetPath,
|
||||
rssPath,
|
||||
showNewIssueLink,
|
||||
|
@ -164,6 +165,7 @@ export function mountIssuesListApp() {
|
|||
isSignedIn: parseBoolean(isSignedIn),
|
||||
jiraIntegrationPath,
|
||||
newIssuePath,
|
||||
releasesPath,
|
||||
rssPath,
|
||||
showNewIssueLink: parseBoolean(showNewIssueLink),
|
||||
signInPath,
|
||||
|
|
|
@ -16,6 +16,8 @@ query getIssues(
|
|||
$milestoneTitle: [String]
|
||||
$milestoneWildcardId: MilestoneWildcardId
|
||||
$myReactionEmoji: String
|
||||
$releaseTag: [String!]
|
||||
$releaseTagWildcardId: ReleaseTagWildcardId
|
||||
$types: [IssueType!]
|
||||
$not: NegatedIssueFilterInput
|
||||
$beforeCursor: String
|
||||
|
@ -66,6 +68,8 @@ query getIssues(
|
|||
milestoneTitle: $milestoneTitle
|
||||
milestoneWildcardId: $milestoneWildcardId
|
||||
myReactionEmoji: $myReactionEmoji
|
||||
releaseTag: $releaseTag
|
||||
releaseTagWildcardId: $releaseTagWildcardId
|
||||
types: $types
|
||||
not: $not
|
||||
before: $beforeCursor
|
||||
|
|
|
@ -10,6 +10,8 @@ query getIssuesCount(
|
|||
$milestoneTitle: [String]
|
||||
$milestoneWildcardId: MilestoneWildcardId
|
||||
$myReactionEmoji: String
|
||||
$releaseTag: [String!]
|
||||
$releaseTagWildcardId: ReleaseTagWildcardId
|
||||
$types: [IssueType!]
|
||||
$not: NegatedIssueFilterInput
|
||||
) {
|
||||
|
@ -78,6 +80,8 @@ query getIssuesCount(
|
|||
milestoneTitle: $milestoneTitle
|
||||
milestoneWildcardId: $milestoneWildcardId
|
||||
myReactionEmoji: $myReactionEmoji
|
||||
releaseTag: $releaseTag
|
||||
releaseTagWildcardId: $releaseTagWildcardId
|
||||
types: $types
|
||||
not: $not
|
||||
) {
|
||||
|
@ -94,6 +98,8 @@ query getIssuesCount(
|
|||
milestoneTitle: $milestoneTitle
|
||||
milestoneWildcardId: $milestoneWildcardId
|
||||
myReactionEmoji: $myReactionEmoji
|
||||
releaseTag: $releaseTag
|
||||
releaseTagWildcardId: $releaseTagWildcardId
|
||||
types: $types
|
||||
not: $not
|
||||
) {
|
||||
|
@ -110,6 +116,8 @@ query getIssuesCount(
|
|||
milestoneTitle: $milestoneTitle
|
||||
milestoneWildcardId: $milestoneWildcardId
|
||||
myReactionEmoji: $myReactionEmoji
|
||||
releaseTag: $releaseTag
|
||||
releaseTagWildcardId: $releaseTagWildcardId
|
||||
types: $types
|
||||
not: $not
|
||||
) {
|
||||
|
|
|
@ -21,10 +21,13 @@ import {
|
|||
RELATIVE_POSITION_ASC,
|
||||
SPECIAL_FILTER,
|
||||
SPECIAL_FILTER_VALUES,
|
||||
TITLE_ASC,
|
||||
TITLE_DESC,
|
||||
TOKEN_TYPE_ASSIGNEE,
|
||||
TOKEN_TYPE_CONFIDENTIAL,
|
||||
TOKEN_TYPE_ITERATION,
|
||||
TOKEN_TYPE_MILESTONE,
|
||||
TOKEN_TYPE_RELEASE,
|
||||
TOKEN_TYPE_TYPE,
|
||||
UPDATED_ASC,
|
||||
UPDATED_DESC,
|
||||
|
@ -114,11 +117,19 @@ export const getSortOptions = (hasIssueWeightsFeature, hasBlockedIssuesFeature)
|
|||
descending: RELATIVE_POSITION_ASC,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
title: __('Title'),
|
||||
sortDirection: {
|
||||
ascending: TITLE_ASC,
|
||||
descending: TITLE_DESC,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
if (hasIssueWeightsFeature) {
|
||||
sortOptions.push({
|
||||
id: 9,
|
||||
id: sortOptions.length + 1,
|
||||
title: __('Weight'),
|
||||
sortDirection: {
|
||||
ascending: WEIGHT_ASC,
|
||||
|
@ -129,7 +140,7 @@ export const getSortOptions = (hasIssueWeightsFeature, hasBlockedIssuesFeature)
|
|||
|
||||
if (hasBlockedIssuesFeature) {
|
||||
sortOptions.push({
|
||||
id: 10,
|
||||
id: sortOptions.length + 1,
|
||||
title: __('Blocking'),
|
||||
sortDirection: {
|
||||
ascending: BLOCKING_ISSUES_DESC,
|
||||
|
@ -194,9 +205,10 @@ const getFilterType = (data, tokenType = '') =>
|
|||
? SPECIAL_FILTER
|
||||
: NORMAL_FILTER;
|
||||
|
||||
const wildcardTokens = [TOKEN_TYPE_ITERATION, TOKEN_TYPE_MILESTONE, TOKEN_TYPE_RELEASE];
|
||||
|
||||
const isWildcardValue = (tokenType, value) =>
|
||||
(tokenType === TOKEN_TYPE_ITERATION || tokenType === TOKEN_TYPE_MILESTONE) &&
|
||||
SPECIAL_FILTER_VALUES.includes(value);
|
||||
wildcardTokens.includes(tokenType) && SPECIAL_FILTER_VALUES.includes(value);
|
||||
|
||||
const requiresUpperCaseValue = (tokenType, value) =>
|
||||
tokenType === TOKEN_TYPE_TYPE || isWildcardValue(tokenType, value);
|
||||
|
|
|
@ -209,17 +209,25 @@ export default {
|
|||
<status-icon v-if="data.icon" :icon-name="data.icon.name" :size="12" class="gl-pl-0" />
|
||||
<gl-intersection-observer
|
||||
:options="{ rootMargin: '100px', thresholds: 0.1 }"
|
||||
class="gl-flex-wrap gl-align-self-center gl-display-flex"
|
||||
class="gl-flex-wrap gl-display-flex gl-w-full"
|
||||
@appear="appear(index)"
|
||||
@disappear="disappear(index)"
|
||||
>
|
||||
<div v-safe-html="data.text" class="gl-mr-4"></div>
|
||||
<div
|
||||
v-safe-html="data.text"
|
||||
class="gl-mr-4 gl-display-flex gl-align-items-center"
|
||||
></div>
|
||||
<div v-if="data.link">
|
||||
<gl-link :href="data.link.href">{{ data.link.text }}</gl-link>
|
||||
</div>
|
||||
<gl-badge v-if="data.badge" :variant="data.badge.variant || 'info'">
|
||||
{{ data.badge.text }}
|
||||
</gl-badge>
|
||||
<actions
|
||||
:widget="$options.label || $options.name"
|
||||
:tertiary-buttons="data.actions"
|
||||
class="gl-ml-auto"
|
||||
/>
|
||||
</gl-intersection-observer>
|
||||
</li>
|
||||
</smart-virtual-list>
|
||||
|
|
|
@ -67,6 +67,7 @@ export default {
|
|||
// href: 'https://google.com', // Required: href for the link
|
||||
// text: 'Link text', // Required: Text to be used inside the link
|
||||
// },
|
||||
actions: [{ text: 'Full report', href: 'https://gitlab.com', target: '_blank' }],
|
||||
}));
|
||||
});
|
||||
},
|
||||
|
|
|
@ -53,6 +53,7 @@ export const TOKEN_TITLE_ASSIGNEE = __('Assignee');
|
|||
export const TOKEN_TITLE_MILESTONE = __('Milestone');
|
||||
export const TOKEN_TITLE_LABEL = __('Label');
|
||||
export const TOKEN_TITLE_TYPE = __('Type');
|
||||
export const TOKEN_TITLE_RELEASE = __('Release');
|
||||
export const TOKEN_TITLE_MY_REACTION = __('My-Reaction');
|
||||
export const TOKEN_TITLE_CONFIDENTIAL = __('Confidential');
|
||||
export const TOKEN_TITLE_ITERATION = __('Iteration');
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
<script>
|
||||
import { GlFilteredSearchSuggestion } from '@gitlab/ui';
|
||||
import createFlash from '~/flash';
|
||||
import { __ } from '~/locale';
|
||||
import BaseToken from '~/vue_shared/components/filtered_search_bar/tokens/base_token.vue';
|
||||
import { DEFAULT_NONE_ANY } from '../constants';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
BaseToken,
|
||||
GlFilteredSearchSuggestion,
|
||||
},
|
||||
props: {
|
||||
active: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
config: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
value: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
releases: this.config.initialReleases || [],
|
||||
loading: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
defaultReleases() {
|
||||
return this.config.defaultReleases || DEFAULT_NONE_ANY;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
getActiveRelease(releases, data) {
|
||||
return releases.find((release) => release.tag.toLowerCase() === data.toLowerCase());
|
||||
},
|
||||
fetchReleases(searchTerm) {
|
||||
this.loading = true;
|
||||
this.config
|
||||
.fetchReleases(searchTerm)
|
||||
.then((response) => {
|
||||
this.releases = response;
|
||||
})
|
||||
.catch(() => {
|
||||
createFlash({ message: __('There was a problem fetching releases.') });
|
||||
})
|
||||
.finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<base-token
|
||||
:active="active"
|
||||
:config="config"
|
||||
:value="value"
|
||||
:default-suggestions="defaultReleases"
|
||||
:suggestions="releases"
|
||||
:suggestions-loading="loading"
|
||||
:get-active-token-value="getActiveRelease"
|
||||
@fetch-suggestions="fetchReleases"
|
||||
v-on="$listeners"
|
||||
>
|
||||
<template #view="{ viewTokenProps: { inputValue, activeTokenValue } }">
|
||||
{{ activeTokenValue ? activeTokenValue.tag : inputValue }}
|
||||
</template>
|
||||
<template #suggestions-list="{ suggestions }">
|
||||
<gl-filtered-search-suggestion
|
||||
v-for="release in suggestions"
|
||||
:key="release.id"
|
||||
:value="release.tag"
|
||||
>
|
||||
{{ release.tag }}
|
||||
</gl-filtered-search-suggestion>
|
||||
</template>
|
||||
</base-token>
|
||||
</template>
|
|
@ -48,9 +48,7 @@ class Projects::IssuesController < Projects::ApplicationController
|
|||
end
|
||||
|
||||
before_action only: :show do
|
||||
real_time_enabled = Gitlab::ActionCable::Config.in_app? || Feature.enabled?(:real_time_issue_sidebar, @project)
|
||||
|
||||
push_to_gon_attributes(:features, :real_time_issue_sidebar, real_time_enabled)
|
||||
push_frontend_feature_flag(:real_time_issue_sidebar, @project, default_enabled: :yaml)
|
||||
push_frontend_feature_flag(:confidential_notes, @project, default_enabled: :yaml)
|
||||
push_frontend_feature_flag(:issue_assignees_widget, @project, default_enabled: :yaml)
|
||||
push_frontend_feature_flag(:labels_widget, @project, default_enabled: :yaml)
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
class Projects::WikisController < Projects::ApplicationController
|
||||
include WikiActions
|
||||
|
||||
urgency :low
|
||||
|
||||
alias_method :container, :project
|
||||
|
||||
before_action do
|
||||
|
|
|
@ -233,6 +233,7 @@ module IssuesHelper
|
|||
new_issue_path: new_project_issue_path(project, issue: { milestone_id: finder.milestones.first.try(:id) }),
|
||||
project_import_jira_path: project_import_jira_path(project),
|
||||
quick_actions_help_path: help_page_path('user/project/quick_actions'),
|
||||
releases_path: project_releases_path(project, format: :json),
|
||||
reset_path: new_issuable_address_project_path(project, issuable_type: 'issue'),
|
||||
show_new_issue_link: show_new_issue_link?(project).to_s
|
||||
)
|
||||
|
|
|
@ -73,7 +73,12 @@ module Integrations
|
|||
{ type: 'text', name: 'webhook', placeholder: "#{webhook_placeholder}", required: true }.freeze,
|
||||
{ type: 'text', name: 'username', placeholder: 'GitLab-integration' }.freeze,
|
||||
{ type: 'checkbox', name: 'notify_only_broken_pipelines', help: 'Do not send notifications for successful pipelines.' }.freeze,
|
||||
{ type: 'select', name: 'branches_to_be_notified', choices: branch_choices }.freeze,
|
||||
{
|
||||
type: 'select',
|
||||
name: 'branches_to_be_notified',
|
||||
title: s_('Integrations|Branches for which notifications are to be sent'),
|
||||
choices: branch_choices
|
||||
}.freeze,
|
||||
{
|
||||
type: 'text',
|
||||
name: 'labels_to_be_notified',
|
||||
|
|
|
@ -41,7 +41,12 @@ module Integrations
|
|||
[
|
||||
{ type: "text", name: "webhook", placeholder: "https://discordapp.com/api/webhooks/…", help: "URL to the webhook for the Discord channel." },
|
||||
{ type: "checkbox", name: "notify_only_broken_pipelines" },
|
||||
{ type: 'select', name: 'branches_to_be_notified', choices: branch_choices }
|
||||
{
|
||||
type: 'select',
|
||||
name: 'branches_to_be_notified',
|
||||
title: s_('Integrations|Branches for which notifications are to be sent'),
|
||||
choices: branch_choices
|
||||
}
|
||||
]
|
||||
end
|
||||
|
||||
|
|
|
@ -76,7 +76,12 @@ module Integrations
|
|||
help: s_("EmailsOnPushService|Send notifications from the committer's email address if the domain matches the domain used by your GitLab instance (such as %{domains}).") % { domains: domains } },
|
||||
{ type: 'checkbox', name: 'disable_diffs', title: s_("EmailsOnPushService|Disable code diffs"),
|
||||
help: s_("EmailsOnPushService|Don't include possibly sensitive code diffs in notification body.") },
|
||||
{ type: 'select', name: 'branches_to_be_notified', choices: branch_choices },
|
||||
{
|
||||
type: 'select',
|
||||
name: 'branches_to_be_notified',
|
||||
title: s_('Integrations|Branches for which notifications are to be sent'),
|
||||
choices: branch_choices
|
||||
},
|
||||
{
|
||||
type: 'textarea',
|
||||
name: 'recipients',
|
||||
|
|
|
@ -40,7 +40,12 @@ module Integrations
|
|||
[
|
||||
{ type: 'text', name: 'webhook', placeholder: "#{webhook_placeholder}" },
|
||||
{ type: 'checkbox', name: 'notify_only_broken_pipelines' },
|
||||
{ type: 'select', name: 'branches_to_be_notified', choices: branch_choices }
|
||||
{
|
||||
type: 'select',
|
||||
name: 'branches_to_be_notified',
|
||||
title: s_('Integrations|Branches for which notifications are to be sent'),
|
||||
choices: branch_choices
|
||||
}
|
||||
]
|
||||
end
|
||||
|
||||
|
|
|
@ -37,7 +37,12 @@ module Integrations
|
|||
[
|
||||
{ type: 'text', name: 'webhook', placeholder: "#{webhook_placeholder}" },
|
||||
{ type: 'checkbox', name: 'notify_only_broken_pipelines', help: 'If selected, successful pipelines do not trigger a notification event.' },
|
||||
{ type: 'select', name: 'branches_to_be_notified', choices: branch_choices }
|
||||
{
|
||||
type: 'select',
|
||||
name: 'branches_to_be_notified',
|
||||
title: s_('Integrations|Branches for which notifications are to be sent'),
|
||||
choices: branch_choices
|
||||
}
|
||||
]
|
||||
end
|
||||
|
||||
|
|
|
@ -71,6 +71,7 @@ module Integrations
|
|||
name: 'notify_only_broken_pipelines' },
|
||||
{ type: 'select',
|
||||
name: 'branches_to_be_notified',
|
||||
title: s_('Integrations|Branches for which notifications are to be sent'),
|
||||
choices: branch_choices }
|
||||
]
|
||||
end
|
||||
|
|
|
@ -34,7 +34,12 @@ module Integrations
|
|||
[
|
||||
{ type: 'text', name: 'webhook', placeholder: "https://yourcircuit.com/rest/v2/webhooks/incoming/…", required: true },
|
||||
{ type: 'checkbox', name: 'notify_only_broken_pipelines' },
|
||||
{ type: 'select', name: 'branches_to_be_notified', choices: branch_choices }
|
||||
{
|
||||
type: 'select',
|
||||
name: 'branches_to_be_notified',
|
||||
title: s_('Integrations|Branches for which notifications are to be sent'),
|
||||
choices: branch_choices
|
||||
}
|
||||
]
|
||||
end
|
||||
|
||||
|
|
|
@ -36,7 +36,12 @@ module Integrations
|
|||
[
|
||||
{ type: 'text', name: 'webhook', placeholder: "https://api.ciscospark.com/v1/webhooks/incoming/...", required: true },
|
||||
{ type: 'checkbox', name: 'notify_only_broken_pipelines' },
|
||||
{ type: 'select', name: 'branches_to_be_notified', choices: branch_choices }
|
||||
{
|
||||
type: 'select',
|
||||
name: 'branches_to_be_notified',
|
||||
title: s_('Integrations|Branches for which notifications are to be sent'),
|
||||
choices: branch_choices
|
||||
}
|
||||
]
|
||||
end
|
||||
|
||||
|
|
|
@ -80,7 +80,7 @@ module Issues
|
|||
todo_service.reassigned_assignable(issue, current_user, old_assignees)
|
||||
track_incident_action(current_user, issue, :incident_assigned)
|
||||
|
||||
if Gitlab::ActionCable::Config.in_app? || Feature.enabled?(:broadcast_issue_updates, issue.project)
|
||||
if Feature.enabled?(:broadcast_issue_updates, issue.project, default_enabled: :yaml)
|
||||
GraphqlTriggers.issuable_assignees_updated(issue)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -59,8 +59,4 @@ Rails.application.configure do
|
|||
config.logger = ActiveSupport::TaggedLogging.new(Logger.new(nil))
|
||||
config.log_level = :fatal
|
||||
end
|
||||
|
||||
# Mount the ActionCable Engine in-app so that we don't have to spawn another Puma
|
||||
# process for feature specs
|
||||
ENV['ACTION_CABLE_IN_APP'] = 'true'
|
||||
end
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
name: broadcast_issue_updates
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/30732
|
||||
rollout_issue_url: https://gitlab.com/gitlab-com/gl-infra/delivery/-/issues/1210
|
||||
rollout_issue_url: https://gitlab.com/gitlab-com/gl-infra/production/-/issues/3413
|
||||
milestone: '13.0'
|
||||
type: development
|
||||
group: group::project management
|
||||
default_enabled: false
|
||||
default_enabled: true
|
||||
|
|
|
@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-com/gl-infra/delivery/-/issues/1210
|
|||
milestone: '13.0'
|
||||
type: development
|
||||
group: group::project management
|
||||
default_enabled: false
|
||||
default_enabled: true
|
||||
|
|
|
@ -65,7 +65,7 @@ if !Rails.env.test? && Gitlab::Metrics.prometheus_metrics_enabled?
|
|||
Gitlab::Metrics::Samplers::DatabaseSampler.initialize_instance.start
|
||||
Gitlab::Metrics::Samplers::ThreadsSampler.initialize_instance.start
|
||||
|
||||
if Gitlab::Runtime.action_cable?
|
||||
if Gitlab::Runtime.web_server?
|
||||
Gitlab::Metrics::Samplers::ActionCableSampler.instance.start
|
||||
end
|
||||
|
||||
|
|
|
@ -3,8 +3,7 @@
|
|||
require 'action_cable/subscription_adapter/redis'
|
||||
|
||||
Rails.application.configure do
|
||||
# Mount the ActionCable engine when in-app mode is enabled
|
||||
config.action_cable.mount_path = Gitlab::ActionCable::Config.in_app? ? '/-/cable' : nil
|
||||
config.action_cable.mount_path = '/-/cable'
|
||||
|
||||
config.action_cable.url = Gitlab::Utils.append_path(Gitlab.config.gitlab.relative_url_root, '/-/cable')
|
||||
config.action_cable.worker_pool_size = Gitlab::ActionCable::Config.worker_pool_size
|
||||
|
|
|
@ -4,24 +4,21 @@
|
|||
|
||||
DEFAULT_BRANCH = 'master'
|
||||
|
||||
THROUGHPUT_LABELS = [
|
||||
'Community contribution',
|
||||
'security',
|
||||
'bug',
|
||||
'feature',
|
||||
TYPE_LABELS = [
|
||||
'type::feature',
|
||||
'feature::addition',
|
||||
'feature::maintenance',
|
||||
'tooling',
|
||||
'type::maintenance',
|
||||
'type::tooling',
|
||||
'tooling::pipelines',
|
||||
'tooling::workflow',
|
||||
'documentation'
|
||||
'type::bug'
|
||||
].freeze
|
||||
|
||||
if gitlab.mr_body.size < 5
|
||||
fail "Please provide a proper merge request description."
|
||||
end
|
||||
|
||||
if (THROUGHPUT_LABELS & gitlab.mr_labels).empty?
|
||||
if (TYPE_LABELS & gitlab.mr_labels).empty?
|
||||
warn 'Please add a [merge request type](https://about.gitlab.com/handbook/engineering/metrics/#work-type-classification) to this merge request.'
|
||||
end
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ SPECIALIZATIONS = {
|
|||
frontend: 'frontend',
|
||||
docs: 'documentation',
|
||||
qa: 'QA',
|
||||
tooling: 'tooling',
|
||||
tooling: 'type::tooling',
|
||||
ci_template: 'ci::templates',
|
||||
feature_flag: 'feature flag'
|
||||
}.freeze
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
NO_SPECS_LABELS = [
|
||||
'tooling',
|
||||
'type::tooling',
|
||||
'tooling::pipelines',
|
||||
'tooling::workflow',
|
||||
'documentation',
|
||||
|
|
|
@ -29,7 +29,7 @@ The extensive usage of feature flags poses a few challenges
|
|||
We sometimes forget how our feature flags are configured or why we haven't
|
||||
yet removed the feature flag.
|
||||
- The usage of feature flags can also be confusing to people outside of
|
||||
development that might not fully understand dependence of ~feature or ~bug
|
||||
development that might not fully understand dependence of ~"type::feature" or ~"type::bug"
|
||||
fix on feature flag and how this feature flag is configured. Or if the feature
|
||||
should be announced as part of release post.
|
||||
- Maintaining feature flags poses additional challenge of having to manage
|
||||
|
|
|
@ -78,7 +78,7 @@ duration is capped at 5 seconds.
|
|||
|
||||
## Decreasing the urgency (setting a higher target duration)
|
||||
|
||||
Increasing the urgency on an existing endpoint can be done on
|
||||
Decreasing the urgency on an existing endpoint can be done on
|
||||
a case-by-case basis. Please take the following into account:
|
||||
|
||||
1. Apdex is about perceived performance, if a user is actively waiting
|
||||
|
@ -137,7 +137,7 @@ the decision.
|
|||
|
||||
## Increasing urgency (setting a lower target duration)
|
||||
|
||||
When decreasing the target duration, we need to make sure the endpoint
|
||||
When increasing the urgency, we need to make sure the endpoint
|
||||
still meets SLO for the fleet that handles the request. You can use the
|
||||
information in the logs to determine this:
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@ scheduling into milestones. Labeling is a task for everyone. (For some projects,
|
|||
|
||||
Most issues will have labels for at least one of the following:
|
||||
|
||||
- Type. For example: `~feature`, `~bug`, `~tooling`, or `~documentation`.
|
||||
- Type. For example: `~"type::feature"`, `~"type::bug"`, or `~"type::tooling"`.
|
||||
- Stage. For example: `~"devops::plan"` or `~"devops::create"`.
|
||||
- Group. For example: `~"group::source code"`, `~"group::knowledge"`, or `~"group::editor"`.
|
||||
- Category. For example: `~"Category:Code Analytics"`, `~"Category:DevOps Reports"`, or `~"Category:Templates"`.
|
||||
|
@ -70,12 +70,12 @@ issue should have one and only one.
|
|||
|
||||
The current type labels are:
|
||||
|
||||
- `~feature`
|
||||
- `~"type::feature"`
|
||||
- `~"feature::addition"`
|
||||
- `~"feature::enhancement"`
|
||||
- `~"feature::maintenance"`
|
||||
- `~bug`
|
||||
- `~tooling`
|
||||
- `~"type::maintenance"`
|
||||
- `~"type::bug"`
|
||||
- `~"type::tooling"`
|
||||
- `~"tooling::pipelines"`
|
||||
- `~"tooling::workflow"`
|
||||
- `~"support request"`
|
||||
|
@ -342,11 +342,11 @@ To create a feature proposal, open an issue on the
|
|||
[issue tracker](https://gitlab.com/gitlab-org/gitlab/-/issues).
|
||||
|
||||
In order to help track the feature proposals, we have created a
|
||||
[`feature`](https://gitlab.com/gitlab-org/gitlab/-/issues?label_name=feature) label.
|
||||
[`~"type::feature"`](https://gitlab.com/gitlab-org/gitlab/-/issues?label_name=type::feature) label.
|
||||
For the time being, users that are not members of the project cannot add labels.
|
||||
You can instead ask one of the [core team](https://about.gitlab.com/community/core-team/)
|
||||
members to add the label `~feature` to the issue or add the following
|
||||
code snippet right after your description in a new line: `~feature`.
|
||||
members to add the label `~"type::feature"` to the issue or add the following
|
||||
code snippet right after your description in a new line: `~"type::feature"`.
|
||||
|
||||
Please keep feature proposals as small and simple as possible, complex ones
|
||||
might be edited to make them small and simple.
|
||||
|
|
|
@ -39,7 +39,7 @@ The following are also added by members of the Technical Writing team:
|
|||
- The `~Technical Writing` [team label](../contributing/issue_workflow.md#team-labels).
|
||||
|
||||
Documentation changes that are not associated with the release of a new or updated feature
|
||||
do not take the `~feature` label, but still need the `~documentation` label.
|
||||
do not take the `~"type::feature"` label, but still need the `~documentation` label.
|
||||
|
||||
They may include:
|
||||
|
||||
|
|
|
@ -180,7 +180,7 @@ subgraph "CNG-mirror pipeline"
|
|||
**Additional notes:**
|
||||
|
||||
- If the `review-deploy` job keeps failing (and a manual retry didn't help),
|
||||
please post a message in the `#g_qe_engineering_productivity` channel and/or create a `~"Engineering Productivity"` `~"ep::review apps"` `~bug`
|
||||
please post a message in the `#g_qe_engineering_productivity` channel and/or create a `~"Engineering Productivity"` `~"ep::review apps"` `~"type::bug"`
|
||||
issue with a link to your merge request. Note that the deployment failure can
|
||||
reveal an actual problem introduced in your merge request (i.e. this isn't
|
||||
necessarily a transient failure)!
|
||||
|
@ -189,7 +189,7 @@ subgraph "CNG-mirror pipeline"
|
|||
your merge request. You can also download the artifacts to see screenshots of
|
||||
the page at the time the failures occurred. If you don't find the cause of the
|
||||
failure or if it seems unrelated to your change, please post a message in the
|
||||
`#quality` channel and/or create a ~Quality ~bug issue with a link to your
|
||||
`#quality` channel and/or create a ~Quality ~"type::bug" issue with a link to your
|
||||
merge request.
|
||||
- The manual `review-stop` can be used to
|
||||
stop a Review App manually, and is also started by GitLab once a merge
|
||||
|
|
|
@ -54,7 +54,7 @@ Then fill in the integration configuration:
|
|||
To change the bot's username, provide a value.
|
||||
- **Notify only broken pipelines**: If you enable the **Pipeline** event, and you want
|
||||
notifications about failed pipelines only.
|
||||
- **Branches to be notified**: The branches to send notifications for.
|
||||
- **Branches for which notifications are to be sent**: The branches to send notifications for.
|
||||
- **Labels to be notified**: (Optional) Labels required for the issue or merge request
|
||||
to trigger a notification. Leave blank to notify for all issues and merge requests.
|
||||
- **Labels to be notified behavior**: When you use the **Labels to be notified** filter,
|
||||
|
|
|
@ -45,7 +45,7 @@ to control GitLab from Slack. Slash commands are configured separately.
|
|||
1. (Optional) In **Username**, enter the username of the Slack bot that sends
|
||||
the notifications.
|
||||
1. Select the **Notify only broken pipelines** checkbox to notify only on failures.
|
||||
1. In the **Branches to be notified** dropdown, select which types of branches
|
||||
1. In the **Branches for which notifications are to be sent** dropdown, select which types of branches
|
||||
to send notifications for.
|
||||
1. Leave the **Labels to be notified** field blank to get all notifications, or
|
||||
add labels that the issue or merge request must have to trigger a
|
||||
|
|
|
@ -21,7 +21,7 @@ In GitLab:
|
|||
1. Select the checkboxes corresponding to the GitLab events you want to receive in Unify Circuit.
|
||||
1. Paste the **Webhook URL** that you copied from the Unify Circuit configuration step.
|
||||
1. Select the **Notify only broken pipelines** checkbox to notify only on failures.
|
||||
1. In the **Branches to be notified** dropdown, select which types of branches to send notifications for.
|
||||
1. In the **Branches for which notifications are to be sent** dropdown, select which types of branches to send notifications for.
|
||||
1. Select `Save changes` or optionally select **Test settings**.
|
||||
|
||||
Your Unify Circuit conversation now starts receiving GitLab event notifications.
|
||||
|
|
|
@ -380,12 +380,18 @@ You can also use the `/iteration`
|
|||
[quick action](../quick_actions.md#issues-merge-requests-and-epics)
|
||||
in a comment or description field.
|
||||
|
||||
## Real-time sidebar **(FREE SELF)**
|
||||
## Real-time sidebar
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/17589) in GitLab 13.3.
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/17589) in GitLab 13.3. Disabled by default.
|
||||
> - [Enabled on GitLab.com](https://gitlab.com/gitlab-com/gl-infra/production/-/issues/3413) in GitLab 13.9.
|
||||
> - [Enabled on self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/17589) in GitLab 14.5.
|
||||
|
||||
Assignees in the sidebar are updated in real time. This feature is **disabled by default**.
|
||||
To enable it, you need to enable [Action Cable in-app mode](https://docs.gitlab.com/omnibus/settings/actioncable.html).
|
||||
FLAG:
|
||||
On self-managed GitLab, by default this feature is available. To hide the feature per project or for your entire instance, ask an administrator to
|
||||
[disable the feature flags](../../../administration/feature_flags.md) named `real_time_issue_sidebar` and `broadcast_issue_updates`.
|
||||
On GitLab.com, this feature is available.
|
||||
|
||||
Assignees in the sidebar are updated in real time.
|
||||
|
||||
## Similar issues
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ module API
|
|||
params do
|
||||
use :pagination
|
||||
end
|
||||
get 'public' do
|
||||
get 'public', urgency: :low do
|
||||
authenticate!
|
||||
|
||||
present paginate(public_snippets), with: Entities::PersonalSnippet, current_user: current_user
|
||||
|
|
|
@ -32,7 +32,7 @@ module API
|
|||
params do
|
||||
optional :with_content, type: Boolean, default: false, desc: "Include pages' content"
|
||||
end
|
||||
get ':id/wikis' do
|
||||
get ':id/wikis', urgency: :low do
|
||||
authorize! :read_wiki, container
|
||||
|
||||
entity = params[:with_content] ? Entities::WikiPage : Entities::WikiPageBasic
|
||||
|
|
|
@ -4,10 +4,6 @@ module Gitlab
|
|||
module ActionCable
|
||||
class Config
|
||||
class << self
|
||||
def in_app?
|
||||
Gitlab::Utils.to_boolean(ENV.fetch('ACTION_CABLE_IN_APP', false))
|
||||
end
|
||||
|
||||
def worker_pool_size
|
||||
ENV.fetch('ACTION_CABLE_WORKER_POOL_SIZE', 4).to_i
|
||||
end
|
||||
|
|
|
@ -39,23 +39,14 @@ module Gitlab
|
|||
|
||||
def sample
|
||||
pool = @action_cable.worker_pool.executor
|
||||
labels = {
|
||||
server_mode: server_mode
|
||||
}
|
||||
|
||||
metrics[:active_connections].set(labels, @action_cable.connections.size)
|
||||
metrics[:pool_min_size].set(labels, pool.min_length)
|
||||
metrics[:pool_max_size].set(labels, pool.max_length)
|
||||
metrics[:pool_current_size].set(labels, pool.length)
|
||||
metrics[:pool_largest_size].set(labels, pool.largest_length)
|
||||
metrics[:pool_completed_tasks].set(labels, pool.completed_task_count)
|
||||
metrics[:pool_pending_tasks].set(labels, pool.queue_length)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def server_mode
|
||||
Gitlab::ActionCable::Config.in_app? ? 'in-app' : 'standalone'
|
||||
metrics[:active_connections].set({}, @action_cable.connections.size)
|
||||
metrics[:pool_min_size].set({}, pool.min_length)
|
||||
metrics[:pool_max_size].set({}, pool.max_length)
|
||||
metrics[:pool_current_size].set({}, pool.length)
|
||||
metrics[:pool_largest_size].set({}, pool.largest_length)
|
||||
metrics[:pool_completed_tasks].set({}, pool.completed_task_count)
|
||||
metrics[:pool_pending_tasks].set({}, pool.queue_length)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -63,12 +63,8 @@ module Gitlab
|
|||
puma?
|
||||
end
|
||||
|
||||
def action_cable?
|
||||
web_server? && (!!defined?(ACTION_CABLE_SERVER) || Gitlab::ActionCable::Config.in_app?)
|
||||
end
|
||||
|
||||
def multi_threaded?
|
||||
puma? || sidekiq? || action_cable?
|
||||
puma? || sidekiq?
|
||||
end
|
||||
|
||||
def puma_in_clustered_mode?
|
||||
|
@ -92,7 +88,7 @@ module Gitlab
|
|||
threads += Sidekiq.options[:concurrency] + 2
|
||||
end
|
||||
|
||||
if action_cable?
|
||||
if web_server?
|
||||
threads += Gitlab::ActionCable::Config.worker_pool_size
|
||||
end
|
||||
|
||||
|
|
|
@ -18350,6 +18350,9 @@ msgstr ""
|
|||
msgid "Integrations|An error occurred while loading projects using custom settings."
|
||||
msgstr ""
|
||||
|
||||
msgid "Integrations|Branches for which notifications are to be sent"
|
||||
msgstr ""
|
||||
|
||||
msgid "Integrations|Browser limitations"
|
||||
msgstr ""
|
||||
|
||||
|
@ -34507,6 +34510,9 @@ msgstr ""
|
|||
msgid "There was a problem fetching recent projects."
|
||||
msgstr ""
|
||||
|
||||
msgid "There was a problem fetching releases."
|
||||
msgstr ""
|
||||
|
||||
msgid "There was a problem fetching the job token scope value"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -1084,28 +1084,30 @@ RSpec.describe Projects::IssuesController do
|
|||
end
|
||||
|
||||
context 'real-time sidebar feature flag' do
|
||||
using RSpec::Parameterized::TableSyntax
|
||||
|
||||
let_it_be(:project) { create(:project, :public) }
|
||||
let_it_be(:issue) { create(:issue, project: project) }
|
||||
|
||||
where(:action_cable_in_app_enabled, :feature_flag_enabled, :gon_feature_flag) do
|
||||
true | true | true
|
||||
true | false | true
|
||||
false | true | true
|
||||
false | false | false
|
||||
end
|
||||
|
||||
with_them do
|
||||
context 'when enabled' do
|
||||
before do
|
||||
expect(Gitlab::ActionCable::Config).to receive(:in_app?).and_return(action_cable_in_app_enabled)
|
||||
stub_feature_flags(real_time_issue_sidebar: feature_flag_enabled)
|
||||
stub_feature_flags(real_time_issue_sidebar: true)
|
||||
end
|
||||
|
||||
it 'broadcasts to the issues channel based on ActionCable and feature flag values' do
|
||||
it 'pushes the correct value to the frontend' do
|
||||
go(id: issue.to_param)
|
||||
|
||||
expect(Gon.features).to include('realTimeIssueSidebar' => gon_feature_flag)
|
||||
expect(Gon.features).to include('realTimeIssueSidebar' => true)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when disabled' do
|
||||
before do
|
||||
stub_feature_flags(real_time_issue_sidebar: false)
|
||||
end
|
||||
|
||||
it 'pushes the correct value to the frontend' do
|
||||
go(id: issue.to_param)
|
||||
|
||||
expect(Gon.features).to include('realTimeIssueSidebar' => false)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -37,6 +37,7 @@ import {
|
|||
TOKEN_TYPE_LABEL,
|
||||
TOKEN_TYPE_MILESTONE,
|
||||
TOKEN_TYPE_MY_REACTION,
|
||||
TOKEN_TYPE_RELEASE,
|
||||
TOKEN_TYPE_TYPE,
|
||||
TOKEN_TYPE_WEIGHT,
|
||||
urlSortParams,
|
||||
|
@ -581,6 +582,7 @@ describe('IssuesListApp component', () => {
|
|||
{ type: TOKEN_TYPE_MILESTONE },
|
||||
{ type: TOKEN_TYPE_LABEL },
|
||||
{ type: TOKEN_TYPE_TYPE },
|
||||
{ type: TOKEN_TYPE_RELEASE },
|
||||
{ type: TOKEN_TYPE_MY_REACTION },
|
||||
{ type: TOKEN_TYPE_CONFIDENTIAL },
|
||||
{ type: TOKEN_TYPE_ITERATION },
|
||||
|
|
|
@ -95,12 +95,18 @@ export const locationSearch = [
|
|||
'assignee_username[]=lisa',
|
||||
'not[assignee_username][]=patty',
|
||||
'not[assignee_username][]=selma',
|
||||
'milestone_title=season+3',
|
||||
'milestone_title=season+4',
|
||||
'not[milestone_title]=season+20',
|
||||
'not[milestone_title]=season+30',
|
||||
'label_name[]=cartoon',
|
||||
'label_name[]=tv',
|
||||
'not[label_name][]=live action',
|
||||
'not[label_name][]=drama',
|
||||
'release_tag=v3',
|
||||
'release_tag=v4',
|
||||
'not[release_tag]=v20',
|
||||
'not[release_tag]=v30',
|
||||
'type[]=issue',
|
||||
'type[]=feature',
|
||||
'not[type][]=bug',
|
||||
|
@ -109,7 +115,9 @@ export const locationSearch = [
|
|||
'not[my_reaction_emoji]=thumbsdown',
|
||||
'confidential=yes',
|
||||
'iteration_id=4',
|
||||
'iteration_id=12',
|
||||
'not[iteration_id]=20',
|
||||
'not[iteration_id]=42',
|
||||
'epic_id=12',
|
||||
'not[epic_id]=34',
|
||||
'weight=1',
|
||||
|
@ -122,6 +130,7 @@ export const locationSearchWithSpecialValues = [
|
|||
'my_reaction_emoji=None',
|
||||
'iteration_id=Current',
|
||||
'label_name[]=None',
|
||||
'release_tag=None',
|
||||
'milestone_title=Upcoming',
|
||||
'epic_id=None',
|
||||
'weight=None',
|
||||
|
@ -134,12 +143,18 @@ export const filteredTokens = [
|
|||
{ type: 'assignee_username', value: { data: 'lisa', operator: OPERATOR_IS } },
|
||||
{ type: 'assignee_username', value: { data: 'patty', operator: OPERATOR_IS_NOT } },
|
||||
{ type: 'assignee_username', value: { data: 'selma', operator: OPERATOR_IS_NOT } },
|
||||
{ type: 'milestone', value: { data: 'season 3', operator: OPERATOR_IS } },
|
||||
{ type: 'milestone', value: { data: 'season 4', operator: OPERATOR_IS } },
|
||||
{ type: 'milestone', value: { data: 'season 20', operator: OPERATOR_IS_NOT } },
|
||||
{ type: 'milestone', value: { data: 'season 30', operator: OPERATOR_IS_NOT } },
|
||||
{ type: 'labels', value: { data: 'cartoon', operator: OPERATOR_IS } },
|
||||
{ type: 'labels', value: { data: 'tv', operator: OPERATOR_IS } },
|
||||
{ type: 'labels', value: { data: 'live action', operator: OPERATOR_IS_NOT } },
|
||||
{ type: 'labels', value: { data: 'drama', operator: OPERATOR_IS_NOT } },
|
||||
{ type: 'release', value: { data: 'v3', operator: OPERATOR_IS } },
|
||||
{ type: 'release', value: { data: 'v4', operator: OPERATOR_IS } },
|
||||
{ type: 'release', value: { data: 'v20', operator: OPERATOR_IS_NOT } },
|
||||
{ type: 'release', value: { data: 'v30', operator: OPERATOR_IS_NOT } },
|
||||
{ type: 'type', value: { data: 'issue', operator: OPERATOR_IS } },
|
||||
{ type: 'type', value: { data: 'feature', operator: OPERATOR_IS } },
|
||||
{ type: 'type', value: { data: 'bug', operator: OPERATOR_IS_NOT } },
|
||||
|
@ -148,7 +163,9 @@ export const filteredTokens = [
|
|||
{ type: 'my_reaction_emoji', value: { data: 'thumbsdown', operator: OPERATOR_IS_NOT } },
|
||||
{ type: 'confidential', value: { data: 'yes', operator: OPERATOR_IS } },
|
||||
{ type: 'iteration', value: { data: '4', operator: OPERATOR_IS } },
|
||||
{ type: 'iteration', value: { data: '12', operator: OPERATOR_IS } },
|
||||
{ type: 'iteration', value: { data: '20', operator: OPERATOR_IS_NOT } },
|
||||
{ type: 'iteration', value: { data: '42', operator: OPERATOR_IS_NOT } },
|
||||
{ type: 'epic_id', value: { data: '12', operator: OPERATOR_IS } },
|
||||
{ type: 'epic_id', value: { data: '34', operator: OPERATOR_IS_NOT } },
|
||||
{ type: 'weight', value: { data: '1', operator: OPERATOR_IS } },
|
||||
|
@ -163,6 +180,7 @@ export const filteredTokensWithSpecialValues = [
|
|||
{ type: 'my_reaction_emoji', value: { data: 'None', operator: OPERATOR_IS } },
|
||||
{ type: 'iteration', value: { data: 'Current', operator: OPERATOR_IS } },
|
||||
{ type: 'labels', value: { data: 'None', operator: OPERATOR_IS } },
|
||||
{ type: 'release', value: { data: 'None', operator: OPERATOR_IS } },
|
||||
{ type: 'milestone', value: { data: 'Upcoming', operator: OPERATOR_IS } },
|
||||
{ type: 'epic_id', value: { data: 'None', operator: OPERATOR_IS } },
|
||||
{ type: 'weight', value: { data: 'None', operator: OPERATOR_IS } },
|
||||
|
@ -171,22 +189,24 @@ export const filteredTokensWithSpecialValues = [
|
|||
export const apiParams = {
|
||||
authorUsername: 'homer',
|
||||
assigneeUsernames: ['bart', 'lisa'],
|
||||
milestoneTitle: 'season 4',
|
||||
milestoneTitle: ['season 3', 'season 4'],
|
||||
labelName: ['cartoon', 'tv'],
|
||||
releaseTag: ['v3', 'v4'],
|
||||
types: ['ISSUE', 'FEATURE'],
|
||||
myReactionEmoji: 'thumbsup',
|
||||
confidential: true,
|
||||
iterationId: '4',
|
||||
iterationId: ['4', '12'],
|
||||
epicId: '12',
|
||||
weight: '1',
|
||||
not: {
|
||||
authorUsername: 'marge',
|
||||
assigneeUsernames: ['patty', 'selma'],
|
||||
milestoneTitle: 'season 20',
|
||||
milestoneTitle: ['season 20', 'season 30'],
|
||||
labelName: ['live action', 'drama'],
|
||||
releaseTag: ['v20', 'v30'],
|
||||
types: ['BUG', 'INCIDENT'],
|
||||
myReactionEmoji: 'thumbsdown',
|
||||
iterationId: '20',
|
||||
iterationId: ['20', '42'],
|
||||
epicId: '34',
|
||||
weight: '3',
|
||||
},
|
||||
|
@ -197,6 +217,7 @@ export const apiParamsWithSpecialValues = {
|
|||
assigneeUsernames: 'bart',
|
||||
labelName: 'None',
|
||||
myReactionEmoji: 'None',
|
||||
releaseTagWildcardId: 'NONE',
|
||||
iterationWildcardId: 'CURRENT',
|
||||
milestoneWildcardId: 'UPCOMING',
|
||||
epicId: 'None',
|
||||
|
@ -208,17 +229,19 @@ export const urlParams = {
|
|||
'not[author_username]': 'marge',
|
||||
'assignee_username[]': ['bart', 'lisa'],
|
||||
'not[assignee_username][]': ['patty', 'selma'],
|
||||
milestone_title: 'season 4',
|
||||
'not[milestone_title]': 'season 20',
|
||||
milestone_title: ['season 3', 'season 4'],
|
||||
'not[milestone_title]': ['season 20', 'season 30'],
|
||||
'label_name[]': ['cartoon', 'tv'],
|
||||
'not[label_name][]': ['live action', 'drama'],
|
||||
release_tag: ['v3', 'v4'],
|
||||
'not[release_tag]': ['v20', 'v30'],
|
||||
'type[]': ['issue', 'feature'],
|
||||
'not[type][]': ['bug', 'incident'],
|
||||
my_reaction_emoji: 'thumbsup',
|
||||
'not[my_reaction_emoji]': 'thumbsdown',
|
||||
confidential: 'yes',
|
||||
iteration_id: '4',
|
||||
'not[iteration_id]': '20',
|
||||
iteration_id: ['4', '12'],
|
||||
'not[iteration_id]': ['20', '42'],
|
||||
epic_id: '12',
|
||||
'not[epic_id]': '34',
|
||||
weight: '1',
|
||||
|
@ -229,6 +252,7 @@ export const urlParamsWithSpecialValues = {
|
|||
assignee_id: '123',
|
||||
'assignee_username[]': 'bart',
|
||||
'label_name[]': 'None',
|
||||
release_tag: 'None',
|
||||
my_reaction_emoji: 'None',
|
||||
iteration_id: 'Current',
|
||||
milestone_title: 'Upcoming',
|
||||
|
|
|
@ -58,10 +58,10 @@ describe('getDueDateValue', () => {
|
|||
describe('getSortOptions', () => {
|
||||
describe.each`
|
||||
hasIssueWeightsFeature | hasBlockedIssuesFeature | length | containsWeight | containsBlocking
|
||||
${false} | ${false} | ${8} | ${false} | ${false}
|
||||
${true} | ${false} | ${9} | ${true} | ${false}
|
||||
${false} | ${true} | ${9} | ${false} | ${true}
|
||||
${true} | ${true} | ${10} | ${true} | ${true}
|
||||
${false} | ${false} | ${9} | ${false} | ${false}
|
||||
${true} | ${false} | ${10} | ${true} | ${false}
|
||||
${false} | ${true} | ${10} | ${false} | ${true}
|
||||
${true} | ${true} | ${11} | ${true} | ${true}
|
||||
`(
|
||||
'when hasIssueWeightsFeature=$hasIssueWeightsFeature and hasBlockedIssuesFeature=$hasBlockedIssuesFeature',
|
||||
({
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { GlBadge, GlLink, GlIcon, GlDropdown } from '@gitlab/ui';
|
||||
import { GlBadge, GlLink, GlIcon, GlButton, GlDropdown } from '@gitlab/ui';
|
||||
import { mount } from '@vue/test-utils';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import Vue, { nextTick } from 'vue';
|
||||
|
@ -947,6 +947,9 @@ describe('MrWidgetOptions', () => {
|
|||
// Renders a link in the row
|
||||
expect(collapsedSection.find(GlLink).exists()).toBe(true);
|
||||
expect(collapsedSection.find(GlLink).text()).toBe('GitLab.com');
|
||||
|
||||
expect(collapsedSection.find(GlButton).exists()).toBe(true);
|
||||
expect(collapsedSection.find(GlButton).text()).toBe('Full report');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -31,6 +31,7 @@ export default {
|
|||
href: 'https://gitlab.com',
|
||||
text: 'GitLab.com',
|
||||
},
|
||||
actions: [{ text: 'Full report', href: 'https://gitlab.com', target: '_blank' }],
|
||||
},
|
||||
]);
|
||||
},
|
||||
|
|
|
@ -9,6 +9,7 @@ import EpicToken from '~/vue_shared/components/filtered_search_bar/tokens/epic_t
|
|||
import IterationToken from '~/vue_shared/components/filtered_search_bar/tokens/iteration_token.vue';
|
||||
import LabelToken from '~/vue_shared/components/filtered_search_bar/tokens/label_token.vue';
|
||||
import MilestoneToken from '~/vue_shared/components/filtered_search_bar/tokens/milestone_token.vue';
|
||||
import ReleaseToken from '~/vue_shared/components/filtered_search_bar/tokens/release_token.vue';
|
||||
import WeightToken from '~/vue_shared/components/filtered_search_bar/tokens/weight_token.vue';
|
||||
|
||||
export const mockAuthor1 = {
|
||||
|
@ -132,6 +133,14 @@ export const mockMilestoneToken = {
|
|||
fetchMilestones: () => Promise.resolve({ data: mockMilestones }),
|
||||
};
|
||||
|
||||
export const mockReleaseToken = {
|
||||
type: 'release',
|
||||
icon: 'rocket',
|
||||
title: 'Release',
|
||||
token: ReleaseToken,
|
||||
fetchReleases: () => Promise.resolve(),
|
||||
};
|
||||
|
||||
export const mockEpicToken = {
|
||||
type: 'epic_iid',
|
||||
icon: 'clock',
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
import { GlFilteredSearchToken, GlFilteredSearchTokenSegment } from '@gitlab/ui';
|
||||
import { mount } from '@vue/test-utils';
|
||||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
import createFlash from '~/flash';
|
||||
import ReleaseToken from '~/vue_shared/components/filtered_search_bar/tokens/release_token.vue';
|
||||
import { mockReleaseToken } from '../mock_data';
|
||||
|
||||
jest.mock('~/flash');
|
||||
|
||||
describe('ReleaseToken', () => {
|
||||
const id = 123;
|
||||
let wrapper;
|
||||
|
||||
const createComponent = ({ config = mockReleaseToken, value = { data: '' } } = {}) =>
|
||||
mount(ReleaseToken, {
|
||||
propsData: {
|
||||
active: false,
|
||||
config,
|
||||
value,
|
||||
},
|
||||
provide: {
|
||||
portalName: 'fake target',
|
||||
alignSuggestions: function fakeAlignSuggestions() {},
|
||||
suggestionsListClass: () => 'custom-class',
|
||||
},
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
wrapper.destroy();
|
||||
});
|
||||
|
||||
it('renders release value', async () => {
|
||||
wrapper = createComponent({ value: { data: id } });
|
||||
await wrapper.vm.$nextTick();
|
||||
|
||||
const tokenSegments = wrapper.findAllComponents(GlFilteredSearchTokenSegment);
|
||||
|
||||
expect(tokenSegments).toHaveLength(3); // `Release` `=` `v1`
|
||||
expect(tokenSegments.at(2).text()).toBe(id.toString());
|
||||
});
|
||||
|
||||
it('fetches initial values', () => {
|
||||
const fetchReleasesSpy = jest.fn().mockResolvedValue();
|
||||
|
||||
wrapper = createComponent({
|
||||
config: { ...mockReleaseToken, fetchReleases: fetchReleasesSpy },
|
||||
value: { data: id },
|
||||
});
|
||||
|
||||
expect(fetchReleasesSpy).toHaveBeenCalledWith(id);
|
||||
});
|
||||
|
||||
it('fetches releases on user input', () => {
|
||||
const search = 'hello';
|
||||
const fetchReleasesSpy = jest.fn().mockResolvedValue();
|
||||
|
||||
wrapper = createComponent({
|
||||
config: { ...mockReleaseToken, fetchReleases: fetchReleasesSpy },
|
||||
});
|
||||
|
||||
wrapper.findComponent(GlFilteredSearchToken).vm.$emit('input', { data: search });
|
||||
|
||||
expect(fetchReleasesSpy).toHaveBeenCalledWith(search);
|
||||
});
|
||||
|
||||
it('renders error message when request fails', async () => {
|
||||
const fetchReleasesSpy = jest.fn().mockRejectedValue();
|
||||
|
||||
wrapper = createComponent({
|
||||
config: { ...mockReleaseToken, fetchReleases: fetchReleasesSpy },
|
||||
});
|
||||
await waitForPromises();
|
||||
|
||||
expect(createFlash).toHaveBeenCalledWith({
|
||||
message: 'There was a problem fetching releases.',
|
||||
});
|
||||
});
|
||||
});
|
|
@ -326,6 +326,7 @@ RSpec.describe IssuesHelper do
|
|||
new_issue_path: new_project_issue_path(project, issue: { milestone_id: finder.milestones.first.id }),
|
||||
project_import_jira_path: project_import_jira_path(project),
|
||||
quick_actions_help_path: help_page_path('user/project/quick_actions'),
|
||||
releases_path: project_releases_path(project, format: :json),
|
||||
reset_path: new_issuable_address_project_path(project, issuable_type: 'issue'),
|
||||
rss_path: '#',
|
||||
show_new_issue_link: 'true',
|
||||
|
|
|
@ -23,64 +23,46 @@ RSpec.describe Gitlab::Metrics::Samplers::ActionCableSampler do
|
|||
allow(pool).to receive(:queue_length).and_return(6)
|
||||
end
|
||||
|
||||
shared_examples 'collects metrics' do |expected_labels|
|
||||
it 'includes active connections' do
|
||||
expect(subject.metrics[:active_connections]).to receive(:set).with(expected_labels, 0)
|
||||
it 'includes active connections' do
|
||||
expect(subject.metrics[:active_connections]).to receive(:set).with({}, 0)
|
||||
|
||||
subject.sample
|
||||
end
|
||||
|
||||
it 'includes minimum worker pool size' do
|
||||
expect(subject.metrics[:pool_min_size]).to receive(:set).with(expected_labels, 1)
|
||||
|
||||
subject.sample
|
||||
end
|
||||
|
||||
it 'includes maximum worker pool size' do
|
||||
expect(subject.metrics[:pool_max_size]).to receive(:set).with(expected_labels, 2)
|
||||
|
||||
subject.sample
|
||||
end
|
||||
|
||||
it 'includes current worker pool size' do
|
||||
expect(subject.metrics[:pool_current_size]).to receive(:set).with(expected_labels, 3)
|
||||
|
||||
subject.sample
|
||||
end
|
||||
|
||||
it 'includes largest worker pool size' do
|
||||
expect(subject.metrics[:pool_largest_size]).to receive(:set).with(expected_labels, 4)
|
||||
|
||||
subject.sample
|
||||
end
|
||||
|
||||
it 'includes worker pool completed task count' do
|
||||
expect(subject.metrics[:pool_completed_tasks]).to receive(:set).with(expected_labels, 5)
|
||||
|
||||
subject.sample
|
||||
end
|
||||
|
||||
it 'includes worker pool pending task count' do
|
||||
expect(subject.metrics[:pool_pending_tasks]).to receive(:set).with(expected_labels, 6)
|
||||
|
||||
subject.sample
|
||||
end
|
||||
subject.sample
|
||||
end
|
||||
|
||||
context 'for in-app mode' do
|
||||
before do
|
||||
expect(Gitlab::ActionCable::Config).to receive(:in_app?).and_return(true)
|
||||
end
|
||||
it 'includes minimum worker pool size' do
|
||||
expect(subject.metrics[:pool_min_size]).to receive(:set).with({}, 1)
|
||||
|
||||
it_behaves_like 'collects metrics', server_mode: 'in-app'
|
||||
subject.sample
|
||||
end
|
||||
|
||||
context 'for standalone mode' do
|
||||
before do
|
||||
expect(Gitlab::ActionCable::Config).to receive(:in_app?).and_return(false)
|
||||
end
|
||||
it 'includes maximum worker pool size' do
|
||||
expect(subject.metrics[:pool_max_size]).to receive(:set).with({}, 2)
|
||||
|
||||
it_behaves_like 'collects metrics', server_mode: 'standalone'
|
||||
subject.sample
|
||||
end
|
||||
|
||||
it 'includes current worker pool size' do
|
||||
expect(subject.metrics[:pool_current_size]).to receive(:set).with({}, 3)
|
||||
|
||||
subject.sample
|
||||
end
|
||||
|
||||
it 'includes largest worker pool size' do
|
||||
expect(subject.metrics[:pool_largest_size]).to receive(:set).with({}, 4)
|
||||
|
||||
subject.sample
|
||||
end
|
||||
|
||||
it 'includes worker pool completed task count' do
|
||||
expect(subject.metrics[:pool_completed_tasks]).to receive(:set).with({}, 5)
|
||||
|
||||
subject.sample
|
||||
end
|
||||
|
||||
it 'includes worker pool pending task count' do
|
||||
expect(subject.metrics[:pool_pending_tasks]).to receive(:set).with({}, 6)
|
||||
|
||||
subject.sample
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -48,10 +48,9 @@ RSpec.describe Gitlab::Runtime do
|
|||
|
||||
before do
|
||||
stub_const('::Puma', puma_type)
|
||||
stub_env('ACTION_CABLE_IN_APP', 'false')
|
||||
end
|
||||
|
||||
it_behaves_like "valid runtime", :puma, 1
|
||||
it_behaves_like "valid runtime", :puma, 1 + Gitlab::ActionCable::Config.worker_pool_size
|
||||
end
|
||||
|
||||
context "puma with cli_config" do
|
||||
|
@ -61,27 +60,16 @@ RSpec.describe Gitlab::Runtime do
|
|||
before do
|
||||
stub_const('::Puma', puma_type)
|
||||
allow(puma_type).to receive_message_chain(:cli_config, :options).and_return(max_threads: 2, workers: max_workers)
|
||||
stub_env('ACTION_CABLE_IN_APP', 'false')
|
||||
end
|
||||
|
||||
it_behaves_like "valid runtime", :puma, 3
|
||||
it_behaves_like "valid runtime", :puma, 3 + Gitlab::ActionCable::Config.worker_pool_size
|
||||
|
||||
context "when ActionCable in-app mode is enabled" do
|
||||
context "when ActionCable worker pool size is configured" do
|
||||
before do
|
||||
stub_env('ACTION_CABLE_IN_APP', 'true')
|
||||
stub_env('ACTION_CABLE_WORKER_POOL_SIZE', '3')
|
||||
stub_env('ACTION_CABLE_WORKER_POOL_SIZE', 10)
|
||||
end
|
||||
|
||||
it_behaves_like "valid runtime", :puma, 6
|
||||
end
|
||||
|
||||
context "when ActionCable standalone is run" do
|
||||
before do
|
||||
stub_const('ACTION_CABLE_SERVER', true)
|
||||
stub_env('ACTION_CABLE_WORKER_POOL_SIZE', '8')
|
||||
end
|
||||
|
||||
it_behaves_like "valid runtime", :puma, 11
|
||||
it_behaves_like "valid runtime", :puma, 13
|
||||
end
|
||||
|
||||
describe ".puma_in_clustered_mode?" do
|
||||
|
|
|
@ -86,7 +86,7 @@ RSpec.describe ServiceFieldEntity do
|
|||
expected_hash = {
|
||||
type: 'select',
|
||||
name: 'branches_to_be_notified',
|
||||
title: nil,
|
||||
title: 'Branches for which notifications are to be sent',
|
||||
placeholder: nil,
|
||||
required: nil,
|
||||
choices: [['All branches', 'all'], ['Default branch', 'default'], ['Protected branches', 'protected'], ['Default branch and protected branches', 'default_and_protected']],
|
||||
|
|
|
@ -1248,28 +1248,38 @@ RSpec.describe Issues::UpdateService, :mailer do
|
|||
let(:closed_issuable) { create(:closed_issue, project: project) }
|
||||
end
|
||||
|
||||
context 'real-time updates' do
|
||||
using RSpec::Parameterized::TableSyntax
|
||||
|
||||
context 'broadcasting issue assignee updates' do
|
||||
let(:update_params) { { assignee_ids: [user2.id] } }
|
||||
|
||||
where(:action_cable_in_app_enabled, :feature_flag_enabled, :should_broadcast) do
|
||||
true | true | true
|
||||
true | false | true
|
||||
false | true | true
|
||||
false | false | false
|
||||
context 'when feature flag is enabled' do
|
||||
before do
|
||||
stub_feature_flags(broadcast_issue_updates: true)
|
||||
end
|
||||
|
||||
it 'triggers the GraphQL subscription' do
|
||||
expect(GraphqlTriggers).to receive(:issuable_assignees_updated).with(issue)
|
||||
|
||||
update_issue(update_params)
|
||||
end
|
||||
|
||||
context 'when assignee is not updated' do
|
||||
let(:update_params) { { title: 'Some other title' } }
|
||||
|
||||
it 'does not trigger the GraphQL subscription' do
|
||||
expect(GraphqlTriggers).not_to receive(:issuable_assignees_updated).with(issue)
|
||||
|
||||
update_issue(update_params)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
with_them do
|
||||
it 'broadcasts to the issues channel based on ActionCable and feature flag values' do
|
||||
allow(Gitlab::ActionCable::Config).to receive(:in_app?).and_return(action_cable_in_app_enabled)
|
||||
stub_feature_flags(broadcast_issue_updates: feature_flag_enabled)
|
||||
context 'when feature flag is disabled' do
|
||||
before do
|
||||
stub_feature_flags(broadcast_issue_updates: false)
|
||||
end
|
||||
|
||||
if should_broadcast
|
||||
expect(GraphqlTriggers).to receive(:issuable_assignees_updated).with(issue)
|
||||
else
|
||||
expect(GraphqlTriggers).not_to receive(:issuable_assignees_updated).with(issue)
|
||||
end
|
||||
it 'does not trigger the GraphQL subscription' do
|
||||
expect(GraphqlTriggers).not_to receive(:issuable_assignees_updated).with(issue)
|
||||
|
||||
update_issue(update_params)
|
||||
end
|
||||
|
|
|
@ -228,7 +228,7 @@ RSpec.describe Tooling::Danger::Changelog do
|
|||
end
|
||||
|
||||
context 'with changelog label' do
|
||||
let(:mr_labels) { ['feature'] }
|
||||
let(:mr_labels) { ['type::feature'] }
|
||||
|
||||
it 'is truthy' do
|
||||
is_expected.to be_truthy
|
||||
|
@ -236,7 +236,7 @@ RSpec.describe Tooling::Danger::Changelog do
|
|||
end
|
||||
|
||||
context 'with no changelog label' do
|
||||
let(:mr_labels) { ['tooling'] }
|
||||
let(:mr_labels) { ['type::tooling'] }
|
||||
|
||||
it 'is truthy' do
|
||||
is_expected.to be_falsey
|
||||
|
|
|
@ -6,7 +6,7 @@ module Tooling
|
|||
module Danger
|
||||
module Changelog
|
||||
NO_CHANGELOG_LABELS = [
|
||||
'tooling',
|
||||
'type::tooling',
|
||||
'tooling::pipelines',
|
||||
'tooling::workflow',
|
||||
'ci-build',
|
||||
|
|
Loading…
Reference in a new issue