Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
2f752481c2
commit
4b9bde7848
|
|
@ -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,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -22,6 +22,10 @@ export function formatListIssues(listIssues) {
|
|||
}, {});
|
||||
}
|
||||
|
||||
export function fullBoardId(boardId) {
|
||||
return `gid://gitlab/Board/${boardId}`;
|
||||
}
|
||||
|
||||
export default {
|
||||
getMilestone,
|
||||
formatListIssues,
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
#import "./board_list.fragment.graphql"
|
||||
|
||||
mutation CreateBoardList($boardId: BoardID!, $backlog: Boolean) {
|
||||
boardListCreate(input: { boardId: $boardId, backlog: $backlog }) {
|
||||
list {
|
||||
...BoardListFragment
|
||||
}
|
||||
errors
|
||||
}
|
||||
}
|
||||
|
|
@ -4,7 +4,6 @@ fragment BoardListShared on BoardList {
|
|||
position
|
||||
listType
|
||||
collapsed
|
||||
maxIssueCount
|
||||
label {
|
||||
id
|
||||
title
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
},
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ import { inactiveId } from '~/boards/constants';
|
|||
export default () => ({
|
||||
endpoints: {},
|
||||
boardType: null,
|
||||
disabled: false,
|
||||
showPromotion: false,
|
||||
isShowingLabels: true,
|
||||
activeId: inactiveId,
|
||||
boardLists: [],
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -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`"
|
||||
|
|
|
|||
|
|
@ -35,9 +35,7 @@ function parseDatasetToProps(data) {
|
|||
} = parseBooleanInData(booleanAttributes);
|
||||
|
||||
return {
|
||||
activeToggleProps: {
|
||||
initialActivated: activated,
|
||||
},
|
||||
initialActivated: activated,
|
||||
showActive,
|
||||
type,
|
||||
triggerFieldsProps: {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
import PersistentUserCallout from '~/persistent_user_callout';
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const callout = document.querySelector('.js-service-templates-deprecated');
|
||||
PersistentUserCallout.factory(callout);
|
||||
});
|
||||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
})
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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')
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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 }
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Add ignore_skipped option for pipeline status badge
|
||||
merge_request: 28288
|
||||
author: Fabian Schneider @fabsrc
|
||||
type: added
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Add Service Templates deprecation warning banner
|
||||
merge_request: 25587
|
||||
author:
|
||||
type: changed
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Change active toggle on integration settings page to checkbox
|
||||
merge_request: 39586
|
||||
author:
|
||||
type: changed
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
title: Include Redis in Workhorse-in-test-suite integration
|
||||
merge_request: 40026
|
||||
author:
|
||||
type: other
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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:**
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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).
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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} > %{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 "We’ve been making changes to %{featureName} and we’d love your feedback %{linkStart}in this issue%{linkEnd} to help us improve the experience."
|
||||
msgstr ""
|
||||
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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 } }
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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|
|
||||
|
|
|
|||
|
|
@ -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|
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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|
|
||||
|
|
|
|||
|
|
@ -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!
|
||||
|
|
|
|||
|
|
@ -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|
|
||||
|
|
|
|||
|
|
@ -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')
|
||||
|
|
|
|||
|
|
@ -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}")
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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!
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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|
|
||||
|
|
|
|||
|
|
@ -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|
|
||||
|
|
|
|||
|
|
@ -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
|
||||
})
|
||||
|
|
|
|||
|
|
@ -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|
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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|
|
||||
|
|
|
|||
|
|
@ -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|
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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|
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -44,3 +44,4 @@ UsageData/DistinctCountByLargeForeignKey:
|
|||
- :project_id
|
||||
- :issue_id
|
||||
- :merge_request_id
|
||||
- :merge_requests.target_project_id
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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')
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
Loading…
Reference in New Issue