Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2020-08-24 12:10:17 +00:00
parent 2f752481c2
commit 4b9bde7848
140 changed files with 1131 additions and 494 deletions

View File

@ -1,8 +1,8 @@
<script>
import { s__ } from '~/locale';
import Todo from '~/sidebar/components/todo_toggle/todo.vue';
import createAlertTodo from '../../graphql/mutations/alert_todo_create.mutation.graphql';
import todoMarkDone from '../../graphql/mutations/alert_todo_mark_done.mutation.graphql';
import createAlertTodoMutation from '../../graphql/mutations/alert_todo_create.mutation.graphql';
import todoMarkDoneMutation from '~/graphql_shared/mutations/todo_mark_done.mutation.graphql';
import alertQuery from '../../graphql/queries/details.query.graphql';
export default {
@ -66,7 +66,7 @@ export default {
this.isUpdating = true;
return this.$apollo
.mutate({
mutation: createAlertTodo,
mutation: createAlertTodoMutation,
variables: {
iid: this.alert.iid,
projectPath: this.projectPath,
@ -89,7 +89,7 @@ export default {
this.isUpdating = true;
return this.$apollo
.mutate({
mutation: todoMarkDone,
mutation: todoMarkDoneMutation,
variables: {
id: this.firstToDoId,
},

View File

@ -22,6 +22,10 @@ export function formatListIssues(listIssues) {
}, {});
}
export function fullBoardId(boardId) {
return `gid://gitlab/Board/${boardId}`;
}
export default {
getMilestone,
formatListIssues,

View File

@ -1,5 +1,5 @@
<script>
import { mapState } from 'vuex';
import { mapActions, mapState } from 'vuex';
import { GlAlert } from '@gitlab/ui';
import BoardColumn from 'ee_else_ce/boards/components/board_column.vue';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
@ -47,6 +47,18 @@ export default {
isSwimlanesOn() {
return this.glFeatures.boardsWithSwimlanes && this.isShowingEpicsSwimlanes;
},
boardListsToUse() {
return this.glFeatures.graphqlBoardLists ? this.boardLists : this.lists;
},
},
mounted() {
if (this.glFeatures.graphqlBoardLists) {
this.fetchLists();
this.showPromotionList();
}
},
methods: {
...mapActions(['fetchLists', 'showPromotionList']),
},
};
</script>
@ -62,7 +74,7 @@ export default {
data-qa-selector="boards_list"
>
<board-column
v-for="list in lists"
v-for="list in boardListsToUse"
:key="list.id"
ref="board"
:can-admin-list="canAdminList"
@ -77,7 +89,7 @@ export default {
<epics-swimlanes
v-else
ref="swimlanes"
:lists="boardLists"
:lists="boardListsToUse"
:can-admin-list="canAdminList"
:disabled="disabled"
:board-id="boardId"

View File

@ -6,6 +6,7 @@ import boardsStore from '~/boards/stores/boards_store';
import eventHub from '~/sidebar/event_hub';
import { isScopedLabel } from '~/lib/utils/common_utils';
import { inactiveId } from '~/boards/constants';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
// NOTE: need to revisit how we handle headerHeight, because we have so many different header and footer options.
export default {
@ -23,13 +24,17 @@ export default {
BoardSettingsListTypes: () =>
import('ee_component/boards/components/board_settings_list_types.vue'),
},
mixins: [glFeatureFlagMixin()],
computed: {
...mapState(['activeId']),
...mapState(['activeId', 'boardLists']),
activeList() {
/*
Warning: Though a computed property it is not reactive because we are
referencing a List Model class. Reactivity only applies to plain JS objects
*/
if (this.glFeatures.graphqlBoardLists) {
return this.boardLists.find(({ id }) => id === this.activeId);
}
return boardsStore.state.lists.find(({ id }) => id === this.activeId);
},
isSidebarOpen() {

View File

@ -24,7 +24,6 @@ import { deprecatedCreateFlash as Flash } from '~/flash';
import { __ } from '~/locale';
import './models/label';
import './models/assignee';
import { BoardType } from './constants';
import toggleFocusMode from '~/boards/toggle_focus';
import FilteredSearchBoards from '~/boards/filtered_search_boards';
@ -44,10 +43,7 @@ import {
parseBoolean,
urlParamsToObject,
} from '~/lib/utils/common_utils';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import mountMultipleBoardsSwitcher from './mount_multiple_boards_switcher';
import projectBoardQuery from './queries/project_board.query.graphql';
import groupQuery from './queries/group_board.query.graphql';
Vue.use(VueApollo);
@ -119,7 +115,12 @@ export default () => {
boardId: this.boardId,
fullPath: $boardApp.dataset.fullPath,
};
this.setInitialBoardData({ ...endpoints, boardType: this.parent });
this.setInitialBoardData({
...endpoints,
boardType: this.parent,
disabled: this.disabled,
showPromotion: parseBoolean($boardApp.getAttribute('data-show-promotion')),
});
boardsStore.setEndpoints(endpoints);
boardsStore.rootPath = this.boardsEndpoint;
@ -144,42 +145,7 @@ export default () => {
boardsStore.disabled = this.disabled;
if (gon.features.graphqlBoardLists) {
this.$apollo.addSmartQuery('lists', {
query() {
return this.parent === BoardType.group ? groupQuery : projectBoardQuery;
},
variables() {
return {
fullPath: this.state.endpoints.fullPath,
boardId: `gid://gitlab/Board/${this.boardId}`,
};
},
update(data) {
return this.getNodes(data);
},
result({ data, error }) {
if (error) {
throw error;
}
const lists = this.getNodes(data);
lists.forEach(list =>
boardsStore.addList({
...list,
id: getIdFromGraphQLId(list.id),
}),
);
boardsStore.addBlankState();
setPromotionState(boardsStore);
},
error() {
Flash(__('An error occurred while fetching the board lists. Please try again.'));
},
});
} else {
if (!gon.features.graphqlBoardLists) {
boardsStore
.all()
.then(res => res.data)

View File

@ -0,0 +1,10 @@
#import "./board_list.fragment.graphql"
mutation CreateBoardList($boardId: BoardID!, $backlog: Boolean) {
boardListCreate(input: { boardId: $boardId, backlog: $backlog }) {
list {
...BoardListFragment
}
errors
}
}

View File

@ -4,7 +4,6 @@ fragment BoardListShared on BoardList {
position
listType
collapsed
maxIssueCount
label {
id
title

View File

@ -1,17 +1,28 @@
import * as types from './mutation_types';
import Cookies from 'js-cookie';
import { sortBy } from 'lodash';
import createFlash from '~/flash';
import { __ } from '~/locale';
import { parseBoolean } from '~/lib/utils/common_utils';
import createDefaultClient from '~/lib/graphql';
import { BoardType } from '~/boards/constants';
import { formatListIssues } from '../boards_util';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import { BoardType, ListType } from '~/boards/constants';
import * as types from './mutation_types';
import { formatListIssues, fullBoardId } from '../boards_util';
import boardStore from '~/boards/stores/boards_store';
import groupListsIssuesQuery from '../queries/group_lists_issues.query.graphql';
import projectListsIssuesQuery from '../queries/project_lists_issues.query.graphql';
const gqlClient = createDefaultClient();
import projectBoardQuery from '../queries/project_board.query.graphql';
import groupBoardQuery from '../queries/group_board.query.graphql';
import createBoardListMutation from '../queries/board_list_create.mutation.graphql';
const notImplemented = () => {
/* eslint-disable-next-line @gitlab/require-i18n-strings */
throw new Error('Not implemented!');
};
export const gqlClient = createDefaultClient();
export default {
setInitialBoardData: ({ commit }, data) => {
commit(types.SET_INITIAL_BOARD_DATA, data);
@ -26,18 +37,112 @@ export default {
commit(types.SET_FILTERS, filterParams);
},
fetchLists: () => {
notImplemented();
fetchLists: ({ commit, state, dispatch }) => {
const { endpoints, boardType } = state;
const { fullPath, boardId } = endpoints;
let query;
if (boardType === BoardType.group) {
query = groupBoardQuery;
} else if (boardType === BoardType.project) {
query = projectBoardQuery;
} else {
createFlash(__('Invalid board'));
return Promise.reject();
}
const variables = {
fullPath,
boardId: fullBoardId(boardId),
};
return gqlClient
.query({
query,
variables,
})
.then(({ data }) => {
let { lists } = data[boardType]?.board;
// Temporarily using positioning logic from boardStore
lists = lists.nodes.map(list =>
boardStore.updateListPosition({
...list,
id: getIdFromGraphQLId(list.id),
}),
);
commit(types.RECEIVE_LISTS, sortBy(lists, 'position'));
// Backlog list needs to be created if it doesn't exist
if (!lists.find(l => l.type === ListType.backlog)) {
dispatch('createList', { backlog: true });
}
dispatch('showWelcomeList');
})
.catch(() => {
createFlash(
__('An error occurred while fetching the board lists. Please reload the page.'),
);
});
},
// This action only supports backlog list creation at this stage
// Future iterations will add the ability to create other list types
createList: ({ state, commit, dispatch }, { backlog = false }) => {
const { boardId } = state.endpoints;
gqlClient
.mutate({
mutation: createBoardListMutation,
variables: {
boardId: fullBoardId(boardId),
backlog,
},
})
.then(({ data }) => {
if (data?.boardListCreate?.errors.length) {
commit(types.CREATE_LIST_FAILURE);
} else {
const list = data.boardListCreate?.list;
dispatch('addList', { ...list, id: getIdFromGraphQLId(list.id) });
}
})
.catch(() => {
commit(types.CREATE_LIST_FAILURE);
});
},
addList: ({ state, commit }, list) => {
const lists = state.boardLists;
// Temporarily using positioning logic from boardStore
lists.push(boardStore.updateListPosition(list));
commit(types.RECEIVE_LISTS, sortBy(lists, 'position'));
},
showWelcomeList: ({ state, dispatch }) => {
if (state.disabled) {
return;
}
if (
state.boardLists.find(list => list.type !== ListType.backlog && list.type !== ListType.closed)
) {
return;
}
if (parseBoolean(Cookies.get('issue_board_welcome_hidden'))) {
return;
}
dispatch('addList', {
id: 'blank',
listType: ListType.blank,
title: __('Welcome to your issue board!'),
position: 0,
});
},
showPromotionList: () => {},
generateDefaultLists: () => {
notImplemented();
},
createList: () => {
notImplemented();
},
updateList: () => {
notImplemented();
},
@ -60,7 +165,7 @@ export default {
const variables = {
fullPath,
boardId: `gid://gitlab/Board/${boardId}`,
boardId: fullBoardId(boardId),
};
return gqlClient

View File

@ -1,5 +1,9 @@
export const SET_INITIAL_BOARD_DATA = 'SET_INITIAL_BOARD_DATA';
export const SET_FILTERS = 'SET_FILTERS';
export const CREATE_LIST_SUCCESS = 'CREATE_LIST_SUCCESS';
export const CREATE_LIST_FAILURE = 'CREATE_LIST_FAILURE';
export const RECEIVE_LISTS = 'RECEIVE_LISTS';
export const SHOW_PROMOTION_LIST = 'SHOW_PROMOTION_LIST';
export const REQUEST_ADD_LIST = 'REQUEST_ADD_LIST';
export const RECEIVE_ADD_LIST_SUCCESS = 'RECEIVE_ADD_LIST_SUCCESS';
export const RECEIVE_ADD_LIST_ERROR = 'RECEIVE_ADD_LIST_ERROR';

View File

@ -7,10 +7,16 @@ const notImplemented = () => {
};
export default {
[mutationTypes.SET_INITIAL_BOARD_DATA]: (state, data) => {
const { boardType, ...endpoints } = data;
[mutationTypes.SET_INITIAL_BOARD_DATA](state, data) {
const { boardType, disabled, showPromotion, ...endpoints } = data;
state.endpoints = endpoints;
state.boardType = boardType;
state.disabled = disabled;
state.showPromotion = showPromotion;
},
[mutationTypes.RECEIVE_LISTS]: (state, lists) => {
state.boardLists = lists;
},
[mutationTypes.SET_ACTIVE_ID](state, id) {
@ -21,6 +27,10 @@ export default {
state.filterParams = filterParams;
},
[mutationTypes.CREATE_LIST_FAILURE]: state => {
state.error = __('An error occurred while creating the list. Please try again.');
},
[mutationTypes.REQUEST_ADD_LIST]: () => {
notImplemented();
},

View File

@ -3,6 +3,8 @@ import { inactiveId } from '~/boards/constants';
export default () => ({
endpoints: {},
boardType: null,
disabled: false,
showPromotion: false,
isShowingLabels: true,
activeId: inactiveId,
boardLists: [],

View File

@ -1,36 +1,31 @@
<script>
import { mapGetters } from 'vuex';
import { GlFormGroup, GlToggle } from '@gitlab/ui';
import { GlFormGroup, GlFormCheckbox } from '@gitlab/ui';
import eventHub from '../event_hub';
export default {
name: 'ActiveToggle',
name: 'ActiveCheckbox',
components: {
GlFormGroup,
GlToggle,
},
props: {
initialActivated: {
type: Boolean,
required: true,
},
GlFormCheckbox,
},
data() {
return {
activated: this.initialActivated,
activated: false,
};
},
computed: {
...mapGetters(['isInheriting']),
...mapGetters(['isInheriting', 'propsSource']),
},
mounted() {
this.activated = this.propsSource.initialActivated;
// Initialize view
this.$nextTick(() => {
this.onToggle(this.activated);
this.onChange(this.activated);
});
},
methods: {
onToggle(e) {
onChange(e) {
eventHub.$emit('toggle', e);
},
},
@ -39,12 +34,15 @@ export default {
<template>
<gl-form-group :label="__('Enable integration')" label-for="service[active]">
<gl-toggle
<input name="service[active]" type="hidden" :value="activated || false" />
<gl-form-checkbox
v-model="activated"
name="service[active]"
class="gl-display-block gl-line-height-0"
:disabled="isInheriting"
@change="onToggle"
/>
@change="onChange"
>
{{ __('Active') }}
</gl-form-checkbox>
</gl-form-group>
</template>

View File

@ -3,7 +3,7 @@ import { mapState, mapActions, mapGetters } from 'vuex';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import OverrideDropdown from './override_dropdown.vue';
import ActiveToggle from './active_toggle.vue';
import ActiveCheckbox from './active_checkbox.vue';
import JiraTriggerFields from './jira_trigger_fields.vue';
import JiraIssuesFields from './jira_issues_fields.vue';
import TriggerFields from './trigger_fields.vue';
@ -13,7 +13,7 @@ export default {
name: 'IntegrationForm',
components: {
OverrideDropdown,
ActiveToggle,
ActiveCheckbox,
JiraTriggerFields,
JiraIssuesFields,
TriggerFields,
@ -44,11 +44,7 @@ export default {
:override="override"
@change="setOverride"
/>
<active-toggle
v-if="propsSource.showActive"
:key="`${currentKey}-active-toggle`"
v-bind="propsSource.activeToggleProps"
/>
<active-checkbox v-if="propsSource.showActive" :key="`${currentKey}-active-checkbox`" />
<jira-trigger-fields
v-if="isJira"
:key="`${currentKey}-jira-trigger-fields`"

View File

@ -35,9 +35,7 @@ function parseDatasetToProps(data) {
} = parseBooleanInData(booleanAttributes);
return {
activeToggleProps: {
initialActivated: activated,
},
initialActivated: activated,
showActive,
type,
triggerFieldsProps: {

View File

@ -4,6 +4,7 @@ import { createUploadLink } from 'apollo-upload-client';
import { ApolloLink } from 'apollo-link';
import { BatchHttpLink } from 'apollo-link-batch-http';
import csrf from '~/lib/utils/csrf';
import PerformanceBarService from '~/performance_bar/services/performance_bar_service';
export const fetchPolicies = {
CACHE_FIRST: 'cache-first',
@ -32,13 +33,35 @@ export default (resolvers = {}, config = {}) => {
credentials: 'same-origin',
};
const uploadsLink = ApolloLink.split(
operation => operation.getContext().hasUpload || operation.getContext().isSingleRequest,
createUploadLink(httpOptions),
new BatchHttpLink(httpOptions),
);
const performanceBarLink = new ApolloLink((operation, forward) => {
return forward(operation).map(response => {
const httpResponse = operation.getContext().response;
if (PerformanceBarService.interceptor) {
PerformanceBarService.interceptor({
config: {
url: httpResponse.url,
},
headers: {
'x-request-id': httpResponse.headers.get('x-request-id'),
'x-gitlab-from-cache': httpResponse.headers.get('x-gitlab-from-cache'),
},
});
}
return response;
});
});
return new ApolloClient({
typeDefs: config.typeDefs,
link: ApolloLink.split(
operation => operation.getContext().hasUpload || operation.getContext().isSingleRequest,
createUploadLink(httpOptions),
new BatchHttpLink(httpOptions),
),
link: ApolloLink.from([performanceBarLink, uploadsLink]),
cache: new InMemoryCache({
...config.cacheConfig,
freezeResults: config.assumeImmutableResults,

View File

@ -37,7 +37,11 @@ export default {
};
</script>
<template>
<div ref="variablesSection" class="d-sm-flex flex-sm-wrap pt-2 pr-1 pb-0 pl-2 variables-section">
<div
ref="variablesSection"
class="d-sm-flex flex-sm-wrap pt-2 pr-1 pb-0 pl-2 variables-section"
data-qa-selector="variables_content"
>
<div v-for="variable in variables" :key="variable.name" class="mb-1 pr-2 d-flex d-sm-block">
<component
:is="variableField(variable.type)"
@ -46,6 +50,7 @@ export default {
:value="variable.value"
:name="variable.name"
:options="variable.options"
data-qa-selector="variable_item"
@input="refreshDashboard(variable, $event)"
/>
</div>

View File

@ -0,0 +1,6 @@
import PersistentUserCallout from '~/persistent_user_callout';
document.addEventListener('DOMContentLoaded', () => {
const callout = document.querySelector('.js-service-templates-deprecated');
PersistentUserCallout.factory(callout);
});

View File

@ -24,15 +24,12 @@ export default ({ container }) =>
};
},
mounted() {
this.interceptor = PerformanceBarService.registerInterceptor(
this.peekUrl,
this.loadRequestDetails,
);
PerformanceBarService.registerInterceptor(this.peekUrl, this.loadRequestDetails);
this.loadRequestDetails(this.requestId, window.location.href);
},
beforeDestroy() {
PerformanceBarService.removeInterceptor(this.interceptor);
PerformanceBarService.removeInterceptor();
},
methods: {
addRequestManually(urlOrRequestId) {

View File

@ -2,12 +2,14 @@ import axios from '../../lib/utils/axios_utils';
import { parseBoolean } from '~/lib/utils/common_utils';
export default class PerformanceBarService {
static interceptor = null;
static fetchRequestDetails(peekUrl, requestId) {
return axios.get(peekUrl, { params: { request_id: requestId } });
}
static registerInterceptor(peekUrl, callback) {
const interceptor = response => {
PerformanceBarService.interceptor = response => {
const [fireCallback, requestId, requestUrl] = PerformanceBarService.callbackParams(
response,
peekUrl,
@ -20,18 +22,17 @@ export default class PerformanceBarService {
return response;
};
return axios.interceptors.response.use(interceptor);
return axios.interceptors.response.use(PerformanceBarService.interceptor);
}
static removeInterceptor(interceptor) {
axios.interceptors.response.eject(interceptor);
static removeInterceptor() {
axios.interceptors.response.eject(PerformanceBarService.interceptor);
PerformanceBarService.interceptor = null;
}
static callbackParams(response, peekUrl) {
const requestId = response.headers && response.headers['x-request-id'];
// Get the request URL from response.config for Axios, and response for
// Vue Resource.
const requestUrl = (response.config || response).url;
const requestUrl = response.config?.url;
const cachedResponse =
response.headers && parseBoolean(response.headers['x-gitlab-from-cache']);
const fireCallback = requestUrl !== peekUrl && Boolean(requestId) && !cachedResponse;

View File

@ -47,7 +47,10 @@ export default class PerformanceBarStore {
}
canTrackRequest(requestUrl) {
return this.requests.filter(request => request.url === requestUrl).length < 2;
return (
requestUrl.endsWith('/api/graphql') ||
this.requests.filter(request => request.url === requestUrl).length < 2
);
}
static truncateUrl(requestUrl) {

View File

@ -1,5 +1,5 @@
<script>
import { GlDeprecatedButton, GlTooltipDirective, GlLoadingIcon } from '@gitlab/ui';
import { GlTooltipDirective, GlButton, GlLoadingIcon } from '@gitlab/ui';
import axios from '~/lib/utils/axios_utils';
import { deprecatedCreateFlash as flash } from '~/flash';
import { s__, __, sprintf } from '~/locale';
@ -14,7 +14,7 @@ export default {
components: {
Icon,
GlCountdown,
GlDeprecatedButton,
GlButton,
GlLoadingIcon,
},
props: {
@ -83,9 +83,9 @@ export default {
type="button"
:disabled="isLoading"
class="dropdown-new btn btn-default js-pipeline-dropdown-manual-actions"
:title="__('Manual job')"
:title="__('Run manual or delayed jobs')"
data-toggle="dropdown"
:aria-label="__('Manual job')"
:aria-label="__('Run manual or delayed jobs')"
>
<icon name="play" class="icon-play" />
<i class="fa fa-caret-down" aria-hidden="true"></i>
@ -94,18 +94,21 @@ export default {
<ul class="dropdown-menu dropdown-menu-right">
<li v-for="action in actions" :key="action.path">
<gl-deprecated-button
<gl-button
category="tertiary"
:class="{ disabled: isActionDisabled(action) }"
:disabled="isActionDisabled(action)"
class="js-pipeline-action-link no-btn btn d-flex align-items-center justify-content-between flex-wrap"
class="js-pipeline-action-link"
@click="onClickAction(action)"
>
{{ action.name }}
<span v-if="action.scheduled_at">
<icon name="clock" />
<gl-countdown :end-date-string="action.scheduled_at" />
</span>
</gl-deprecated-button>
<div class="d-flex justify-content-between flex-wrap">
{{ action.name }}
<span v-if="action.scheduled_at">
<icon name="clock" />
<gl-countdown :end-date-string="action.scheduled_at" />
</span>
</div>
</gl-button>
</li>
</ul>
</div>

View File

@ -42,7 +42,7 @@ export default {
<template>
<div class="card-header d-flex align-items-center bg-white pr-0">
<h2 class="card-title my-2 mr-auto gl-font-size-20-deprecated-no-really-do-not-use-me">
<h2 class="card-title my-2 mr-auto">
<gl-link v-if="selfLink" :href="selfLink" class="font-size-inherit">
{{ release.name }}
</gl-link>

View File

@ -528,4 +528,3 @@ img.emoji {
See https://gitlab.com/gitlab-org/gitlab/issues/36857 for more details.
**/
.gl-line-height-14 { line-height: $gl-line-height-14; }
.gl-font-size-20 { font-size: $gl-font-size-20; }

View File

@ -352,7 +352,6 @@ $gl-header-color: #4c4e54;
$gl-font-size-12: 12px;
$gl-font-size-14: 14px;
$gl-font-size-16: 16px;
$gl-font-size-20: 20px;
$gl-font-size-28: 28px;
$gl-font-size-42: 42px;

View File

@ -8,6 +8,7 @@ class Groups::BoardsController < Groups::ApplicationController
before_action :assign_endpoint_vars
before_action do
push_frontend_feature_flag(:multi_select_board, default_enabled: true)
push_frontend_feature_flag(:graphql_board_lists, group, default_enabled: false)
push_frontend_feature_flag(:boards_with_swimlanes, group, default_enabled: false)
end

View File

@ -9,6 +9,7 @@ class Projects::BadgesController < Projects::ApplicationController
def pipeline
pipeline_status = Gitlab::Badge::Pipeline::Status
.new(project, params[:ref], opts: {
ignore_skipped: params[:ignore_skipped],
key_text: params[:key_text],
key_width: params[:key_width]
})

View File

@ -5,6 +5,7 @@ module UserCalloutsHelper
GKE_CLUSTER_INTEGRATION = 'gke_cluster_integration'
GCP_SIGNUP_OFFER = 'gcp_signup_offer'
SUGGEST_POPOVER_DISMISSED = 'suggest_popover_dismissed'
SERVICE_TEMPLATES_DEPRECATED = 'service_templates_deprecated'
TABS_POSITION_HIGHLIGHT = 'tabs_position_highlight'
WEBHOOKS_MOVED = 'webhooks_moved'
CUSTOMIZE_HOMEPAGE = 'customize_homepage'
@ -37,6 +38,10 @@ module UserCalloutsHelper
!user_dismissed?(SUGGEST_POPOVER_DISMISSED)
end
def show_service_templates_deprecated?
!user_dismissed?(SERVICE_TEMPLATES_DEPRECATED)
end
def show_webhooks_moved_alert?
!user_dismissed?(WEBHOOKS_MOVED)
end

View File

@ -5,6 +5,7 @@
module Ci
class PipelineArtifact < ApplicationRecord
extend Gitlab::Ci::Model
include UpdateProjectStatistics
include Artifactable
include FileStoreMounter
@ -30,6 +31,8 @@ module Ci
mount_file_store_uploader Ci::PipelineArtifactUploader
update_project_statistics project_statistics_name: :pipeline_artifacts_size
enum file_type: {
code_coverage: 1
}

View File

@ -148,7 +148,7 @@ class Deployment < ApplicationRecord
def execute_hooks
deployment_data = Gitlab::DataBuilder::Deployment.build(self)
project.execute_hooks(deployment_data, :deployment_hooks) if Feature.enabled?(:deployment_webhooks, project, default_enabled: true)
project.execute_hooks(deployment_data, :deployment_hooks)
project.execute_services(deployment_data, :deployment_hooks)
end

View File

@ -12,7 +12,12 @@ class ProjectStatistics < ApplicationRecord
before_save :update_storage_size
COLUMNS_TO_REFRESH = [:repository_size, :wiki_size, :lfs_objects_size, :commit_count, :snippets_size].freeze
INCREMENTABLE_COLUMNS = { build_artifacts_size: %i[storage_size], packages_size: %i[storage_size], snippets_size: %i[storage_size] }.freeze
INCREMENTABLE_COLUMNS = {
build_artifacts_size: %i[storage_size],
packages_size: %i[storage_size],
pipeline_artifacts_size: %i[storage_size],
snippets_size: %i[storage_size]
}.freeze
NAMESPACE_RELATABLE_COLUMNS = [:repository_size, :wiki_size, :lfs_objects_size].freeze
scope :for_project_ids, ->(project_ids) { where(project_id: project_ids) }
@ -75,7 +80,7 @@ class ProjectStatistics < ApplicationRecord
end
def update_storage_size
storage_size = repository_size + wiki_size + lfs_objects_size + build_artifacts_size + packages_size
storage_size = repository_size + wiki_size + lfs_objects_size + build_artifacts_size + packages_size + pipeline_artifacts_size
# The `snippets_size` column was added on 20200622095419 but db/post_migrate/20190527194900_schedule_calculate_wiki_sizes.rb
# might try to update project statistics before the `snippets_size` column has been created.
storage_size += snippets_size if self.class.column_names.include?('snippets_size')

View File

@ -17,6 +17,7 @@ module UserCalloutEnums
suggest_popover_dismissed: 9,
tabs_position_highlight: 10,
webhooks_moved: 13,
service_templates_deprecated: 14,
admin_integrations_moved: 15,
personal_access_token_expiry: 21, # EE-only
suggest_pipeline: 22,

View File

@ -1,9 +1,28 @@
- page_title _("Service Templates")
- @content_class = 'limit-container-width' unless fluid_layout
- if show_service_templates_deprecated?
.gl-alert.gl-alert-tip.js-service-templates-deprecated.gl-mt-5{ role: 'alert', data: { feature_id: UserCalloutsHelper::SERVICE_TEMPLATES_DEPRECATED, dismiss_endpoint: user_callouts_path } }
= sprite_icon('bulb', css_class: 'gl-alert-icon gl-alert-icon-no-title')
%button.js-close.gl-alert-dismiss{ type: 'button', aria: { label: _('Dismiss') } }
= sprite_icon('close')
%h4.gl-alert-title= s_('AdminSettings|Service Templates will soon be deprecated.')
.gl-alert-body
= s_('AdminSettings|Try using the latest version of Integrations instead.')
.gl-alert-actions
= link_to _('Go to Integrations'), integrations_admin_application_settings_path, class: 'btn btn-info gl-alert-action gl-button'
= link_to _('Learn more'), help_page_path('user/admin_area/settings/project_integration_management'), class: 'btn gl-alert-action btn-secondary gl-button', target: '_blank', rel: 'noopener noreferrer'
%h3.page-title Service templates
%p.light= s_('AdminSettings|Service template allows you to set default values for integrations')
.table-holder
%table.table
%colgroup
%col
%col
%col
%col{ width: 135 }
%thead
%tr
%th

View File

@ -8,7 +8,7 @@
= _("GitLab is a single application for the entire software development lifecycle. From project planning and source code management to CI/CD, monitoring, and security.")
.col-lg-5.order-12
.text-center.mb-3
%h2.font-weight-bold.gl-font-size-20-deprecated-no-really-do-not-use-me= _('Register for GitLab')
%h2.font-weight-bold= _('Register for GitLab')
= render 'devise/shared/experimental_separate_sign_up_flow_box'
= render 'devise/shared/sign_in_link'
- else

View File

@ -1,4 +1,6 @@
- if Feature.enabled?(:vue_issuables_list, @project)
- is_project_overview = local_assigns.fetch(:is_project_overview, false)
- if Feature.enabled?(:vue_issuables_list, @project) && !is_project_overview
- data_endpoint = local_assigns.fetch(:data_endpoint, expose_path(api_v4_projects_issues_path(id: @project.id)))
- default_empty_state_meta = { create_issue_path: new_project_issue_path(@project), svg_path: image_path('illustrations/issues.svg') }
- data_empty_state_meta = local_assigns.fetch(:data_empty_state_meta, default_empty_state_meta)

View File

@ -3,7 +3,7 @@
%col
%col
%col.d-none.d-sm-table-column
%col{ width: 130 }
%col{ width: 135 }
%thead{ role: 'rowgroup' }
%tr{ role: 'row' }
%th{ role: 'columnheader', scope: 'col', 'aria-colindex': 1 }

View File

@ -10,7 +10,7 @@ module Ci
def perform(project_id, user_id, ref_path)
::Project.find_by_id(project_id).try do |project|
::User.find_by_id(user_id).try do |user|
::Ci::Ref.find_by_ref_path(ref_path).try do |ci_ref|
project.ci_refs.find_by_ref_path(ref_path).try do |ci_ref|
::Ci::UnlockArtifactsService
.new(project, user)
.execute(ci_ref)

View File

@ -0,0 +1,5 @@
---
title: Add ignore_skipped option for pipeline status badge
merge_request: 28288
author: Fabian Schneider @fabsrc
type: added

View File

@ -0,0 +1,5 @@
---
title: Add Service Templates deprecation warning banner
merge_request: 25587
author:
type: changed

View File

@ -0,0 +1,5 @@
---
title: Change active toggle on integration settings page to checkbox
merge_request: 39586
author:
type: changed

View File

@ -1,5 +0,0 @@
---
title: Include Redis in Workhorse-in-test-suite integration
merge_request: 40026
author:
type: other

View File

@ -5,7 +5,7 @@ const isESLint = mod => {
let parent = mod.parent;
while (parent) {
if (parent.filename.includes('/eslint')) {
if (parent.filename && parent.filename.includes('/eslint')) {
return true;
}

View File

@ -7,33 +7,15 @@ type: howto
# Updating the Geo nodes **(PREMIUM ONLY)**
CAUTION: **Warning:**
Please ensure you read these sections carefully before updating your Geo nodes! Not following version-specific update steps may result in unexpected downtime. Please [contact support](https://about.gitlab.com/support/#contact-support) if you have any specific questions.
Updating Geo nodes involves performing:
1. [Version-specific update steps](#version-specific-update-steps), depending on the
1. [Version-specific update steps](version_specific_updates.md), depending on the
version being updated to or from.
1. [General update steps](#general-update-steps), for all updates.
## Version specific update steps
Depending on which version of Geo you are updating to/from, there may be
different steps.
- [Updating to GitLab 12.9](version_specific_updates.md#updating-to-gitlab-129)
- [Updating to GitLab 12.7](version_specific_updates.md#updating-to-gitlab-127)
- [Updating to GitLab 12.2](version_specific_updates.md#updating-to-gitlab-122)
- [Updating to GitLab 12.1](version_specific_updates.md#updating-to-gitlab-121)
- [Updating to GitLab 12.0](version_specific_updates.md#updating-to-gitlab-120)
- [Updating to GitLab 11.11](version_specific_updates.md#updating-to-gitlab-1111)
- [Updating to GitLab 10.8](version_specific_updates.md#updating-to-gitlab-108)
- [Updating to GitLab 10.6](version_specific_updates.md#updating-to-gitlab-106)
- [Updating to GitLab 10.5](version_specific_updates.md#updating-to-gitlab-105)
- [Updating to GitLab 10.3](version_specific_updates.md#updating-to-gitlab-103)
- [Updating to GitLab 10.2](version_specific_updates.md#updating-to-gitlab-102)
- [Updating to GitLab 10.1](version_specific_updates.md#updating-to-gitlab-101)
- [Updating to GitLab 10.0](version_specific_updates.md#updating-to-gitlab-100)
- [Updating from GitLab 9.3 or older](version_specific_updates.md#updating-from-gitlab-93-or-older)
- [Updating to GitLab 9.0](version_specific_updates.md#updating-to-gitlab-90)
## General update steps
NOTE: **Note:**

View File

@ -266,6 +266,14 @@ You can access a pipeline status badge image using the following link:
https://gitlab.example.com/<namespace>/<project>/badges/<branch>/pipeline.svg
```
#### Display only non-skipped status
If you want the pipeline status badge to only display the last non-skipped status, you can use the `?ignore_skipped=true` query parameter:
```plaintext
https://example.gitlab.com/<namespace>/<project>/badges/<branch>/pipeline.svg?ignore_skipped=true
```
### Test coverage report badge
GitLab makes it possible to define the regular expression for [coverage report](#test-coverage-parsing),

View File

@ -691,6 +691,38 @@ unit tests.
Instead of `setImmediate`, use `jest.runAllTimers` or `jest.runOnlyPendingTimers` to run pending timers.
The latter is useful when you have `setInterval` in the code. **Remember:** our Jest configuration uses fake timers.
## Avoid non-deterministic specs
Non-determinism is the breeding ground for flaky and brittle specs. Such specs end up breaking the CI pipeline, interrupting the work flow of other contributors.
1. Make sure your test subject's collaborators (e.g., axios, apollo, lodash helpers) and test environment (e.g., Date) behave consistently across systems and over time.
1. Make sure tests are focused and not doing "extra work" (e.g., needlessly creating the test subject more than once in an individual test)
### Faking `Date` for determinism
Consider using `useFakeDate` to ensure a consistent value is returned with every `new Date()` or `Date.now()`.
```javascript
import { useFakeDate } from 'helpers/fake_date';
describe('cool/component', () => {
useFakeDate();
// ...
});
```
### Faking `Math.random` for determinism
Consider replacing `Math.random` with a fake when the test subject depends on it.
```javascript
beforeEach(() => {
// https://xkcd.com/221/
jest.spyOn(Math, 'random').mockReturnValue(0.4);
});
```
## Factories
TBU

View File

@ -214,17 +214,17 @@ If you have an issue that spans across multiple repositories, create an issue fo
With Git, you can use an interactive rebase (`rebase -i`) to squash multiple commits into one or reorder them.
This functionality is useful if you want to replace a couple of small commits with a single commit, or if you want to make the order more logical.
However, you should never rebase commits you have pushed to a remote server.
Rebasing creates new commits for all your changes, which can cause confusion because the same change would have multiple identifiers.
It also causes merge errors for anyone working on the same branch because their history would not match with yours.
However, you should avoid rebasing commits you have pushed to a remote server if you have other active contributors in the same branch.
Since rebasing creates new commits for all your changes, it can cause confusion because the same change would have multiple identifiers.
It would cause merge errors for anyone working on the same branch because their history would not match with yours. It can be really troublesome for the author or other contributors.
Also, if someone has already reviewed your code, rebasing makes it hard to tell what changed since the last review.
You should also never rebase commits authored by other people.
You should never rebase commits authored by other people unless you've agreed otherwise.
Not only does this rewrite history, but it also loses authorship information.
Rebasing prevents the other authors from being attributed and sharing part of the [`git blame`](https://git-scm.com/docs/git-blame).
If a merge involves many commits, it may seem more difficult to undo.
You might think to solve this by squashing all the changes into one commit before merging, but as discussed earlier, it is a bad idea to rebase commits that you have already pushed.
You might consider solving this by squashing all the changes into one commit just before merging by using GitLab's [Squash-and-Merge](../user/project/merge_requests/squash_and_merge.md) feature.
Fortunately, there is an easy way to undo a merge with all its commits.
The way to do this is by reverting the merge commit.
Preserving this ability to revert a merge is a good reason to always use the "no fast-forward" (`--no-ff`) strategy when you merge manually.
@ -241,10 +241,9 @@ Having lots of merge commits can make your repository history messy.
Therefore, you should try to avoid merge commits in feature branches.
Often, people avoid merge commits by just using rebase to reorder their commits after the commits on the `master` branch.
Using rebase prevents a merge commit when merging `master` into your feature branch, and it creates a neat linear history.
However, as discussed in [the section about rebasing](#squashing-commits-with-rebase), you should never rebase commits you have pushed to a remote server.
This restriction makes it impossible to rebase work in progress that you already shared with your team, which is something we recommend.
However, as discussed in [the section about rebasing](#squashing-commits-with-rebase), you should avoid rebasing commits in a feature branch that you're sharing with others.
Rebasing also creates more work, since every time you rebase, you have to resolve similar conflicts.
Rebasing could create more work, since every time you rebase, you may need to resolve the same conflicts.
Sometimes you can reuse recorded resolutions (`rerere`), but merging is better since you only have to resolve conflicts once.
Atlassian has a more thorough explanation of the tradeoffs between merging and rebasing [on their blog](https://www.atlassian.com/blog/git/git-team-workflows-merge-or-rebase).

View File

@ -12,6 +12,7 @@ module Gitlab
def initialize(project, ref, opts: {})
@project = project
@ref = ref
@ignore_skipped = Gitlab::Utils.to_boolean(opts[:ignore_skipped], default: false)
@customization = {
key_width: opts[:key_width].to_i,
key_text: opts[:key_text]
@ -26,9 +27,11 @@ module Gitlab
# rubocop: disable CodeReuse/ActiveRecord
def status
@project.ci_pipelines
pipelines = @project.ci_pipelines
.where(sha: @sha)
.latest_status(@ref) || 'unknown'
relation = @ignore_skipped ? pipelines.without_statuses([:skipped]) : pipelines
relation.latest_status(@ref) || 'unknown'
end
# rubocop: enable CodeReuse/ActiveRecord

View File

@ -28,26 +28,6 @@ module Gitlab
end
# rubocop:enable Rails/Output
module Workhorse
extend Gitlab::SetupHelper
class << self
def configuration_toml(dir, _)
config = { redis: { URL: redis_url } }
TomlRB.dump(config)
end
def redis_url
data = YAML.load_file(Rails.root.join('config/resque.yml'))
data.dig(Rails.env, 'url')
end
def get_config_path(dir)
File.join(dir, 'config.toml')
end
end
end
module Gitaly
extend Gitlab::SetupHelper
class << self

View File

@ -1848,6 +1848,9 @@ msgstr ""
msgid "AdminSettings|Select a template"
msgstr ""
msgid "AdminSettings|Service Templates will soon be deprecated."
msgstr ""
msgid "AdminSettings|Service template allows you to set default values for integrations"
msgstr ""
@ -1863,6 +1866,9 @@ msgstr ""
msgid "AdminSettings|The required pipeline configuration can be selected from the %{code_start}gitlab-ci%{code_end} directory inside of the configured %{link_start}instance template repository%{link_end} or from GitLab provided configurations."
msgstr ""
msgid "AdminSettings|Try using the latest version of Integrations instead."
msgstr ""
msgid "AdminSettings|When creating a new environment variable it will be protected by default."
msgstr ""
@ -2591,6 +2597,9 @@ msgstr ""
msgid "An error occurred while committing your changes."
msgstr ""
msgid "An error occurred while creating the list. Please try again."
msgstr ""
msgid "An error occurred while decoding the file."
msgstr ""
@ -2666,6 +2675,9 @@ msgstr ""
msgid "An error occurred while fetching the board issues. Please reload the page."
msgstr ""
msgid "An error occurred while fetching the board lists. Please reload the page."
msgstr ""
msgid "An error occurred while fetching the board lists. Please try again."
msgstr ""
@ -7719,9 +7731,15 @@ msgstr ""
msgid "DastProfiles|Manage profiles"
msgstr ""
msgid "DastProfiles|New Scanner Profile"
msgstr ""
msgid "DastProfiles|New Site Profile"
msgstr ""
msgid "DastProfiles|New scanner profile"
msgstr ""
msgid "DastProfiles|New site profile"
msgstr ""
@ -11710,6 +11728,9 @@ msgstr ""
msgid "Go to %{strongStart}Issues%{strongEnd} &gt; %{strongStart}Boards%{strongEnd} to access your personalized learning issue board."
msgstr ""
msgid "Go to Integrations"
msgstr ""
msgid "Go to Webhooks"
msgstr ""
@ -12962,6 +12983,9 @@ msgstr ""
msgid "ImportProjects|Update of imported projects with realtime changes failed"
msgstr ""
msgid "Improve Issue Boards"
msgstr ""
msgid "Improve Issue boards"
msgstr ""
@ -13291,6 +13315,9 @@ msgstr ""
msgid "Invalid URL"
msgstr ""
msgid "Invalid board"
msgstr ""
msgid "Invalid container_name"
msgstr ""
@ -14741,9 +14768,6 @@ msgstr ""
msgid "Manifest import"
msgstr ""
msgid "Manual job"
msgstr ""
msgid "ManualOrdering|Couldn't save the order of the issues"
msgstr ""
@ -21100,6 +21124,9 @@ msgstr ""
msgid "Run housekeeping"
msgstr ""
msgid "Run manual or delayed jobs"
msgstr ""
msgid "Run tests against your code live using the Web Terminal"
msgstr ""
@ -27586,6 +27613,9 @@ msgstr ""
msgid "Welcome to your Issue Board!"
msgstr ""
msgid "Welcome to your issue board!"
msgstr ""
msgid "Weve been making changes to %{featureName} and wed love your feedback %{linkStart}in this issue%{linkEnd} to help us improve the experience."
msgstr ""

View File

@ -7,8 +7,8 @@
"dev-server": "NODE_OPTIONS=\"--max-old-space-size=3584\" node scripts/frontend/webpack_dev_server.js",
"eslint": "eslint --cache --max-warnings 0 --report-unused-disable-directives --ext .js,.vue .",
"eslint-fix": "eslint --cache --max-warnings 0 --report-unused-disable-directives --ext .js,.vue --fix .",
"eslint-staged": "git diff --cached --name-only | grep -E \"(.*)\\.(js|vue)$\" | xargs eslint --cache --max-warnings 0 --report-unused-disable-directives",
"eslint-staged-fix": "git diff --cached --name-only | grep -E \"(.*)\\.(js|vue)$\" | xargs eslint --cache --max-warnings 0 --report-unused-disable-directives --fix",
"eslint-staged": "git diff --diff-filter=d --cached --name-only | grep -E \"(.*)\\.(js|vue)$\" | xargs eslint --cache --max-warnings 0 --report-unused-disable-directives",
"eslint-staged-fix": "git diff --diff-filter=d --cached --name-only | grep -E \"(.*)\\.(js|vue)$\" | xargs eslint --cache --max-warnings 0 --report-unused-disable-directives --fix",
"eslint-report": "eslint --max-warnings 0 --ext .js,.vue --format html --output-file ./eslint-report.html --no-inline-config .",
"file-coverage": "scripts/frontend/file_test_coverage.js",
"prejest": "yarn check-dependencies",
@ -43,7 +43,7 @@
"@babel/preset-env": "^7.10.1",
"@gitlab/at.js": "1.5.5",
"@gitlab/svgs": "1.158.0",
"@gitlab/ui": "20.4.1",
"@gitlab/ui": "20.5.0",
"@gitlab/visual-review-tools": "1.6.1",
"@rails/actioncable": "^6.0.3-1",
"@sentry/browser": "^5.10.2",

View File

@ -0,0 +1,43 @@
dashboard: 'Pod metrics'
priority: 10
templating:
variables:
pod_name:
label: 'CPU POD'
type: custom
options:
values:
- value: 'runner-gitlab-runner-.*'
text: 'GitLab Runner'
- value: 'Option1'
text: 'Option'
- value: 'Option2'
text: 'Option'
- value: 'Option3'
text: 'Option'
pod_name2:
label: 'Memory POD'
type: custom
options:
values:
- value: 'production-postgresql-.*'
text: 'Postgresql'
panel_groups:
- group: CPU metrics
panels:
- title: "CPU usage GitLab Runner"
type: "line-chart"
y_label: "Cores per pod"
metrics:
- id: pod_cpu_usage_seconds_total
query_range: 'rate(container_cpu_usage_seconds_total{pod_name=~"{{pod_name}}"}[5m])'
unit: "cores"
label: pod_name
- title: "Memory usage Postgresql"
type: "line-chart"
y_label: "Working set memory (MiB)"
metrics:
- id: pod_memory_working_set1
query_range: 'container_memory_working_set_bytes{pod_name=~"{{pod_name2}}"}/1024/1024'
unit: "MiB"
label: pod_name

View File

@ -41,6 +41,11 @@ module QA
element :quick_range_item
end
view 'app/assets/javascripts/monitoring/components/variables_section.vue' do
element :variables_content
element :variable_item
end
def wait_for_metrics
wait_for_data
return if has_metrics?
@ -73,6 +78,14 @@ module QA
within('.modal-content') { click_button(class: 'btn-success') }
end
def select_dashboard(dashboard_name)
click_element :dashboards_filter_dropdown
within_element :dashboards_filter_dropdown do
click_on dashboard_name
end
end
def filter_environment(environment = 'production')
click_element :environments_dropdown
@ -97,6 +110,18 @@ module QA
end
end
def has_templating_variable?(variable)
within_element :variables_content do
has_element?(:variable_item, text: variable)
end
end
def has_template_metric?(metric)
within_element :prometheus_graphs do
has_text?(metric)
end
end
private
def wait_for_data

View File

@ -28,7 +28,7 @@ module QA
praefect_manager.reset_primary_to_original
end
it 'automatically fails over' do
it 'automatically fails over', status_issue: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/976' do
# Create a new project with a commit and wait for it to replicate
Resource::Repository::ProjectPush.fabricate! do |push|
push.project = project
@ -66,7 +66,7 @@ module QA
end
context 'when recovering from dataloss after failover' do
it 'allows reconciliation', quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/238187', type: :stale } do
it 'allows reconciliation', quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/238187', type: :stale }, status_issue: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/977' do
# Start the old primary node again
praefect_manager.start_primary_node
praefect_manager.wait_for_health_check_current_primary_node

View File

@ -22,7 +22,7 @@ module QA
praefect_manager.reset_primary_to_original
end
it 'recovers from dataloss', quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/238186', type: :investigating } do
it 'recovers from dataloss', quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/238186', type: :investigating }, status_issue: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/978' do
# Create a new project with a commit and wait for it to replicate
praefect_manager.wait_for_replication(project.id)

View File

@ -25,7 +25,7 @@ module QA
end
end
context 'when moving from one Gitaly storage to another', :orchestrated, :repository_storage do
context 'when moving from one Gitaly storage to another', :orchestrated, :repository_storage, status_issue: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/973' do
let(:source_storage) { { type: :gitaly, name: 'default' } }
let(:destination_storage) { { type: :gitaly, name: QA::Runtime::Env.additional_repository_storage } }
@ -43,7 +43,7 @@ module QA
# Note: This test doesn't have the :orchestrated tag because it runs in the Test::Integration::Praefect
# scenario with other tests that aren't considered orchestrated.
# It also runs on staging using nfs-file07 as non-cluster storage and nfs-file22 as cluster/praefect storage
context 'when moving from Gitaly to Gitaly Cluster', :requires_praefect do
context 'when moving from Gitaly to Gitaly Cluster', :requires_praefect, status_issue: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/974' do
let(:source_storage) { { type: :gitaly, name: QA::Runtime::Env.non_cluster_repository_storage } }
let(:destination_storage) { { type: :praefect, name: QA::Runtime::Env.praefect_repository_storage } }

View File

@ -25,7 +25,7 @@ module QA
Runtime::Feature.disable_and_verify('gitaly_distributed_reads')
end
it 'reads from each node' do
it 'reads from each node', status_issue: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/979' do
pre_read_data = praefect_manager.query_read_distribution
wait_for_reads_to_increase(project, number_of_reads_per_loop, pre_read_data)
@ -53,7 +53,7 @@ module QA
praefect_manager.wait_for_reliable_connection
end
it 'does not read from the unhealthy node' do
it 'does not read from the unhealthy node', status_issue: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/980' do
pre_read_data = praefect_manager.query_read_distribution
read_from_project(project, number_of_reads_per_loop * 10)

View File

@ -19,7 +19,7 @@ module QA
praefect_manager.clear_replication_queue
end
it 'allows replication of different repository after interruption' do
it 'allows replication of different repository after interruption', status_issue: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/975' do
# We want to fill the replication queue with 10 `in_progress` jobs,
# while a lock has been acquired, which is when the problem occurred
# as reported in https://gitlab.com/gitlab-org/gitaly/-/issues/2801

View File

@ -12,7 +12,7 @@ module QA
let(:project_name) { "api-basics-#{SecureRandom.hex(8)}" }
let(:sanitized_project_path) { CGI.escape("#{Runtime::User.username}/#{project_name}") }
it 'user creates a project with a file and deletes them afterwards' do
it 'user creates a project with a file and deletes them afterwards', status_issue: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/420' do
create_project_request = Runtime::API::Request.new(@api_client, '/projects')
post create_project_request.url, path: project_name, name: project_name
@ -76,7 +76,7 @@ module QA
SVG
end
it 'sets no-cache headers as expected' do
it 'sets no-cache headers as expected', status_issue: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/421' do
create_project_request = Runtime::API::Request.new(@api_client, '/projects')
post create_project_request.url, path: project_name, name: project_name

View File

@ -28,7 +28,7 @@ module QA
end
end
it 'download archives of each user project then check they are different' do
it 'download archives of each user project then check they are different', status_issue: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/427' do
archive_checksums = {}
users.each do |user_key, user_info|

View File

@ -12,7 +12,7 @@ module QA
Flow::Login.sign_in
end
it 'user adds a design and annotates it' do
it 'user adds a design and annotates it', status_issue: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/955' do
issue.visit!
Page::Project::Issue::Show.perform do |issue|

View File

@ -41,7 +41,7 @@ module QA
end
end
it 'closes an issue via pushing a commit' do
it 'closes an issue via pushing a commit', status_issue: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/827' do
issue_key = Vendor::Jira::JiraAPI.perform do |jira_api|
jira_api.create_issue(jira_project_key)
end
@ -51,7 +51,7 @@ module QA
expect_issue_done(issue_key)
end
it 'closes an issue via a merge request' do
it 'closes an issue via a merge request', status_issue: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/828' do
issue_key = Vendor::Jira::JiraAPI.perform do |jira_api|
jira_api.create_issue(jira_project_key)
end

View File

@ -16,7 +16,7 @@ module QA
Flow::Login.sign_in
end
it 'creates a basic merge request', :smoke do
it 'creates a basic merge request', :smoke, status_issue: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/409' do
Resource::MergeRequest.fabricate_via_browser_ui! do |merge_request|
merge_request.project = project
merge_request.title = merge_request_title
@ -29,7 +29,7 @@ module QA
end
end
it 'creates a merge request with a milestone and label' do
it 'creates a merge request with a milestone and label', status_issue: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/514' do
gitlab_account_username = "@#{Runtime::User.username}"
milestone = Resource::ProjectMilestone.fabricate_via_api! do |milestone|

View File

@ -9,7 +9,7 @@ module QA
end
end
it 'can merge feature branch fork to mainline' do
it 'can merge feature branch fork to mainline', status_issue: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/928' do
Flow::Login.sign_in
merge_request.visit!

View File

@ -3,7 +3,7 @@
module QA
RSpec.describe 'Create', quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/30226', type: :bug } do
describe 'Merge request rebasing' do
it 'user rebases source branch of merge request' do
it 'user rebases source branch of merge request', status_issue: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/398' do
Flow::Login.sign_in
project = Resource::Project.fabricate_via_api! do |project|

View File

@ -31,7 +31,7 @@ module QA
merge_request.visit!
end
it 'user squashes commits while merging' do
it 'user squashes commits while merging', status_issue: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/418' do
Page::MergeRequest::Show.perform do |merge_request_page|
merge_request_page.retry_on_exception(reload: true) do
expect(merge_request_page).to have_text('to be squashed')

View File

@ -15,7 +15,7 @@ module QA
merge_request.visit!
end
it 'views the merge request email patches' do
it 'views the merge request email patches', status_issue: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/416' do
Page::MergeRequest::Show.perform(&:view_email_patches)
expect(page.text).to start_with('From')
@ -23,7 +23,7 @@ module QA
expect(page).to have_content("diff --git a/#{merge_request.file_name} b/#{merge_request.file_name}")
end
it 'views the merge request plain diff' do
it 'views the merge request plain diff', status_issue: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/417' do
Page::MergeRequest::Show.perform(&:view_plain_diff)
expect(page.text).to start_with("diff --git a/#{merge_request.file_name} b/#{merge_request.file_name}")

View File

@ -55,7 +55,7 @@ module QA
project.visit!
end
it 'lists branches correctly after CRUD operations' do
it 'lists branches correctly after CRUD operations', status_issue: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/413' do
Page::Project::Menu.perform(&:go_to_repository_branches)
expect(page).to have_content(master_branch)

View File

@ -26,7 +26,7 @@ module QA
project.wait_for_push_new_branch
end
it 'user performs a deep clone' do
it 'user performs a deep clone', status_issue: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/475' do
Git::Repository.perform do |repository|
repository.uri = project.repository_http_location.uri
repository.use_default_credentials
@ -37,7 +37,7 @@ module QA
end
end
it 'user performs a shallow clone' do
it 'user performs a shallow clone', status_issue: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/411' do
Git::Repository.perform do |repository|
repository.uri = project.repository_http_location.uri
repository.use_default_credentials

View File

@ -3,7 +3,7 @@
module QA
RSpec.describe 'Create' do
describe 'Files management' do
it 'user creates, edits and deletes a file via the Web' do
it 'user creates, edits and deletes a file via the Web', status_issue: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/451' do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.perform(&:sign_in_using_credentials)

View File

@ -22,7 +22,7 @@ module QA
parent_project.add_member(user)
end
it 'creates a 2nd fork after moving the parent project' do
it 'creates a 2nd fork after moving the parent project', status_issue: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/713' do
Flow::Login.sign_in(as: user)
fork_project.visit!

View File

@ -3,7 +3,7 @@
module QA
RSpec.describe 'Create' do
describe 'Push over HTTP using Git protocol version 2', :requires_git_protocol_v2 do
it 'user pushes to the repository' do
it 'user pushes to the repository', status_issue: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/469' do
Flow::Login.sign_in
# Create a project to push to

View File

@ -27,7 +27,7 @@ module QA
Page::Main::Menu.perform(&:sign_out_if_signed_in)
end
it 'user pushes to the repository' do
it 'user pushes to the repository', status_issue: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/386' do
project = Resource::Project.fabricate_via_api! do |project|
project.name = 'git-protocol-project'
end

View File

@ -3,7 +3,7 @@
module QA
RSpec.describe 'Create' do
describe 'Git push over HTTP', :ldap_no_tls, :smoke do
it 'user using a personal access token pushes code to the repository' do
it 'user using a personal access token pushes code to the repository', status_issue: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/430' do
Flow::Login.sign_in
access_token = Resource::PersonalAccessToken.fabricate!.access_token

View File

@ -3,7 +3,7 @@
module QA
RSpec.describe 'Create' do
describe 'Push mirror a repository over HTTP' do
it 'configures and syncs a (push) mirrored repository' do
it 'configures and syncs a (push) mirrored repository', status_issue: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/414' do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.perform(&:sign_in_using_credentials)

View File

@ -26,7 +26,7 @@ module QA
set_file_size_limit(nil)
end
it 'push successful when the file size is under the limit' do
it 'push successful when the file size is under the limit', status_issue: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/456' do
set_file_size_limit(5)
retry_on_fail do
@ -36,7 +36,7 @@ module QA
end
end
it 'push fails when the file size is above the limit' do
it 'push fails when the file size is above the limit', status_issue: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/458' do
set_file_size_limit(2)
retry_on_fail do

View File

@ -3,7 +3,7 @@
module QA
RSpec.describe 'Create' do
describe 'Git push over HTTP', :ldap_no_tls do
it 'user pushes code to the repository', :smoke do
it 'user pushes code to the repository', :smoke, status_issue: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/426' do
Flow::Login.sign_in
Resource::Repository::ProjectPush.fabricate! do |push|
@ -18,7 +18,7 @@ module QA
end
end
it 'pushes to a project using a specific Praefect repository storage', :smoke, :requires_admin, :requires_praefect do
it 'pushes to a project using a specific Praefect repository storage', :smoke, :requires_admin, :requires_praefect, status_issue: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/742' do
Flow::Login.sign_in_as_admin
project = Resource::Project.fabricate_via_api! do |storage_project|

View File

@ -26,7 +26,7 @@ module QA
Flow::Login.sign_in
end
it 'pushes code to the repository via SSH', :smoke do
it 'pushes code to the repository via SSH', :smoke, status_issue: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/969' do
Resource::Repository::ProjectPush.fabricate! do |push|
push.project = project
push.ssh_key = @key
@ -41,7 +41,7 @@ module QA
end
end
it 'pushes multiple branches and tags together', :smoke do
it 'pushes multiple branches and tags together', :smoke, status_issue: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/970' do
branches = []
tags = []
Git::Repository.perform do |repository|

View File

@ -18,7 +18,7 @@ module QA
end
context 'when developers and maintainers are allowed to push to a protected branch' do
it 'user with push rights successfully pushes to the protected branch' do
it 'user with push rights successfully pushes to the protected branch', status_issue: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/447' do
create_protected_branch(allowed_to_push: {
roles: Resource::ProtectedBranch::Roles::DEVS_AND_MAINTAINERS
})
@ -30,7 +30,7 @@ module QA
end
context 'when developers and maintainers are not allowed to push to a protected branch' do
it 'user without push rights fails to push to the protected branch' do
it 'user without push rights fails to push to the protected branch', status_issue: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/449' do
create_protected_branch(allowed_to_push: {
roles: Resource::ProtectedBranch::Roles::NO_ONE
})

View File

@ -9,7 +9,7 @@ module QA
Flow::Login.sign_in
end
it 'user can add an SSH key' do
it 'user can add an SSH key', status_issue: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/929' do
key = Resource::SSHKey.fabricate_via_browser_ui! do |resource|
resource.title = key_title
end
@ -20,7 +20,7 @@ module QA
# Note this context ensures that the example it contains is executed after the example above. Be aware of the order of execution if you add new examples in either context.
context 'after adding an ssh key' do
it 'can delete an ssh key' do
it 'can delete an ssh key', status_issue: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/930' do
Page::Main::Menu.perform(&:click_settings_link)
Page::Profile::Menu.perform(&:click_ssh_keys)
Page::Profile::SSHKeys.perform do |ssh_keys|

View File

@ -43,7 +43,7 @@ module QA
find('pre').text
end
it 'user views raw email patch' do
it 'user views raw email patch', status_issue: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/442' do
view_commit
Page::Project::Commit::Show.perform(&:select_email_patches)
@ -53,7 +53,7 @@ module QA
expect(page).to have_content('diff --git a/second b/second')
end
it 'user views raw commit diff' do
it 'user views raw commit diff', status_issue: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/439' do
view_commit
Page::Project::Commit::Show.perform(&:select_plain_diff)

View File

@ -36,7 +36,7 @@ module QA
Flow::Login.sign_in
end
it 'clones, pushes, and pulls a snippet over HTTP, edits via UI' do
it 'clones, pushes, and pulls a snippet over HTTP, edits via UI', status_issue: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/826' do
Resource::Repository::Push.fabricate! do |push|
push.repository_http_uri = repository_uri_http
push.file_name = new_file
@ -65,7 +65,7 @@ module QA
end
end
it 'clones, pushes, and pulls a snippet over SSH, deletes via UI' do
it 'clones, pushes, and pulls a snippet over SSH, deletes via UI', status_issue: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/825' do
Resource::Repository::Push.fabricate! do |push|
push.repository_ssh_uri = repository_uri_ssh
push.ssh_key = ssh_key

View File

@ -36,7 +36,7 @@ module QA
Flow::Login.sign_in
end
it 'clones, pushes, and pulls a project snippet over HTTP, edits via UI' do
it 'clones, pushes, and pulls a project snippet over HTTP, edits via UI', status_issue: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/833' do
Resource::Repository::Push.fabricate! do |push|
push.repository_http_uri = repository_uri_http
push.file_name = new_file
@ -65,7 +65,7 @@ module QA
end
end
it 'clones, pushes, and pulls a project snippet over SSH, deletes via UI' do
it 'clones, pushes, and pulls a project snippet over SSH, deletes via UI', status_issue: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/832' do
Resource::Repository::Push.fabricate! do |push|
push.repository_ssh_uri = repository_uri_ssh
push.ssh_key = ssh_key

View File

@ -3,7 +3,7 @@
module QA
RSpec.describe 'Create', :smoke do
describe 'Personal snippet creation' do
it 'User creates a personal snippet' do
it 'User creates a personal snippet', status_issue: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/840' do
Flow::Login.sign_in
Page::Main::Menu.perform do |menu|

View File

@ -3,7 +3,7 @@
module QA
RSpec.describe 'Create' do # to be converted to a smoke test once proved to be stable
describe 'Project snippet creation' do
it 'User creates a project snippet' do
it 'User creates a project snippet', status_issue: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/839' do
Flow::Login.sign_in
Resource::ProjectSnippet.fabricate_via_browser_ui! do |snippet|

View File

@ -17,7 +17,7 @@ module QA
Flow::Login.sign_in
end
it "creates the first file in an empty project via Web IDE" do
it "creates the first file in an empty project via Web IDE", status_issue: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/847' do
# In the first iteration, the test opens Web IDE by modifying the URL to address past regressions.
# Once the Web IDE button is introduced for empty projects, the test will be modified to go through UI.
# See https://gitlab.com/gitlab-org/gitlab/-/issues/27915 and https://gitlab.com/gitlab-org/gitlab/-/issues/27535.

View File

@ -14,7 +14,7 @@ module QA
let(:user) { Resource::User.fabricate_or_use(Runtime::Env.gitlab_qa_username_1, Runtime::Env.gitlab_qa_password_1) }
context 'when no fork is present' do
it 'suggests to create a fork when a user clicks Web IDE in the main project' do
it 'suggests to create a fork when a user clicks Web IDE in the main project', status_issue: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/959' do
Flow::Login.sign_in(as: user)
parent_project.visit!
@ -34,7 +34,7 @@ module QA
end
end
it 'opens the fork when a user clicks Web IDE in the main project' do
it 'opens the fork when a user clicks Web IDE in the main project', status_issue: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/960' do
Flow::Login.sign_in(as: user)
fork_project.upstream.visit!
Page::Project::Show.perform do |project_page|

View File

@ -20,7 +20,7 @@ module QA
merge_request.visit!
end
it 'opens and edits a merge request in Web IDE' do
it 'opens and edits a merge request in Web IDE', status_issue: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/705' do
Page::MergeRequest::Show.perform do |show|
show.click_open_in_web_ide
end

View File

@ -15,7 +15,7 @@ module QA
Flow::Login.sign_in
end
it 'by adding a home page to the wiki' do
it 'by adding a home page to the wiki', status_issue: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/856' do
project.visit!
Page::Project::Menu.perform(&:click_wiki)
@ -35,7 +35,7 @@ module QA
end
end
it 'by adding a second page to the wiki' do
it 'by adding a second page to the wiki', status_issue: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/855' do
wiki.visit!
Page::Project::Wiki::Show.perform(&:click_new_page)
@ -54,7 +54,7 @@ module QA
end
end
it 'by adding a home page to the wiki using git push' do
it 'by adding a home page to the wiki using git push', status_issue: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/853' do
empty_wiki = Resource::Wiki::ProjectPage.new do |empty_wiki|
empty_wiki.project = project
end
@ -73,7 +73,7 @@ module QA
end
end
it 'by adding a second page to the wiki using git push' do
it 'by adding a second page to the wiki using git push', status_issue: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/854' do
Resource::Repository::WikiPush.fabricate! do |push|
push.file_name = "#{new_wiki_title}.md"
push.file_content = new_wiki_content

View File

@ -14,7 +14,7 @@ module QA
Flow::Login.sign_in
end
it 'by manipulating content on the page' do
it 'by manipulating content on the page', status_issue: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/857' do
wiki.visit!
Page::Project::Wiki::Show.perform(&:click_edit)
@ -33,7 +33,7 @@ module QA
end
end
it 'by manipulating content on the page using git push' do
it 'by manipulating content on the page using git push', status_issue: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/858' do
Resource::Repository::WikiPush.fabricate! do |push|
push.file_content = new_wiki_content
push.commit_message = commit_message

View File

@ -10,7 +10,7 @@ module QA
Flow::Login.sign_in
end
it 'has changed the directory' do
it 'has changed the directory', status_issue: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/948' do
initial_wiki.visit!
Page::Project::Wiki::Show.perform(&:click_edit)

View File

@ -15,7 +15,7 @@ module QA
end
context 'Sidebar' do
it 'has all expected links that work' do
it 'has all expected links that work', status_issue: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/903' do
small_wiki.visit!
small_number_of_pages.times do |index|
@ -35,7 +35,7 @@ module QA
end
context 'Page List' do
it 'has all expected links that work' do
it 'has all expected links that work', status_issue: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/902' do
large_wiki.visit!
Page::Project::Wiki::Show.perform(&:click_view_all_pages)

View File

@ -10,7 +10,7 @@ module QA
end
context 'Page deletion' do
it 'has removed the deleted page correctly' do
it 'has removed the deleted page correctly', status_issue: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/921' do
initial_wiki.visit!
Page::Project::Wiki::Show.perform(&:click_edit)

View File

@ -78,6 +78,31 @@ module QA
end
end
it 'uses templating variables for metrics dashboards' do
templating_dashboard_yml = Pathname
.new(__dir__)
.join('../../../../fixtures/metrics_dashboards/templating.yml')
Resource::Repository::ProjectPush.fabricate! do |push|
push.project = @project
push.file_name = '.gitlab/dashboards/templating.yml'
push.file_content = File.read(templating_dashboard_yml)
push.commit_message = 'Add templating in dashboard file'
push.new_branch = false
end
Page::Project::Menu.perform(&:go_to_operations_metrics)
Page::Project::Operations::Metrics::Show.perform do |dashboard|
dashboard.select_dashboard('templating.yml')
expect(dashboard).to have_template_metric('CPU usage GitLab Runner')
expect(dashboard).to have_template_metric('Memory usage Postgresql')
expect(dashboard).to have_templating_variable('GitLab Runner')
expect(dashboard).to have_templating_variable('Postgresql')
end
end
private
def deploy_project_with_prometheus

View File

@ -31,7 +31,7 @@ module RuboCop
private
def allowed_foreign_key?(key)
key.type == :sym && allowed_foreign_keys.include?(key.value)
[:sym, :str].include?(key.type) && allowed_foreign_keys.include?(key.value.to_sym)
end
def allowed_foreign_keys

View File

@ -44,3 +44,4 @@ UsageData/DistinctCountByLargeForeignKey:
- :project_id
- :issue_id
- :merge_request_id
- :merge_requests.target_project_id

View File

@ -3,9 +3,9 @@
require 'spec_helper'
RSpec.describe Projects::BadgesController do
let(:project) { pipeline.project }
let!(:pipeline) { create(:ci_empty_pipeline) }
let(:user) { create(:user) }
let_it_be(:project, reload: true) { create(:project, :repository) }
let_it_be(:pipeline, reload: true) { create(:ci_empty_pipeline, project: project) }
let_it_be(:user) { create(:user) }
shared_examples 'a badge resource' do |badge_type|
context 'when pipelines are public' do
@ -137,6 +137,26 @@ RSpec.describe Projects::BadgesController do
describe '#pipeline' do
it_behaves_like 'a badge resource', :pipeline
context 'with ignore_skipped param' do
render_views
before do
pipeline.update!(status: :skipped)
project.add_maintainer(user)
sign_in(user)
end
it 'returns skipped badge if set to false' do
get_badge(:pipeline, ignore_skipped: false)
expect(response.body).to include('skipped')
end
it 'does not return skipped badge if set to true' do
get_badge(:pipeline, ignore_skipped: true)
expect(response.body).to include('unknown')
end
end
end
describe '#coverage' do
@ -148,7 +168,7 @@ RSpec.describe Projects::BadgesController do
namespace_id: project.namespace.to_param,
project_id: project,
ref: pipeline.ref
}.merge(args.slice(:style, :key_text, :key_width))
}.merge(args.slice(:style, :key_text, :key_width, :ignore_skipped))
get badge, params: params, format: :svg
end

View File

@ -22,6 +22,7 @@ FactoryBot.define do
project_statistics.build_artifacts_size = evaluator.size_multiplier * 4
project_statistics.packages_size = evaluator.size_multiplier * 5
project_statistics.snippets_size = evaluator.size_multiplier * 6
project_statistics.pipeline_artifacts_size = evaluator.size_multiplier * 7
end
end
end

View File

@ -525,6 +525,7 @@ RSpec.describe 'Admin updates settings', :clean_gitlab_redis_shared_state, :do_n
end
def check_all_events
page.check('Active')
page.check('Push')
page.check('Issue')
page.check('Confidential Issue')

View File

@ -130,24 +130,43 @@ RSpec.describe 'Issue Boards new issue', :js do
context 'group boards' do
let_it_be(:group) { create(:group, :public) }
let_it_be(:project) { create(:project, namespace: group) }
let_it_be(:project) { create(:project, :public, namespace: group) }
let_it_be(:group_board) { create(:board, group: group) }
let_it_be(:list) { create(:list, board: group_board, position: 0) }
let_it_be(:project_label) { create(:label, project: project, name: 'label') }
let_it_be(:list) { create(:list, board: group_board, label: project_label, position: 0) }
context 'for unauthorized users' do
before do
sign_in(user)
visit group_board_path(group, group_board)
wait_for_requests
context 'when backlog does not exist' do
before do
sign_in(user)
visit group_board_path(group, group_board)
wait_for_requests
end
it 'does not display new issue button in label list' do
page.within('.board.is-draggable') do
expect(page).not_to have_selector('.issue-count-badge-add-button')
end
end
end
it 'displays new issue button in open list' do
expect(first('.board')).to have_selector('.issue-count-badge-add-button', count: 1)
end
context 'when backlog list already exists' do
let!(:backlog_list) { create(:backlog_list, board: group_board) }
it 'does not display new issue button in label list' do
page.within('.board.is-draggable') do
expect(page).not_to have_selector('.issue-count-badge-add-button')
before do
sign_in(user)
visit group_board_path(group, group_board)
wait_for_requests
end
it 'displays new issue button in open list' do
expect(first('.board')).to have_selector('.issue-count-badge-add-button', count: 1)
end
it 'does not display new issue button in label list' do
page.within('.board.is-draggable') do
expect(page).not_to have_selector('.issue-count-badge-add-button')
end
end
end
end

View File

@ -296,6 +296,7 @@ RSpec.describe 'Labels Hierarchy', :js do
let(:board) { create(:board, group: parent) }
before do
stub_feature_flags(graphql_board_lists: false)
parent.add_developer(user)
visit group_board_path(parent, board)
find('.js-new-board-list').click

Some files were not shown because too many files have changed in this diff Show More