Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
33882b0ed1
commit
2f5c5b1081
126 changed files with 1478 additions and 958 deletions
|
@ -3,6 +3,8 @@
|
|||
stage: notify
|
||||
dependencies: []
|
||||
cache: {}
|
||||
variables:
|
||||
MERGE_REQUEST_URL: ${CI_MERGE_REQUEST_PROJECT_URL}/-/merge_requests/${CI_MERGE_REQUEST_IID}
|
||||
before_script:
|
||||
- apk update && apk add git curl bash
|
||||
|
||||
|
@ -16,8 +18,19 @@ notify-update-gitaly:
|
|||
variables:
|
||||
NOTIFY_CHANNEL: g_create_gitaly
|
||||
GITALY_UPDATE_BRANCH: release-tools/update-gitaly
|
||||
MERGE_REQUEST_URL: ${CI_MERGE_REQUEST_PROJECT_URL}/-/merge_requests/${CI_MERGE_REQUEST_IID}
|
||||
script:
|
||||
- echo "NOTIFY_CHANNEL is ${NOTIFY_CHANNEL}"
|
||||
- echo "CI_PIPELINE_URL is ${CI_PIPELINE_URL}"
|
||||
- scripts/slack ${NOTIFY_CHANNEL} "☠️ \`${GITALY_UPDATE_BRANCH}\` failed! ☠️ See ${CI_PIPELINE_URL} (triggered from ${MERGE_REQUEST_URL})" ci_failing
|
||||
- scripts/slack ${NOTIFY_CHANNEL} "☠️ \`${GITALY_UPDATE_BRANCH}\` failed! ☠️ See ${CI_PIPELINE_URL} (triggered from ${MERGE_REQUEST_URL})" ci_failing "GitLab QA Bot"
|
||||
|
||||
notify-security-pipeline:
|
||||
extends:
|
||||
- .notify-slack
|
||||
- .delivery:rules:security-pipeline-merge-result-failure
|
||||
variables:
|
||||
NOTIFY_CHANNEL: f_upcoming_release
|
||||
script:
|
||||
- echo "NOTIFY_CHANNEL is ${NOTIFY_CHANNEL}"
|
||||
- echo "CI_PIPELINE_URL is ${CI_PIPELINE_URL}"
|
||||
# <!subteam^S0127FU8PDE> mentions the `@release-managers` group
|
||||
- scripts/slack ${NOTIFY_CHANNEL} "<!subteam^S0127FU8PDE> ☠️ Pipeline for merged result failed! ☠️ See ${CI_PIPELINE_URL} (triggered from ${MERGE_REQUEST_URL})" ci_failing "GitLab Release Tools Bot"
|
||||
|
|
|
@ -73,6 +73,12 @@
|
|||
.if-rspec-fail-fast-skipped: &if-rspec-fail-fast-skipped
|
||||
if: '$CI_MERGE_REQUEST_TITLE =~ /SKIP RSPEC FAIL-FAST/'
|
||||
|
||||
# For Security merge requests, the gitlab-release-tools-bot triggers a new
|
||||
# pipeline for the "Pipelines for merged results" feature. If the pipeline
|
||||
# fails, we notify release managers.
|
||||
.if-security-pipeline-merge-result: &if-security-pipeline-merge-result
|
||||
if: '$CI_PIPELINE_SOURCE == "merge_request_event" && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == $CI_DEFAULT_BRANCH && $CI_PROJECT_NAMESPACE == "gitlab-org/security" && $GITLAB_USER_LOGIN == "gitlab-release-tools-bot"'
|
||||
|
||||
####################
|
||||
# Changes patterns #
|
||||
####################
|
||||
|
@ -285,6 +291,14 @@
|
|||
when: manual
|
||||
allow_failure: true
|
||||
|
||||
##################
|
||||
# Delivery rules #
|
||||
##################
|
||||
.delivery:rules:security-pipeline-merge-result-failure:
|
||||
rules:
|
||||
- <<: *if-security-pipeline-merge-result
|
||||
when: on_failure
|
||||
|
||||
######################
|
||||
# Dev fixtures rules #
|
||||
######################
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
* Used in the environments table and the environment detail view.
|
||||
*/
|
||||
|
||||
import $ from 'jquery';
|
||||
import { GlTooltipDirective, GlIcon } from '@gitlab/ui';
|
||||
import { s__ } from '~/locale';
|
||||
import eventHub from '../event_hub';
|
||||
|
@ -42,7 +41,7 @@ export default {
|
|||
},
|
||||
methods: {
|
||||
onClick() {
|
||||
$(this.$el).tooltip('dispose');
|
||||
this.$root.$emit('bv::hide::tooltip', this.$options.deleteEnvironmentTooltipId);
|
||||
eventHub.$emit('requestDeleteEnvironment', this.environment);
|
||||
},
|
||||
onDeleteEnvironment(environment) {
|
||||
|
@ -51,11 +50,12 @@ export default {
|
|||
}
|
||||
},
|
||||
},
|
||||
deleteEnvironmentTooltipId: 'delete-environment-button-tooltip',
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<loading-button
|
||||
v-gl-tooltip
|
||||
v-gl-tooltip="{ id: $options.deleteEnvironmentTooltipId }"
|
||||
:loading="isLoading"
|
||||
:title="title"
|
||||
:aria-label="title"
|
||||
|
|
|
@ -1,98 +0,0 @@
|
|||
const entryTypeIcons = {
|
||||
tree: 'folder',
|
||||
commit: 'archive',
|
||||
};
|
||||
|
||||
const fileTypeIcons = [
|
||||
{ extensions: ['pdf'], name: 'file-pdf-o' },
|
||||
{
|
||||
extensions: [
|
||||
'jpg',
|
||||
'jpeg',
|
||||
'jif',
|
||||
'jfif',
|
||||
'jp2',
|
||||
'jpx',
|
||||
'j2k',
|
||||
'j2c',
|
||||
'png',
|
||||
'gif',
|
||||
'tif',
|
||||
'tiff',
|
||||
'svg',
|
||||
'ico',
|
||||
'bmp',
|
||||
],
|
||||
name: 'file-image-o',
|
||||
},
|
||||
{
|
||||
extensions: ['zip', 'zipx', 'tar', 'gz', 'bz', 'bzip', 'xz', 'rar', '7z'],
|
||||
name: 'file-archive-o',
|
||||
},
|
||||
{ extensions: ['mp3', 'wma', 'ogg', 'oga', 'wav', 'flac', 'aac'], name: 'file-audio-o' },
|
||||
{
|
||||
extensions: [
|
||||
'mp4',
|
||||
'm4p',
|
||||
'm4v',
|
||||
'mpg',
|
||||
'mp2',
|
||||
'mpeg',
|
||||
'mpe',
|
||||
'mpv',
|
||||
'm2v',
|
||||
'avi',
|
||||
'mkv',
|
||||
'flv',
|
||||
'ogv',
|
||||
'mov',
|
||||
'3gp',
|
||||
'3g2',
|
||||
],
|
||||
name: 'file-video-o',
|
||||
},
|
||||
{ extensions: ['doc', 'dot', 'docx', 'docm', 'dotx', 'dotm', 'docb'], name: 'file-word-o' },
|
||||
{
|
||||
extensions: [
|
||||
'xls',
|
||||
'xlt',
|
||||
'xlm',
|
||||
'xlsx',
|
||||
'xlsm',
|
||||
'xltx',
|
||||
'xltm',
|
||||
'xlsb',
|
||||
'xla',
|
||||
'xlam',
|
||||
'xll',
|
||||
'xlw',
|
||||
],
|
||||
name: 'file-excel-o',
|
||||
},
|
||||
{
|
||||
extensions: [
|
||||
'ppt',
|
||||
'pot',
|
||||
'pps',
|
||||
'pptx',
|
||||
'pptm',
|
||||
'potx',
|
||||
'potm',
|
||||
'ppam',
|
||||
'ppsx',
|
||||
'ppsm',
|
||||
'sldx',
|
||||
'sldm',
|
||||
],
|
||||
name: 'file-powerpoint-o',
|
||||
},
|
||||
];
|
||||
|
||||
export const getIconName = (type, path) => {
|
||||
if (entryTypeIcons[type]) return entryTypeIcons[type];
|
||||
|
||||
const extension = path.split('.').pop();
|
||||
const file = fileTypeIcons.find(t => t.extensions.some(ext => ext === extension));
|
||||
|
||||
return file ? file.name : 'file-text-o';
|
||||
};
|
|
@ -1,37 +0,0 @@
|
|||
import { __ } from '~/locale';
|
||||
import { parseUrlPathname, parseUrl } from '../lib/utils/common_utils';
|
||||
|
||||
function swapActiveState(activateBtn, deactivateBtn) {
|
||||
activateBtn.classList.add('is-active');
|
||||
deactivateBtn.classList.remove('is-active');
|
||||
}
|
||||
|
||||
export default () => {
|
||||
const shareBtn = document.querySelector('.js-share-btn');
|
||||
|
||||
if (shareBtn) {
|
||||
const embedBtn = document.querySelector('.js-embed-btn');
|
||||
const snippetUrlArea = document.querySelector('.js-snippet-url-area');
|
||||
const embedAction = document.querySelector('.js-embed-action');
|
||||
const dataUrl = snippetUrlArea.getAttribute('data-url');
|
||||
|
||||
snippetUrlArea.addEventListener('click', () => snippetUrlArea.select());
|
||||
|
||||
shareBtn.addEventListener('click', () => {
|
||||
swapActiveState(shareBtn, embedBtn);
|
||||
snippetUrlArea.value = dataUrl;
|
||||
embedAction.innerText = __('Share');
|
||||
});
|
||||
|
||||
embedBtn.addEventListener('click', () => {
|
||||
const parser = parseUrl(dataUrl);
|
||||
const url = `${parser.origin + parseUrlPathname(dataUrl)}`;
|
||||
const params = parser.search;
|
||||
const scriptTag = `<script src="${url}.js${params}"></script>`;
|
||||
|
||||
swapActiveState(embedBtn, shareBtn);
|
||||
snippetUrlArea.value = scriptTag;
|
||||
embedAction.innerText = __('Embed');
|
||||
});
|
||||
}
|
||||
};
|
|
@ -1,48 +1,13 @@
|
|||
if (!gon.features.snippetsVue) {
|
||||
const LineHighlighterModule = import('~/line_highlighter');
|
||||
const BlobViewerModule = import('~/blob/viewer');
|
||||
const ZenModeModule = import('~/zen_mode');
|
||||
const SnippetEmbedModule = import('~/snippet/snippet_embed');
|
||||
const initNotesModule = import('~/init_notes');
|
||||
const loadAwardsHandlerModule = import('~/awards_handler');
|
||||
import initNotes from '~/init_notes';
|
||||
import loadAwardsHandler from '~/awards_handler';
|
||||
import { SnippetShowInit } from '~/snippets';
|
||||
import ZenMode from '~/zen_mode';
|
||||
|
||||
Promise.all([
|
||||
LineHighlighterModule,
|
||||
BlobViewerModule,
|
||||
ZenModeModule,
|
||||
SnippetEmbedModule,
|
||||
initNotesModule,
|
||||
loadAwardsHandlerModule,
|
||||
])
|
||||
.then(
|
||||
([
|
||||
{ default: LineHighlighter },
|
||||
{ default: BlobViewer },
|
||||
{ default: ZenMode },
|
||||
{ default: SnippetEmbed },
|
||||
{ default: initNotes },
|
||||
{ default: loadAwardsHandler },
|
||||
]) => {
|
||||
new LineHighlighter(); // eslint-disable-line no-new
|
||||
new BlobViewer(); // eslint-disable-line no-new
|
||||
new ZenMode(); // eslint-disable-line no-new
|
||||
SnippetEmbed();
|
||||
initNotes();
|
||||
loadAwardsHandler();
|
||||
},
|
||||
)
|
||||
.catch(() => {});
|
||||
} else {
|
||||
import('~/snippets')
|
||||
.then(({ SnippetShowInit }) => {
|
||||
SnippetShowInit();
|
||||
})
|
||||
.then(() => {
|
||||
return Promise.all([import('~/init_notes'), import('~/awards_handler')]);
|
||||
})
|
||||
.then(([{ default: initNotes }, { default: loadAwardsHandler }]) => {
|
||||
initNotes();
|
||||
loadAwardsHandler();
|
||||
})
|
||||
.catch(() => {});
|
||||
}
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
SnippetShowInit();
|
||||
initNotes();
|
||||
loadAwardsHandler();
|
||||
|
||||
// eslint-disable-next-line no-new
|
||||
new ZenMode();
|
||||
});
|
||||
|
|
|
@ -60,7 +60,7 @@ export default {
|
|||
class="gl-dropdown-text-py-0 gl-dropdown-text-block"
|
||||
data-testid="input"
|
||||
>
|
||||
<gl-form-input-group :value="value" readonly select-on-click>
|
||||
<gl-form-input-group :value="value" readonly select-on-click :aria-label="name">
|
||||
<template #append>
|
||||
<gl-button
|
||||
v-gl-tooltip.hover
|
||||
|
|
|
@ -0,0 +1,121 @@
|
|||
import { deprecatedCreateFlash as createFlash } from '~/flash';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { __ } from '~/locale';
|
||||
import Api from '~/api';
|
||||
import * as types from './mutation_types';
|
||||
|
||||
export const setEndpoints = ({ commit }, params) => {
|
||||
const { milestonesEndpoint, labelsEndpoint, groupEndpoint, projectEndpoint } = params;
|
||||
commit(types.SET_MILESTONES_ENDPOINT, milestonesEndpoint);
|
||||
commit(types.SET_LABELS_ENDPOINT, labelsEndpoint);
|
||||
commit(types.SET_GROUP_ENDPOINT, groupEndpoint);
|
||||
commit(types.SET_PROJECT_ENDPOINT, projectEndpoint);
|
||||
};
|
||||
|
||||
export function fetchBranches({ commit, state }, search = '') {
|
||||
const { projectEndpoint } = state;
|
||||
commit(types.REQUEST_BRANCHES);
|
||||
|
||||
return Api.branches(projectEndpoint, search)
|
||||
.then(response => {
|
||||
commit(types.RECEIVE_BRANCHES_SUCCESS, response.data);
|
||||
return response;
|
||||
})
|
||||
.catch(({ response }) => {
|
||||
const { status } = response;
|
||||
commit(types.RECEIVE_BRANCHES_ERROR, status);
|
||||
createFlash(__('Failed to load branches. Please try again.'));
|
||||
});
|
||||
}
|
||||
|
||||
export const fetchMilestones = ({ commit, state }, search_title = '') => {
|
||||
commit(types.REQUEST_MILESTONES);
|
||||
const { milestonesEndpoint } = state;
|
||||
|
||||
return axios
|
||||
.get(milestonesEndpoint, { params: { search_title } })
|
||||
.then(response => {
|
||||
commit(types.RECEIVE_MILESTONES_SUCCESS, response.data);
|
||||
return response;
|
||||
})
|
||||
.catch(({ response }) => {
|
||||
const { status } = response;
|
||||
commit(types.RECEIVE_MILESTONES_ERROR, status);
|
||||
createFlash(__('Failed to load milestones. Please try again.'));
|
||||
});
|
||||
};
|
||||
|
||||
export const fetchLabels = ({ commit, state }, search = '') => {
|
||||
commit(types.REQUEST_LABELS);
|
||||
|
||||
return axios
|
||||
.get(state.labelsEndpoint, { params: { search } })
|
||||
.then(response => {
|
||||
commit(types.RECEIVE_LABELS_SUCCESS, response.data);
|
||||
return response;
|
||||
})
|
||||
.catch(({ response }) => {
|
||||
const { status } = response;
|
||||
commit(types.RECEIVE_LABELS_ERROR, status);
|
||||
createFlash(__('Failed to load labels. Please try again.'));
|
||||
});
|
||||
};
|
||||
|
||||
function fetchUser(options = {}) {
|
||||
const { commit, projectEndpoint, groupEndpoint, query, action, errorMessage } = options;
|
||||
commit(`REQUEST_${action}`);
|
||||
|
||||
let fetchUserPromise;
|
||||
if (projectEndpoint) {
|
||||
fetchUserPromise = Api.projectUsers(projectEndpoint, query).then(data => ({ data }));
|
||||
} else {
|
||||
fetchUserPromise = Api.groupMembers(groupEndpoint, { query });
|
||||
}
|
||||
|
||||
return fetchUserPromise
|
||||
.then(response => {
|
||||
commit(`RECEIVE_${action}_SUCCESS`, response.data);
|
||||
return response;
|
||||
})
|
||||
.catch(({ response }) => {
|
||||
const { status } = response;
|
||||
commit(`RECEIVE_${action}_ERROR`, status);
|
||||
createFlash(errorMessage);
|
||||
});
|
||||
}
|
||||
|
||||
export const fetchAuthors = ({ commit, state }, query = '') => {
|
||||
const { projectEndpoint, groupEndpoint } = state;
|
||||
|
||||
return fetchUser({
|
||||
commit,
|
||||
query,
|
||||
projectEndpoint,
|
||||
groupEndpoint,
|
||||
action: 'AUTHORS',
|
||||
errorMessage: __('Failed to load authors. Please try again.'),
|
||||
});
|
||||
};
|
||||
|
||||
export const fetchAssignees = ({ commit, state }, query = '') => {
|
||||
const { projectEndpoint, groupEndpoint } = state;
|
||||
|
||||
return fetchUser({
|
||||
commit,
|
||||
query,
|
||||
projectEndpoint,
|
||||
groupEndpoint,
|
||||
action: 'ASSIGNEES',
|
||||
errorMessage: __('Failed to load assignees. Please try again.'),
|
||||
});
|
||||
};
|
||||
|
||||
export const setFilters = ({ commit, dispatch }, filters) => {
|
||||
commit(types.SET_SELECTED_FILTERS, filters);
|
||||
|
||||
return dispatch('setFilters', filters, { root: true });
|
||||
};
|
||||
|
||||
export const initialize = ({ commit }, initialFilters) => {
|
||||
commit(types.SET_SELECTED_FILTERS, initialFilters);
|
||||
};
|
|
@ -0,0 +1,10 @@
|
|||
import state from './state';
|
||||
import * as actions from './actions';
|
||||
import mutations from './mutations';
|
||||
|
||||
export default {
|
||||
namespaced: true,
|
||||
actions,
|
||||
mutations,
|
||||
state: state(),
|
||||
};
|
|
@ -0,0 +1,26 @@
|
|||
export const SET_MILESTONES_ENDPOINT = 'SET_MILESTONES_ENDPOINT';
|
||||
export const SET_LABELS_ENDPOINT = 'SET_LABELS_ENDPOINT';
|
||||
export const SET_GROUP_ENDPOINT = 'SET_GROUP_ENDPOINT';
|
||||
export const SET_PROJECT_ENDPOINT = 'SET_PROJECT_ENDPOINT';
|
||||
|
||||
export const REQUEST_BRANCHES = 'REQUEST_BRANCHES';
|
||||
export const RECEIVE_BRANCHES_SUCCESS = 'RECEIVE_BRANCHES_SUCCESS';
|
||||
export const RECEIVE_BRANCHES_ERROR = 'RECEIVE_BRANCHES_ERROR';
|
||||
|
||||
export const REQUEST_MILESTONES = 'REQUEST_MILESTONES';
|
||||
export const RECEIVE_MILESTONES_SUCCESS = 'RECEIVE_MILESTONES_SUCCESS';
|
||||
export const RECEIVE_MILESTONES_ERROR = 'RECEIVE_MILESTONES_ERROR';
|
||||
|
||||
export const REQUEST_LABELS = 'REQUEST_LABELS';
|
||||
export const RECEIVE_LABELS_SUCCESS = 'RECEIVE_LABELS_SUCCESS';
|
||||
export const RECEIVE_LABELS_ERROR = 'RECEIVE_LABELS_ERROR';
|
||||
|
||||
export const REQUEST_AUTHORS = 'REQUEST_AUTHORS';
|
||||
export const RECEIVE_AUTHORS_SUCCESS = 'RECEIVE_AUTHORS_SUCCESS';
|
||||
export const RECEIVE_AUTHORS_ERROR = 'RECEIVE_AUTHORS_ERROR';
|
||||
|
||||
export const REQUEST_ASSIGNEES = 'REQUEST_ASSIGNEES';
|
||||
export const RECEIVE_ASSIGNEES_SUCCESS = 'RECEIVE_ASSIGNEES_SUCCESS';
|
||||
export const RECEIVE_ASSIGNEES_ERROR = 'RECEIVE_ASSIGNEES_ERROR';
|
||||
|
||||
export const SET_SELECTED_FILTERS = 'SET_SELECTED_FILTERS';
|
|
@ -0,0 +1,109 @@
|
|||
import * as types from './mutation_types';
|
||||
|
||||
export default {
|
||||
[types.SET_SELECTED_FILTERS](state, params) {
|
||||
const {
|
||||
selectedSourceBranch = null,
|
||||
selectedSourceBranchList = [],
|
||||
selectedTargetBranch = null,
|
||||
selectedTargetBranchList = [],
|
||||
selectedAuthor = null,
|
||||
selectedAuthorList = [],
|
||||
selectedMilestone = null,
|
||||
selectedMilestoneList = [],
|
||||
selectedAssignee = null,
|
||||
selectedAssigneeList = [],
|
||||
selectedLabel = null,
|
||||
selectedLabelList = [],
|
||||
} = params;
|
||||
state.branches.source.selected = selectedSourceBranch;
|
||||
state.branches.source.selectedList = selectedSourceBranchList;
|
||||
state.branches.target.selected = selectedTargetBranch;
|
||||
state.branches.target.selectedList = selectedTargetBranchList;
|
||||
state.authors.selected = selectedAuthor;
|
||||
state.authors.selectedList = selectedAuthorList;
|
||||
state.assignees.selected = selectedAssignee;
|
||||
state.assignees.selectedList = selectedAssigneeList;
|
||||
state.milestones.selected = selectedMilestone;
|
||||
state.milestones.selectedList = selectedMilestoneList;
|
||||
state.labels.selected = selectedLabel;
|
||||
state.labels.selectedList = selectedLabelList;
|
||||
},
|
||||
[types.SET_MILESTONES_ENDPOINT](state, milestonesEndpoint) {
|
||||
state.milestonesEndpoint = milestonesEndpoint;
|
||||
},
|
||||
[types.SET_LABELS_ENDPOINT](state, labelsEndpoint) {
|
||||
state.labelsEndpoint = labelsEndpoint;
|
||||
},
|
||||
[types.SET_GROUP_ENDPOINT](state, groupEndpoint) {
|
||||
state.groupEndpoint = groupEndpoint;
|
||||
},
|
||||
[types.SET_PROJECT_ENDPOINT](state, projectEndpoint) {
|
||||
state.projectEndpoint = projectEndpoint;
|
||||
},
|
||||
[types.REQUEST_MILESTONES](state) {
|
||||
state.milestones.isLoading = true;
|
||||
},
|
||||
[types.RECEIVE_MILESTONES_SUCCESS](state, data) {
|
||||
state.milestones.isLoading = false;
|
||||
state.milestones.data = data;
|
||||
state.milestones.errorCode = null;
|
||||
},
|
||||
[types.RECEIVE_MILESTONES_ERROR](state, errorCode) {
|
||||
state.milestones.isLoading = false;
|
||||
state.milestones.errorCode = errorCode;
|
||||
state.milestones.data = [];
|
||||
},
|
||||
[types.REQUEST_LABELS](state) {
|
||||
state.labels.isLoading = true;
|
||||
},
|
||||
[types.RECEIVE_LABELS_SUCCESS](state, data) {
|
||||
state.labels.isLoading = false;
|
||||
state.labels.data = data;
|
||||
state.labels.errorCode = null;
|
||||
},
|
||||
[types.RECEIVE_LABELS_ERROR](state, errorCode) {
|
||||
state.labels.isLoading = false;
|
||||
state.labels.errorCode = errorCode;
|
||||
state.labels.data = [];
|
||||
},
|
||||
[types.REQUEST_AUTHORS](state) {
|
||||
state.authors.isLoading = true;
|
||||
},
|
||||
[types.RECEIVE_AUTHORS_SUCCESS](state, data) {
|
||||
state.authors.isLoading = false;
|
||||
state.authors.data = data;
|
||||
state.authors.errorCode = null;
|
||||
},
|
||||
[types.RECEIVE_AUTHORS_ERROR](state, errorCode) {
|
||||
state.authors.isLoading = false;
|
||||
state.authors.errorCode = errorCode;
|
||||
state.authors.data = [];
|
||||
},
|
||||
[types.REQUEST_ASSIGNEES](state) {
|
||||
state.assignees.isLoading = true;
|
||||
},
|
||||
[types.RECEIVE_ASSIGNEES_SUCCESS](state, data) {
|
||||
state.assignees.isLoading = false;
|
||||
state.assignees.data = data;
|
||||
state.assignees.errorCode = null;
|
||||
},
|
||||
[types.RECEIVE_ASSIGNEES_ERROR](state, errorCode) {
|
||||
state.assignees.isLoading = false;
|
||||
state.assignees.errorCode = errorCode;
|
||||
state.assignees.data = [];
|
||||
},
|
||||
[types.REQUEST_BRANCHES](state) {
|
||||
state.branches.isLoading = true;
|
||||
},
|
||||
[types.RECEIVE_BRANCHES_SUCCESS](state, data) {
|
||||
state.branches.isLoading = false;
|
||||
state.branches.data = data;
|
||||
state.branches.errorCode = null;
|
||||
},
|
||||
[types.RECEIVE_BRANCHES_ERROR](state, errorCode) {
|
||||
state.branches.isLoading = false;
|
||||
state.branches.errorCode = errorCode;
|
||||
state.branches.data = [];
|
||||
},
|
||||
};
|
|
@ -0,0 +1,47 @@
|
|||
export default () => ({
|
||||
milestonesEndpoint: '',
|
||||
labelsEndpoint: '',
|
||||
groupEndpoint: '',
|
||||
projectEndpoint: '',
|
||||
branches: {
|
||||
isLoading: false,
|
||||
errorCode: null,
|
||||
data: [],
|
||||
source: {
|
||||
selected: null,
|
||||
selectedList: [],
|
||||
},
|
||||
target: {
|
||||
selected: null,
|
||||
selectedList: [],
|
||||
},
|
||||
},
|
||||
milestones: {
|
||||
isLoading: false,
|
||||
errorCode: null,
|
||||
data: [],
|
||||
selected: null,
|
||||
selectedList: [],
|
||||
},
|
||||
labels: {
|
||||
isLoading: false,
|
||||
errorCode: null,
|
||||
data: [],
|
||||
selected: null,
|
||||
selectedList: [],
|
||||
},
|
||||
authors: {
|
||||
isLoading: false,
|
||||
errorCode: null,
|
||||
data: [],
|
||||
selected: null,
|
||||
selectedList: [],
|
||||
},
|
||||
assignees: {
|
||||
isLoading: false,
|
||||
errorCode: null,
|
||||
data: [],
|
||||
selected: null,
|
||||
selectedList: [],
|
||||
},
|
||||
});
|
|
@ -18,14 +18,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
.markdown-snippet-copy {
|
||||
position: fixed;
|
||||
top: -10px;
|
||||
left: -10px;
|
||||
max-height: 0;
|
||||
max-width: 0;
|
||||
}
|
||||
|
||||
.snippet-file-content {
|
||||
border-radius: 3px;
|
||||
|
||||
|
@ -45,21 +37,6 @@
|
|||
min-height: $header-height;
|
||||
}
|
||||
|
||||
.snippet-actions {
|
||||
@include media-breakpoint-up(sm) {
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
|
||||
.snippet-scope-menu .btn-success {
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.embed-snippet {
|
||||
padding-right: 0;
|
||||
padding-top: $gl-padding;
|
||||
|
||||
.embed-toggle-list li button {
|
||||
padding: 8px 40px;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ class Projects::AutocompleteSourcesController < Projects::ApplicationController
|
|||
private
|
||||
|
||||
def autocomplete_service
|
||||
@autocomplete_service ||= ::Projects::AutocompleteService.new(@project, current_user)
|
||||
@autocomplete_service ||= ::Projects::AutocompleteService.new(@project, current_user, params)
|
||||
end
|
||||
|
||||
def target
|
||||
|
|
|
@ -9,6 +9,7 @@ module Projects
|
|||
respond_to :json, only: [:reset_alerting_token, :reset_pagerduty_token]
|
||||
|
||||
helper_method :error_tracking_setting
|
||||
helper_method :tracing_setting
|
||||
|
||||
def update
|
||||
result = ::Projects::Operations::UpdateService.new(project, current_user, update_params).execute
|
||||
|
@ -17,15 +18,6 @@ module Projects
|
|||
render_update_response(result)
|
||||
end
|
||||
|
||||
# overridden in EE
|
||||
def track_events(result)
|
||||
if result[:status] == :success
|
||||
::Gitlab::Tracking::IncidentManagement.track_from_params(
|
||||
update_params[:incident_management_setting_attributes]
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def reset_alerting_token
|
||||
result = ::Projects::Operations::UpdateService
|
||||
.new(project, current_user, alerting_params)
|
||||
|
@ -55,6 +47,24 @@ module Projects
|
|||
|
||||
private
|
||||
|
||||
def track_events(result)
|
||||
if result[:status] == :success
|
||||
::Gitlab::Tracking::IncidentManagement.track_from_params(
|
||||
update_params[:incident_management_setting_attributes]
|
||||
)
|
||||
track_tracing_external_url
|
||||
end
|
||||
end
|
||||
|
||||
def track_tracing_external_url
|
||||
external_url_previous_change = project&.tracing_setting&.external_url_previous_change
|
||||
|
||||
return unless external_url_previous_change
|
||||
return unless external_url_previous_change[0].blank? && external_url_previous_change[1].present?
|
||||
|
||||
::Gitlab::Tracking.event('project:operations:tracing', 'external_url_populated')
|
||||
end
|
||||
|
||||
def alerting_params
|
||||
{ alerting_setting_attributes: { regenerate_token: true } }
|
||||
end
|
||||
|
@ -106,6 +116,10 @@ module Projects
|
|||
project.build_error_tracking_setting
|
||||
end
|
||||
|
||||
def tracing_setting
|
||||
@tracing_setting ||= project.tracing_setting || project.build_tracing_setting
|
||||
end
|
||||
|
||||
def update_params
|
||||
params.require(:project).permit(permitted_project_params)
|
||||
end
|
||||
|
@ -124,7 +138,8 @@ module Projects
|
|||
project: [:slug, :name, :organization_slug, :organization_name]
|
||||
],
|
||||
|
||||
grafana_integration_attributes: [:token, :grafana_url, :enabled]
|
||||
grafana_integration_attributes: [:token, :grafana_url, :enabled],
|
||||
tracing_setting_attributes: [:external_url]
|
||||
}
|
||||
|
||||
if Feature.enabled?(:settings_operations_prometheus_service, project)
|
||||
|
|
|
@ -159,6 +159,7 @@ module NotesHelper
|
|||
members: autocomplete,
|
||||
issues: autocomplete,
|
||||
mergeRequests: autocomplete,
|
||||
vulnerabilities: autocomplete,
|
||||
epics: autocomplete,
|
||||
milestones: autocomplete,
|
||||
labels: autocomplete
|
||||
|
|
|
@ -32,31 +32,6 @@ module SnippetsHelper
|
|||
end
|
||||
end
|
||||
|
||||
# Get an array of line numbers surrounding a matching
|
||||
# line, bounded by min/max.
|
||||
#
|
||||
# @returns Array of line numbers
|
||||
def bounded_line_numbers(line, min, max, surrounding_lines)
|
||||
lower = line - surrounding_lines > min ? line - surrounding_lines : min
|
||||
upper = line + surrounding_lines < max ? line + surrounding_lines : max
|
||||
(lower..upper).to_a
|
||||
end
|
||||
|
||||
def snippet_embed_tag(snippet)
|
||||
content_tag(:script, nil, src: gitlab_snippet_url(snippet, format: :js))
|
||||
end
|
||||
|
||||
def snippet_embed_input(snippet)
|
||||
content_tag(:input,
|
||||
nil,
|
||||
type: :text,
|
||||
readonly: true,
|
||||
class: 'js-snippet-url-area snippet-embed-input form-control',
|
||||
data: { url: gitlab_snippet_url(snippet) },
|
||||
value: snippet_embed_tag(snippet),
|
||||
autocomplete: 'off')
|
||||
end
|
||||
|
||||
def snippet_badge(snippet)
|
||||
return unless attrs = snippet_badge_attributes(snippet)
|
||||
|
||||
|
|
|
@ -23,8 +23,6 @@ module VisibilityLevelHelper
|
|||
project_visibility_level_description(level)
|
||||
when Group
|
||||
group_visibility_level_description(level)
|
||||
when Snippet
|
||||
snippet_visibility_level_description(level, form_model)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -50,21 +48,6 @@ module VisibilityLevelHelper
|
|||
end
|
||||
end
|
||||
|
||||
def snippet_visibility_level_description(level, snippet = nil)
|
||||
case level
|
||||
when Gitlab::VisibilityLevel::PRIVATE
|
||||
if snippet.is_a? ProjectSnippet
|
||||
_("The snippet is visible only to project members.")
|
||||
else
|
||||
_("The snippet is visible only to me.")
|
||||
end
|
||||
when Gitlab::VisibilityLevel::INTERNAL
|
||||
_("The snippet is visible to any logged in user.")
|
||||
when Gitlab::VisibilityLevel::PUBLIC
|
||||
_("The snippet can be accessed without any authentication.")
|
||||
end
|
||||
end
|
||||
|
||||
# Note: these messages closely mirror the form validation strings found in the project
|
||||
# model and any changes or additons to these may also need to be made there.
|
||||
def disallowed_project_visibility_level_description(level, project)
|
||||
|
|
|
@ -22,7 +22,7 @@ module Mentionable
|
|||
def self.default_pattern
|
||||
strong_memoize(:default_pattern) do
|
||||
issue_pattern = Issue.reference_pattern
|
||||
link_patterns = Regexp.union([Issue, Commit, MergeRequest, Epic].map(&:link_reference_pattern).compact)
|
||||
link_patterns = Regexp.union([Issue, Commit, MergeRequest, Epic, Vulnerability].map(&:link_reference_pattern).compact)
|
||||
reference_pattern(link_patterns, issue_pattern)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -5,6 +5,10 @@
|
|||
class Vulnerability < ApplicationRecord
|
||||
include IgnorableColumns
|
||||
|
||||
def self.link_reference_pattern
|
||||
nil
|
||||
end
|
||||
|
||||
def self.reference_prefix
|
||||
'+'
|
||||
end
|
||||
|
|
|
@ -63,7 +63,7 @@ module Issues
|
|||
end
|
||||
|
||||
def queue_copy_designs
|
||||
return unless copy_designs_enabled? && original_entity.designs.present?
|
||||
return unless original_entity.designs.present?
|
||||
|
||||
response = DesignManagement::CopyDesignCollection::QueueService.new(
|
||||
current_user,
|
||||
|
@ -74,11 +74,6 @@ module Issues
|
|||
log_error(response.message) if response.error?
|
||||
end
|
||||
|
||||
def copy_designs_enabled?
|
||||
Feature.enabled?(:design_management_copy_designs, old_project) &&
|
||||
Feature.enabled?(:design_management_copy_designs, target_project)
|
||||
end
|
||||
|
||||
def mark_as_moved
|
||||
original_entity.update(moved_to: new_entity)
|
||||
end
|
||||
|
|
|
@ -1,36 +0,0 @@
|
|||
- return unless current_user
|
||||
|
||||
.d-none.d-sm-block
|
||||
- if can?(current_user, :update_snippet, @snippet)
|
||||
= link_to edit_project_snippet_path(@project, @snippet), class: "btn btn-grouped" do
|
||||
= _('Edit')
|
||||
- if can?(current_user, :admin_snippet, @snippet)
|
||||
= link_to project_snippet_path(@project, @snippet), method: :delete, data: { confirm: _("Are you sure?") }, class: "btn btn-grouped btn-inverted btn-remove", title: _('Delete Snippet') do
|
||||
= _('Delete')
|
||||
- if can?(current_user, :create_snippet, @project)
|
||||
= link_to new_project_snippet_path(@project), class: 'btn btn-grouped btn-inverted btn-success', title: _("New snippet") do
|
||||
= _('New snippet')
|
||||
- if @snippet.submittable_as_spam_by?(current_user)
|
||||
= link_to _('Submit as spam'), mark_as_spam_project_snippet_path(@project, @snippet), method: :post, class: 'btn btn-grouped btn-spam', title: _('Submit as spam')
|
||||
- if can?(current_user, :create_snippet, @project) || can?(current_user, :update_snippet, @snippet)
|
||||
.d-block.d-sm-none.dropdown
|
||||
%button.btn.btn-default.btn-block.gl-mb-0.gl-mt-2{ data: { toggle: "dropdown" } }
|
||||
= _('Options')
|
||||
= icon('caret-down')
|
||||
.dropdown-menu.dropdown-menu-full-width
|
||||
%ul
|
||||
- if can?(current_user, :create_snippet, @project)
|
||||
%li
|
||||
= link_to new_project_snippet_path(@project), title: _("New snippet") do
|
||||
= _('New snippet')
|
||||
- if can?(current_user, :admin_snippet, @snippet)
|
||||
%li
|
||||
= link_to project_snippet_path(@project, @snippet), method: :delete, data: { confirm: _("Are you sure?") }, title: _('Delete Snippet') do
|
||||
= _('Delete')
|
||||
- if can?(current_user, :update_snippet, @snippet)
|
||||
%li
|
||||
= link_to edit_project_snippet_path(@project, @snippet) do
|
||||
= _('Edit')
|
||||
- if @snippet.submittable_as_spam_by?(current_user)
|
||||
%li
|
||||
= link_to _('Submit as spam'), mark_as_spam_project_snippet_path(@project, @snippet), method: :post
|
|
@ -3,13 +3,7 @@
|
|||
- breadcrumb_title @snippet.to_reference
|
||||
- page_title "#{@snippet.title} (#{@snippet.to_reference})", _("Snippets")
|
||||
|
||||
- if Feature.enabled?(:snippets_vue, default_enabled: true)
|
||||
#js-snippet-view{ data: {'qa-selector': 'snippet_view', 'snippet-gid': @snippet.to_global_id} }
|
||||
- else
|
||||
= render 'shared/snippets/header'
|
||||
|
||||
.project-snippets
|
||||
= render 'shared/snippets/blob', blob: @blob
|
||||
#js-snippet-view{ data: {'qa-selector': 'snippet_view', 'snippet-gid': @snippet.to_global_id} }
|
||||
|
||||
.row-content-block.top-block.content-component-block
|
||||
= render 'award_emoji/awards_block', awardable: @snippet, inline: true
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
%article.file-holder.snippet-file-content
|
||||
.js-file-title.file-title-flex-parent
|
||||
= render 'projects/blob/header_content', blob: blob
|
||||
|
||||
.file-actions.d-none.d-sm-block
|
||||
= render 'projects/blob/viewer_switcher', blob: blob
|
||||
|
||||
.btn-group{ role: "group" }<
|
||||
= copy_blob_source_button(blob)
|
||||
= open_raw_blob_button(blob)
|
||||
= download_raw_snippet_button(@snippet)
|
||||
|
||||
= render 'projects/blob/content', blob: blob
|
|
@ -1,45 +0,0 @@
|
|||
.detail-page-header
|
||||
.detail-page-header-body
|
||||
.snippet-box.has-tooltip.inline.gl-mr-2{ title: snippet_visibility_level_description(@snippet.visibility_level, @snippet), data: { container: "body" } }
|
||||
%span.sr-only
|
||||
= visibility_level_label(@snippet.visibility_level)
|
||||
= visibility_level_icon(@snippet.visibility_level)
|
||||
%span.creator
|
||||
= s_('Snippets|Authored %{time_ago} by %{author}').html_safe % { time_ago: time_ago_with_tooltip(@snippet.created_at, placement: 'bottom', html_class: 'snippet_updated_ago'), author: link_to_member(@project, @snippet.author, size: 24, author_class: "author item-title", avatar_class: "d-none d-sm-inline") + user_status(@snippet.author) }
|
||||
|
||||
.detail-page-header-actions
|
||||
- if @snippet.project_id?
|
||||
= render "projects/snippets/actions"
|
||||
- else
|
||||
= render "snippets/actions"
|
||||
|
||||
.snippet-header.limited-header-width
|
||||
%h2.snippet-title.gl-mt-0.mb-3
|
||||
= markdown_field(@snippet, :title)
|
||||
|
||||
- if @snippet.description.present?
|
||||
.description
|
||||
.md
|
||||
= markdown_field(@snippet, :description)
|
||||
|
||||
- if @snippet.updated_at != @snippet.created_at
|
||||
= edited_time_ago_with_tooltip(@snippet, placement: 'bottom', exclude_author: true)
|
||||
|
||||
- if @snippet.embeddable?
|
||||
.embed-snippet
|
||||
.input-group
|
||||
.input-group-prepend
|
||||
%button.btn.gl-button.btn-svg.embed-toggle.input-group-text{ 'data-toggle': 'dropdown', type: 'button' }
|
||||
%span.js-embed-action= _("Embed")
|
||||
= sprite_icon('angle-down', size: 12, css_class: 'caret-down')
|
||||
%ul.dropdown-menu.dropdown-menu-selectable.embed-toggle-list
|
||||
%li
|
||||
%button.js-embed-btn.btn.gl-button.btn-default-tertiary.is-active{ type: 'button' }
|
||||
%strong.embed-toggle-list-item= _("Embed")
|
||||
%li
|
||||
%button.js-share-btn.btn.gl-button.btn-default-tertiary{ type: 'button' }
|
||||
%strong.embed-toggle-list-item= _("Share")
|
||||
= snippet_embed_input(@snippet)
|
||||
.input-group-append
|
||||
= clipboard_button(title: _('Copy'), class: 'js-clipboard-btn snippet-clipboard-btn btn btn-default', target: '.js-snippet-url-area')
|
||||
.clearfix
|
|
@ -1,35 +0,0 @@
|
|||
- return unless current_user
|
||||
|
||||
.d-none.d-sm-block
|
||||
- if can?(current_user, :update_snippet, @snippet)
|
||||
= link_to edit_snippet_path(@snippet), class: "btn btn-grouped" do
|
||||
= _("Edit")
|
||||
- if can?(current_user, :admin_snippet, @snippet)
|
||||
= link_to gitlab_snippet_path(@snippet), method: :delete, data: { confirm: _("Are you sure?") }, class: "btn btn-grouped btn-inverted btn-remove", title: _('Delete Snippet') do
|
||||
= _("Delete")
|
||||
- if can?(current_user, :create_snippet)
|
||||
= link_to new_snippet_path, class: "btn btn-grouped btn-success btn-inverted", title: _("New snippet") do
|
||||
= _("New snippet")
|
||||
- if @snippet.submittable_as_spam_by?(current_user)
|
||||
= link_to _('Submit as spam'), mark_as_spam_snippet_path(@snippet), method: :post, class: 'btn btn-grouped btn-spam', title: _('Submit as spam')
|
||||
.d-block.d-sm-none.dropdown
|
||||
%button.btn.btn-default.btn-block.gl-mb-0.gl-mt-2{ data: { toggle: "dropdown" } }
|
||||
= _("Options")
|
||||
= icon('caret-down')
|
||||
.dropdown-menu.dropdown-menu-full-width
|
||||
%ul
|
||||
- if can?(current_user, :create_snippet)
|
||||
%li
|
||||
= link_to new_snippet_path, title: _("New snippet") do
|
||||
= _("New snippet")
|
||||
- if can?(current_user, :admin_snippet, @snippet)
|
||||
%li
|
||||
= link_to gitlab_snippet_path(@snippet), method: :delete, data: { confirm: _("Are you sure?") }, title: _('Delete Snippet') do
|
||||
= _("Delete")
|
||||
- if can?(current_user, :update_snippet, @snippet)
|
||||
%li
|
||||
= link_to edit_snippet_path(@snippet) do
|
||||
= _("Edit")
|
||||
- if @snippet.submittable_as_spam_by?(current_user)
|
||||
%li
|
||||
= link_to _('Submit as spam'), mark_as_spam_snippet_path(@snippet), method: :post
|
|
@ -4,13 +4,7 @@
|
|||
- breadcrumb_title @snippet.to_reference
|
||||
- page_title "#{@snippet.title} (#{@snippet.to_reference})", _("Snippets")
|
||||
|
||||
- if Feature.enabled?(:snippets_vue, default_enabled: true)
|
||||
#js-snippet-view{ data: {'qa-selector': 'snippet_view', 'snippet-gid': @snippet.to_global_id} }
|
||||
- else
|
||||
= render 'shared/snippets/header'
|
||||
|
||||
.personal-snippets
|
||||
= render 'shared/snippets/blob', blob: @blob
|
||||
#js-snippet-view{ data: {'qa-selector': 'snippet_view', 'snippet-gid': @snippet.to_global_id} }
|
||||
|
||||
.row-content-block.top-block.content-component-block
|
||||
= render 'award_emoji/awards_block', awardable: @snippet, inline: true
|
||||
|
|
5
changelogs/unreleased/13426-remove-feature-flag.yml
Normal file
5
changelogs/unreleased/13426-remove-feature-flag.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Designs are moved with an Issue that is moved
|
||||
merge_request: 44524
|
||||
author:
|
||||
type: fixed
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Fix full screen comment button on snippets
|
||||
merge_request: 44083
|
||||
author:
|
||||
type: fixed
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Remove jquery tooltip API call from delete environment button
|
||||
merge_request: 44191
|
||||
author:
|
||||
type: other
|
5
changelogs/unreleased/nicolasdular-respect-dnt.yml
Normal file
5
changelogs/unreleased/nicolasdular-respect-dnt.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Respect DNT when tracking experiments
|
||||
merge_request: 44420
|
||||
author:
|
||||
type: fixed
|
5
changelogs/unreleased/rate-limit-docs.yml
Normal file
5
changelogs/unreleased/rate-limit-docs.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Rate limit documentation for non-configurable limits
|
||||
merge_request: 44003
|
||||
author:
|
||||
type: other
|
|
@ -1,7 +0,0 @@
|
|||
---
|
||||
name: design_management_copy_designs
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/41714
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/247062
|
||||
group: group::knowledge
|
||||
type: development
|
||||
default_enabled: false
|
|
@ -1,7 +0,0 @@
|
|||
---
|
||||
name: snippets_vue
|
||||
introduced_by_url:
|
||||
rollout_issue_url:
|
||||
group: group::editor
|
||||
type: development
|
||||
default_enabled: true
|
|
@ -1,7 +1,7 @@
|
|||
---
|
||||
name: ci_accept_trace
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/41304
|
||||
rollout_issue_url:
|
||||
rollout_issue_url:
|
||||
group: group::continuous integration
|
||||
type: ops
|
||||
default_enabled: false
|
||||
default_enabled: true
|
||||
|
|
|
@ -184,5 +184,4 @@ The following are additional validation tests we performed.
|
|||
[Test Gitaly Cluster on a Geo Deployment](https://gitlab.com/gitlab-org/gitlab/-/issues/223210):
|
||||
|
||||
- Description: Tested a Geo deployment with Gitaly clusters configured on both the primary and secondary Geo sites. Triggered automatic Gitaly cluster failover on the primary Geo site, and ran end-to-end Geo tests. Then triggered Gitaly cluster failover on the secondary Geo site, and re-ran the end-to-end Geo tests.
|
||||
|
||||
- Outcome: Successful end-to-end tests before and after Gitaly cluster failover on the primary site, and before and after Gitaly cluster failover on the secondary site.
|
||||
|
|
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 43 KiB |
|
@ -13,7 +13,7 @@ described, it is possible to adapt these instructions to your needs.
|
|||
|
||||
## Architecture overview
|
||||
|
||||
![Geo multi-node diagram](../../high_availability/img/geo-ha-diagram.png)
|
||||
![Geo multi-node diagram](img/geo-ha-diagram.png)
|
||||
|
||||
_[diagram source - GitLab employees only](https://docs.google.com/drawings/d/1z0VlizKiLNXVVVaERFwgsIOuEgjcUqDTWPdQYsE7Z4c/edit)_
|
||||
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
---
|
||||
redirect_to: ../reference_architectures/index.md
|
||||
---
|
||||
|
||||
# Reference Architectures
|
||||
|
||||
This document was moved to [another location](../reference_architectures/index.md).
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
redirect_to: 'database.md'
|
||||
---
|
||||
|
||||
This document was moved to [another location](../postgresql/index.md).
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
redirect_to: ../consul.md
|
||||
---
|
||||
|
||||
This document was moved to [another location](../consul.md).
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
redirect_to: '../postgresql/index.md'
|
||||
---
|
||||
|
||||
This document was moved to [another location](../postgresql/index.md).
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
redirect_to: ../gitaly/index.md
|
||||
---
|
||||
|
||||
This document was moved to [another location](../gitaly/index.md).
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
redirect_to: ../reference_architectures/index.md
|
||||
---
|
||||
|
||||
This document was moved to [another location](../reference_architectures/index.md).
|
Binary file not shown.
Before Width: | Height: | Size: 46 KiB |
Binary file not shown.
Before Width: | Height: | Size: 18 KiB |
Binary file not shown.
Before Width: | Height: | Size: 20 KiB |
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
redirect_to: ../load_balancer.md
|
||||
---
|
||||
|
||||
This document was moved to [another location](../load_balancer.md).
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
redirect_to: ../monitoring/prometheus/index.md
|
||||
---
|
||||
|
||||
This document was moved to [another location](../monitoring/prometheus/index.md).
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
redirect_to: ../nfs.md
|
||||
---
|
||||
|
||||
This document was moved to [another location](../nfs.md).
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
redirect_to: ../nfs.md
|
||||
---
|
||||
|
||||
This document was moved to [another location](../nfs.md).
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
redirect_to: '../object_storage.md'
|
||||
---
|
||||
|
||||
This document was moved to [another location](../object_storage.md).
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
redirect_to: ../postgresql/pgbouncer.md
|
||||
---
|
||||
|
||||
This document was moved to [another location](../postgresql/pgbouncer.md).
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
redirect_to: ../redis/index.md
|
||||
---
|
||||
|
||||
This document was moved to [another location](../redis/index.md).
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
redirect_to: ../redis/replication_and_failover_external.md
|
||||
---
|
||||
|
||||
This document was moved to [another location](../redis/replication_and_failover_external.md).
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
redirect_to: ../sidekiq.md
|
||||
---
|
||||
|
||||
This document was moved to [another location](../sidekiq.md).
|
|
@ -160,7 +160,7 @@ Projects::HousekeepingService.new(p, :gc).execute
|
|||
`gitlab-rake gitlab:uploads:check VERBOSE=1` detects remote objects that do not exist because they were
|
||||
deleted externally but their references still exist in the GitLab database.
|
||||
|
||||
Example output with error message:
|
||||
Example output with error message:
|
||||
|
||||
```shell
|
||||
$ sudo gitlab-rake gitlab:uploads:check VERBOSE=1
|
||||
|
|
|
@ -1582,8 +1582,8 @@ On each node perform the following:
|
|||
```
|
||||
|
||||
1. Save the `/etc/gitlab/gitlab-secrets.json` file from one of the two
|
||||
application nodes and install it on the other application node and the
|
||||
[Gitaly node](#configure-gitaly) and
|
||||
application nodes and install it on the other application node, the
|
||||
[Gitaly node](#configure-gitaly) and the [Sidekiq node](#configure-sidekiq) and
|
||||
[reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure).
|
||||
|
||||
1. Verify the GitLab services are running:
|
||||
|
|
|
@ -1581,8 +1581,8 @@ On each node perform the following:
|
|||
```
|
||||
|
||||
1. Save the `/etc/gitlab/gitlab-secrets.json` file from one of the two
|
||||
application nodes and install it on the other application node and the
|
||||
[Gitaly node](#configure-gitaly) and
|
||||
application nodes and install it on the other application node, the
|
||||
[Gitaly node](#configure-gitaly) and the [Sidekiq node](#configure-sidekiq) and
|
||||
[reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure).
|
||||
|
||||
1. Verify the GitLab services are running:
|
||||
|
|
|
@ -24,7 +24,7 @@ curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/a
|
|||
```
|
||||
|
||||
```json
|
||||
[
|
||||
[
|
||||
{
|
||||
"id": 4,
|
||||
"name": "Test Token",
|
||||
|
@ -45,7 +45,7 @@ curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/a
|
|||
```
|
||||
|
||||
```json
|
||||
[
|
||||
[
|
||||
{
|
||||
"id": 4,
|
||||
"name": "Test Token",
|
||||
|
|
|
@ -57,7 +57,7 @@ of using this type instead of `ID` are:
|
|||
- it parses it into a `GlobalID` before passing it to user code
|
||||
- it can be parameterized on the type of the object (e.g.
|
||||
`GlobalIDType[Project]`) which offers even better validation and security.
|
||||
|
||||
|
||||
Consider using this type for all new arguments and result types. Remember that
|
||||
it is perfectly possible to parameterize this type with a concern or a
|
||||
supertype, if you want to accept a wider range of objects (e.g.
|
||||
|
|
|
@ -171,7 +171,7 @@ class ParentPolicy < BasePolicy
|
|||
condition(:speaks_spanish) { @subject.spoken_languages.include?(:es) }
|
||||
condition(:has_license) { @subject.driving_license.present? }
|
||||
condition(:enjoys_broccoli) { @subject.enjoyment_of(:broccoli) > 0 }
|
||||
|
||||
|
||||
rule { speaks_spanish }.enable :read_spanish
|
||||
rule { has_license }.enable :drive_car
|
||||
rule { enjoys_broccoli }.enable :eat_broccoli
|
||||
|
@ -190,7 +190,7 @@ child policy, for example:
|
|||
```ruby
|
||||
class ChildPolicy < BasePolicy
|
||||
delegate { @subject.parent }
|
||||
|
||||
|
||||
rule { default }.prevent :drive_car
|
||||
end
|
||||
```
|
||||
|
@ -211,11 +211,11 @@ The solution it to override the `:eat_broccoli` ability in the child policy:
|
|||
```ruby
|
||||
class ChildPolicy < BasePolicy
|
||||
delegate { @subject.parent }
|
||||
|
||||
|
||||
overrides :eat_broccoli
|
||||
|
||||
|
||||
condition(:good_kid) { @subject.behavior_level >= Child::GOOD }
|
||||
|
||||
|
||||
rule { good_kid }.enable :eat_broccoli
|
||||
end
|
||||
```
|
||||
|
|
|
@ -443,7 +443,9 @@ Recommendations:
|
|||
- If possible, data granularity should be a week. For example a key could be composed from the
|
||||
metric's name and week of the year, `2020-33-{metric_name}`.
|
||||
- Use a [feature flag](../../operations/feature_flags.md) to have a control over the impact when
|
||||
adding new metrics.
|
||||
adding new metrics.
|
||||
- Feature flags should be [default on](../documentation/feature_flags.md#criteria)
|
||||
before final release to ensure we receive data from self-managed instances.
|
||||
|
||||
##### Known events in usage data payload
|
||||
|
||||
|
|
|
@ -240,7 +240,7 @@ end
|
|||
|
||||
it 'schedules a background job' do
|
||||
expect(BackgroundJob).to receive(:perform_async)
|
||||
|
||||
|
||||
subject.execute
|
||||
end
|
||||
```
|
||||
|
@ -252,7 +252,7 @@ combining the examples:
|
|||
```ruby
|
||||
it 'performs the expected side-effects' do
|
||||
expect(BackgroundJob).to receive(:perform_async)
|
||||
|
||||
|
||||
expect { subject.execute }
|
||||
.to change(Event, :count).by(1)
|
||||
.and change { arg_0.frobulance }.to('wibble')
|
||||
|
|
|
@ -13,7 +13,7 @@ what environments to run tests against using the `only` metadata.
|
|||
| `production` | Match against production | `Static` |
|
||||
|
||||
CAUTION: **Caution:**
|
||||
You cannot specify `:production` and `{ <switch>: 'value' }` simultaneously.
|
||||
You cannot specify `:production` and `{ <switch>: 'value' }` simultaneously.
|
||||
These options are mutually exclusive. If you want to specify production, you
|
||||
can control the `tld` and `domain` independently.
|
||||
|
||||
|
|
|
@ -229,7 +229,7 @@ beforeEach(() => {
|
|||
it('exists', () => {
|
||||
// Best
|
||||
|
||||
// NOTE: both mount and shallowMount work as long as a DOM element is available
|
||||
// NOTE: both mount and shallowMount work as long as a DOM element is available
|
||||
// Finds a properly formatted link with an accessible name of "Click Me"
|
||||
getByRole(el, 'link', { name: /Click Me/i })
|
||||
getByRole(el, 'link', { name: 'Click Me' })
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
redirect_to: '../user/project/integrations/bamboo.md'
|
||||
---
|
||||
|
||||
This document was moved to [another location](../user/project/integrations/bamboo.md).
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
redirect_to: '../user/project/integrations/bugzilla.md'
|
||||
---
|
||||
|
||||
This document was moved to [another location](../user/project/integrations/bugzilla.md).
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
redirect_to: '../user/project/integrations/emails_on_push.md'
|
||||
---
|
||||
|
||||
This document was moved to [another location](../user/project/integrations/emails_on_push.md).
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
redirect_to: '../user/project/integrations/hipchat.md'
|
||||
---
|
||||
|
||||
This document was moved to [another location](../user/project/integrations/hipchat.md).
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
redirect_to: '../user/project/integrations/irker.md'
|
||||
---
|
||||
|
||||
This document was moved to [another location](../user/project/integrations/irker.md).
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
redirect_to: '../user/project/integrations/jira.md'
|
||||
---
|
||||
|
||||
This document was moved to [another location](../user/project/integrations/jira.md).
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
redirect_to: '../user/project/integrations/kubernetes.md'
|
||||
---
|
||||
|
||||
This document was moved to [another location](../user/project/integrations/kubernetes.md).
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
redirect_to: '../user/project/integrations/mattermost.md'
|
||||
---
|
||||
|
||||
This document was moved to [another location](../user/project/integrations/mattermost.md).
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
redirect_to: '../user/project/integrations/mattermost_slash_commands.md'
|
||||
---
|
||||
|
||||
This document was moved to [another location](../user/project/integrations/mattermost_slash_commands.md).
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
redirect_to: '../user/project/integrations/overview.md'
|
||||
---
|
||||
|
||||
This document was moved to [another location](../user/project/integrations/overview.md).
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
redirect_to: '../user/project/integrations/redmine.md'
|
||||
---
|
||||
|
||||
This document was moved to [another location](../user/project/integrations/redmine.md).
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
redirect_to: '../user/project/integrations/services_templates.md'
|
||||
---
|
||||
|
||||
This document was moved to [another location](../user/project/integrations/services_templates.md).
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
redirect_to: '../user/project/integrations/slack.md'
|
||||
---
|
||||
|
||||
This document was moved to [another location](../user/project/integrations/slack.md).
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
redirect_to: '../user/project/integrations/slack_slash_commands.md'
|
||||
---
|
||||
|
||||
This document was moved to [another location](../user/project/integrations/slack_slash_commands.md).
|
|
@ -28,6 +28,25 @@ similarly mitigated by a rate limit.
|
|||
- [Protected paths](../user/admin_area/settings/protected_paths.md).
|
||||
- [Import/Export rate limits](../user/admin_area/settings/import_export_rate_limits.md).
|
||||
|
||||
## Non-configurable limits
|
||||
|
||||
### Repository archives
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/25750) in GitLab 12.9.
|
||||
|
||||
There is a rate limit for [downloading repository archives](../api/repositories.md#get-file-archive),
|
||||
which applies to the project and to the user initiating the download either through the UI or the API.
|
||||
|
||||
The **rate limit** is 5 requests per minute per user.
|
||||
|
||||
### Webhook Testing
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/commit/35bc85c3ca093fee58d60dacdc9ed1fd9a15adec) in GitLab 13.4.
|
||||
|
||||
There is a rate limit for [testing webhooks](../user/project/integrations/webhooks.md#testing-webhooks), which prevents abuse of the webhook functionality.
|
||||
|
||||
The **rate limit** is 5 requests per minute per user.
|
||||
|
||||
## Rack Attack initializer
|
||||
|
||||
This method of rate limiting is cumbersome, but has some advantages. It allows
|
||||
|
|
|
@ -6,26 +6,27 @@ type: reference
|
|||
|
||||
Your GitLab instance can perform HTTP POST requests on the following events:
|
||||
|
||||
- `group_create`
|
||||
- `group_destroy`
|
||||
- `group_rename`
|
||||
- `key_create`
|
||||
- `key_destroy`
|
||||
- `project_create`
|
||||
- `project_destroy`
|
||||
- `project_rename`
|
||||
- `project_transfer`
|
||||
- `project_update`
|
||||
- `repository_update`
|
||||
- `user_add_to_group`
|
||||
- `user_add_to_team`
|
||||
- `user_remove_from_team`
|
||||
- `user_update_for_team`
|
||||
- `user_create`
|
||||
- `user_destroy`
|
||||
- `user_failed_login`
|
||||
- `user_rename`
|
||||
- `key_create`
|
||||
- `key_destroy`
|
||||
- `group_create`
|
||||
- `group_destroy`
|
||||
- `group_rename`
|
||||
- `user_add_to_group`
|
||||
- `user_remove_from_group`
|
||||
- `user_remove_from_team`
|
||||
- `user_rename`
|
||||
- `user_update_for_group`
|
||||
- `user_update_for_team`
|
||||
|
||||
The triggers for most of these are self-explanatory, but `project_update` and `project_rename` deserve some clarification: `project_update` is fired any time an attribute of a project is changed (name, description, tags, etc.) *unless* the `path` attribute is also changed. In that case, a `project_rename` is triggered instead (so that, for instance, if all you care about is the repository URL, you can just listen for `project_rename`).
|
||||
|
||||
|
|
|
@ -608,6 +608,11 @@ dropped and users get
|
|||
|
||||
To help avoid abuse, project and group imports, exports, and export downloads are rate limited. See [Project import/export rate limits](../../user/project/settings/import_export.md#rate-limits) and [Group import/export rate limits](../../user/group/settings/import_export.md#rate-limits) for details.
|
||||
|
||||
### Non-configurable limits
|
||||
|
||||
See [non-configurable limits](../../security/rate_limits.md#non-configurable-limits) for information on
|
||||
rate limits that are not configurable, and therefore also used on GitLab.com.
|
||||
|
||||
## GitLab.com Logging
|
||||
|
||||
We use [Fluentd](https://gitlab.com/gitlab-com/runbooks/tree/master/logging/doc#fluentd) to parse our logs. Fluentd sends our logs to
|
||||
|
|
|
@ -72,9 +72,7 @@ to add an issue to an epic, reorder issues, move issues between epics, or promot
|
|||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/199184) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 12.10.
|
||||
> - The health status of a closed issue [will be hidden](https://gitlab.com/gitlab-org/gitlab/-/issues/220867) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 13.3 or later.
|
||||
|
||||
You can report on and quickly respond to the health of individual issues and epics by setting a
|
||||
red, amber, or green [health status on an issue](../../project/issues/index.md#health-status),
|
||||
which will appear on your Epic tree.
|
||||
Report or respond to the health of issues and epics by setting a red, amber, or green [health status](../../project/issues/index.md#health-status), which then appears on your Epic tree.
|
||||
|
||||
### Disable Issue health status in Epic tree
|
||||
|
||||
|
|
|
@ -427,6 +427,7 @@ GFM recognizes the following:
|
|||
| merge request | `!123` | `namespace/project!123` | `project!123` |
|
||||
| snippet | `$123` | `namespace/project$123` | `project$123` |
|
||||
| epic **(ULTIMATE)** | `&123` | `group1/subgroup&123` | |
|
||||
| vulnerability **(ULTIMATE)** | `+123` | `namespace/project+123` | `project+123` |
|
||||
| label by ID | `~123` | `namespace/project~123` | `project~123` |
|
||||
| one-word label by name | `~bug` | `namespace/project~bug` | `project~bug` |
|
||||
| multi-word label by name | `~"feature request"` | `namespace/project~"feature request"` | `project~"feature request"` |
|
||||
|
|
|
@ -226,13 +226,13 @@ To delete the currently active issue board:
|
|||
|
||||
An issue board can be associated with a GitLab [Milestone](milestones/index.md#milestones),
|
||||
[Labels](labels.md), Assignee and Weight
|
||||
which will automatically filter the Board issues according to these fields.
|
||||
which automatically filter the board issues accordingly.
|
||||
This allows you to create unique boards according to your team's need.
|
||||
|
||||
![Create scoped board](img/issue_board_creation.png)
|
||||
|
||||
You can define the scope of your board when creating it or by clicking the "Edit board" button.
|
||||
Once a milestone, assignee or weight is assigned to an issue board, you will no longer be able to
|
||||
Once a milestone, assignee or weight is assigned to an issue board, you can no longer
|
||||
filter through these in the search bar. In order to do that, you need to remove the desired scope
|
||||
(for example, milestone, assignee, or weight) from the issue board.
|
||||
|
||||
|
@ -270,24 +270,22 @@ especially in combination with [assignee lists](#assignee-lists).
|
|||
|
||||
### Group issue boards **(PREMIUM)**
|
||||
|
||||
> [Introduced](https://about.gitlab.com/releases/2017/09/22/gitlab-10-0-released/#group-issue-boards) in [GitLab Premium](https://about.gitlab.com/pricing/) 10.0.
|
||||
> - One group issue board per group introduced in GitLab 10.6.
|
||||
> - Multiple group issue boards [introduced](https://about.gitlab.com/releases/2017/09/22/gitlab-10-0-released/#group-issue-boards) in [GitLab Premium](https://about.gitlab.com/pricing/) 10.0.
|
||||
|
||||
Accessible at the group navigation level, a group issue board offers the same features as a project-level board,
|
||||
but it can display issues from all projects in that
|
||||
Accessible at the group navigation level, a group issue board offers the same features as a project-level board.
|
||||
It can display issues from all projects in that
|
||||
group and its descendant subgroups. Similarly, you can only filter by group labels for these
|
||||
boards. When updating milestones and labels for an issue through the sidebar update mechanism, again only
|
||||
group-level objects are available.
|
||||
|
||||
NOTE: **Note:**
|
||||
Multiple group issue boards were originally [introduced](https://about.gitlab.com/releases/2017/09/22/gitlab-10-0-released/#group-issue-boards) in [GitLab Premium](https://about.gitlab.com/pricing/) 10.0, and one group issue board per group was made available in GitLab Core 10.6.
|
||||
|
||||
![Group issue board](img/group_issue_board.png)
|
||||
|
||||
### Assignee lists **(PREMIUM)**
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/5784) in [GitLab Premium](https://about.gitlab.com/pricing/) 11.0.
|
||||
|
||||
Like in a regular list that shows all issues with a chosen label, you can add
|
||||
As in a regular list showing all issues with a chosen label, you can add
|
||||
an assignee list that shows all issues assigned to a user.
|
||||
You can have a board with both label lists and assignee lists. To add an
|
||||
assignee list:
|
||||
|
@ -313,7 +311,7 @@ milestone, giving you more freedom and visibility on the issue board. To add a m
|
|||
1. Select the **Milestone** tab.
|
||||
1. Search and click the milestone.
|
||||
|
||||
Similar to the assignee lists, you're now able to [drag issues](#drag-issues-between-lists)
|
||||
Like the assignee lists, you're able to [drag issues](#drag-issues-between-lists)
|
||||
to and from a milestone list to manipulate the milestone of the dragged issues.
|
||||
As in other list types, click the trash icon to remove a list.
|
||||
|
||||
|
@ -329,7 +327,7 @@ You cannot set a WIP limit on the default lists (**Open** and **Closed**).
|
|||
|
||||
Examples:
|
||||
|
||||
- You have a list with four issues, and a limit of five, the header will show **4/5**.
|
||||
- When you have a list with four issues and a limit of five, the header shows **4/5**.
|
||||
If you exceed the limit, the current number of issues is shown in red.
|
||||
- You have a list with five issues with a limit of five. When you move another issue to that list,
|
||||
the list's header displays **6/5**, with the six shown in red.
|
||||
|
@ -387,7 +385,7 @@ Create a new list by clicking the **Add list** button in the upper right corner
|
|||
|
||||
![creating a new list in an issue board](img/issue_board_add_list.png)
|
||||
|
||||
Then, choose the label or user to create the list from. The new list will be inserted
|
||||
Then, choose the label or user to create the list from. The new list is inserted
|
||||
at the end of the lists, before **Done**. Moving and reordering lists is as
|
||||
easy as dragging them around.
|
||||
|
||||
|
@ -398,15 +396,15 @@ You can now choose it to create a list.
|
|||
### Delete a list
|
||||
|
||||
To delete a list from the issue board, use the small trash icon present
|
||||
in the list's heading. A confirmation dialog will appear for you to confirm.
|
||||
in the list's heading. A confirmation dialog appears for you to confirm.
|
||||
|
||||
Deleting a list doesn't have any effect in issues and labels, it's just the
|
||||
list view that is removed. You can always add it back later if you need.
|
||||
Deleting a list doesn't have any effect on issues and labels, as it's just the
|
||||
list view that's removed. You can always restore it later if you need.
|
||||
|
||||
### Add issues to a list
|
||||
|
||||
You can add issues to a list by clicking the **Add issues** button
|
||||
present in the upper right corner of the issue board. This will open up a modal
|
||||
present in the upper right corner of the issue board. This opens up a modal
|
||||
window where you can see all the issues that do not belong to any list.
|
||||
|
||||
Select one or more issues by clicking the cards and then click **Add issues**
|
||||
|
@ -426,7 +424,7 @@ respective label is removed.
|
|||
### Filter issues
|
||||
|
||||
You should be able to use the filters on top of your issue board to show only
|
||||
the results you want. This is similar to the filtering used in the issue tracker
|
||||
the results you want. It's similar to the filtering used in the issue tracker
|
||||
since the metadata from the issues and labels are re-used in the issue board.
|
||||
|
||||
You can filter by author, assignee, milestone, and label.
|
||||
|
@ -460,12 +458,12 @@ For example, you can create a list based on the label of **Frontend** and one fo
|
|||
worked on by the designers.
|
||||
|
||||
Then, once they're done, all they have to do is
|
||||
drag it to the next list, **Backend**, where a backend developer can
|
||||
drag it to the next list, **Backend**. Then, a backend developer can
|
||||
eventually pick it up. Once they’re done, they move it to **Done**, to close the
|
||||
issue.
|
||||
|
||||
This process can be seen clearly when visiting an issue since with every move
|
||||
to another list the label changes and a system note is recorded.
|
||||
This process can be seen clearly when visiting an issue. With every move
|
||||
to another list, the label changes and a system note is recorded.
|
||||
|
||||
![issue board system notes](img/issue_board_system_notes.png)
|
||||
|
||||
|
|
|
@ -56,8 +56,7 @@ Support for [PDF](https://gitlab.com/gitlab-org/gitlab/issues/32811) is planned
|
|||
- From GitLab 13.1, Design filenames are limited to 255 characters.
|
||||
- Design Management data
|
||||
[isn't deleted when a project is destroyed](https://gitlab.com/gitlab-org/gitlab/-/issues/13429) yet.
|
||||
- Design Management data [won't be moved](https://gitlab.com/gitlab-org/gitlab/-/issues/13426)
|
||||
when an issue is moved, nor [deleted](https://gitlab.com/gitlab-org/gitlab/-/issues/13427)
|
||||
- Design Management data [won't be deleted](https://gitlab.com/gitlab-org/gitlab/-/issues/13427)
|
||||
when an issue is deleted.
|
||||
- From GitLab 12.7, Design Management data [can be replicated](../../../administration/geo/replication/datatypes.md#limitations-on-replicationverification)
|
||||
by Geo but [not verified](https://gitlab.com/gitlab-org/gitlab/-/issues/32467).
|
||||
|
|
|
@ -79,7 +79,7 @@ test:
|
|||
|
||||
The following [`gitlab-ci.yml`](../../../ci/yaml/README.md) example for Java uses [Maven](https://maven.apache.org/)
|
||||
to build the project and [Jacoco](https://www.eclemma.org/jacoco/) coverage-tooling to
|
||||
generate the coverage artifact.
|
||||
generate the coverage artifact.
|
||||
You can check the [Docker image configuration and scripts](https://gitlab.com/haynes/jacoco2cobertura) if you want to build your own image.
|
||||
|
||||
GitLab expects the artifact in the Cobertura format, so you have to execute a few
|
||||
|
@ -119,7 +119,7 @@ coverage-jdk11:
|
|||
|
||||
The following [`gitlab-ci.yml`](../../../ci/yaml/README.md) example for Java uses [Gradle](https://gradle.org/)
|
||||
to build the project and [Jacoco](https://www.eclemma.org/jacoco/) coverage-tooling to
|
||||
generate the coverage artifact.
|
||||
generate the coverage artifact.
|
||||
You can check the [Docker image configuration and scripts](https://gitlab.com/haynes/jacoco2cobertura) if you want to build your own image.
|
||||
|
||||
GitLab expects the artifact in the Cobertura format, so you have to execute a few
|
||||
|
|
|
@ -119,7 +119,7 @@ module Banzai
|
|||
|
||||
# Yields the link's URL and inner HTML whenever the node is a valid <a> tag.
|
||||
def yield_valid_link(node)
|
||||
link = CGI.unescape(node.attr('href').to_s)
|
||||
link = unescape_link(node.attr('href').to_s)
|
||||
inner_html = node.inner_html
|
||||
|
||||
return unless link.force_encoding('UTF-8').valid_encoding?
|
||||
|
@ -127,6 +127,10 @@ module Banzai
|
|||
yield link, inner_html
|
||||
end
|
||||
|
||||
def unescape_link(href)
|
||||
CGI.unescape(href)
|
||||
end
|
||||
|
||||
def replace_text_when_pattern_matches(node, index, pattern)
|
||||
return unless node.text =~ pattern
|
||||
|
||||
|
|
22
lib/banzai/filter/vulnerability_reference_filter.rb
Normal file
22
lib/banzai/filter/vulnerability_reference_filter.rb
Normal file
|
@ -0,0 +1,22 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Banzai
|
||||
module Filter
|
||||
# The actual filter is implemented in the EE mixin
|
||||
class VulnerabilityReferenceFilter < IssuableReferenceFilter
|
||||
self.reference_type = :vulnerability
|
||||
|
||||
def self.object_class
|
||||
Vulnerability
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def project
|
||||
context[:project]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Banzai::Filter::VulnerabilityReferenceFilter.prepend_if_ee('EE::Banzai::Filter::VulnerabilityReferenceFilter')
|
16
lib/banzai/reference_parser/vulnerability_parser.rb
Normal file
16
lib/banzai/reference_parser/vulnerability_parser.rb
Normal file
|
@ -0,0 +1,16 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Banzai
|
||||
module ReferenceParser
|
||||
# The actual parser is implemented in the EE mixin
|
||||
class VulnerabilityParser < IssuableParser
|
||||
self.reference_type = :vulnerability
|
||||
|
||||
def records_for_nodes(_nodes)
|
||||
{}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Banzai::ReferenceParser::VulnerabilityParser.prepend_if_ee('::EE::Banzai::ReferenceParser::VulnerabilityParser')
|
|
@ -56,7 +56,7 @@ module Gitlab
|
|||
|
||||
def self.accept_trace?(project)
|
||||
::Feature.enabled?(:ci_enable_live_trace, project) &&
|
||||
::Feature.enabled?(:ci_accept_trace, project, type: :ops, default_enabled: false)
|
||||
::Feature.enabled?(:ci_accept_trace, project, type: :ops, default_enabled: true)
|
||||
end
|
||||
|
||||
def self.log_invalid_trace_chunks?(project)
|
||||
|
|
|
@ -114,18 +114,23 @@ module Gitlab
|
|||
end
|
||||
|
||||
def track_experiment_event(experiment_key, action, value = nil)
|
||||
return if dnt_enabled?
|
||||
|
||||
track_experiment_event_for(experiment_key, action, value) do |tracking_data|
|
||||
::Gitlab::Tracking.event(tracking_data.delete(:category), tracking_data.delete(:action), **tracking_data)
|
||||
end
|
||||
end
|
||||
|
||||
def frontend_experimentation_tracking_data(experiment_key, action, value = nil)
|
||||
return if dnt_enabled?
|
||||
|
||||
track_experiment_event_for(experiment_key, action, value) do |tracking_data|
|
||||
gon.push(tracking_data: tracking_data)
|
||||
end
|
||||
end
|
||||
|
||||
def record_experiment_user(experiment_key)
|
||||
return if dnt_enabled?
|
||||
return unless Experimentation.enabled?(experiment_key) && current_user
|
||||
|
||||
::Experiment.add_user(experiment_key, tracking_group(experiment_key), current_user)
|
||||
|
|
|
@ -43,7 +43,6 @@ module Gitlab
|
|||
|
||||
# Initialize gon.features with any flags that should be
|
||||
# made globally available to the frontend
|
||||
push_frontend_feature_flag(:snippets_vue, default_enabled: true)
|
||||
push_frontend_feature_flag(:monaco_blobs, default_enabled: true)
|
||||
push_frontend_feature_flag(:monaco_ci, default_enabled: true)
|
||||
push_frontend_feature_flag(:webperf_experiment, default_enabled: false)
|
||||
|
|
|
@ -4,7 +4,7 @@ module Gitlab
|
|||
# Extract possible GFM references from an arbitrary String for further processing.
|
||||
class ReferenceExtractor < Banzai::ReferenceExtractor
|
||||
REFERABLES = %i(user issue label milestone mentioned_user mentioned_group mentioned_project
|
||||
merge_request snippet commit commit_range directly_addressed_user epic iteration).freeze
|
||||
merge_request snippet commit commit_range directly_addressed_user epic iteration vulnerability).freeze
|
||||
attr_accessor :project, :current_user, :author
|
||||
# This counter is increased by a number of references filtered out by
|
||||
# banzai reference exctractor. Note that this counter is stateful and
|
||||
|
@ -38,7 +38,7 @@ module Gitlab
|
|||
end
|
||||
|
||||
REFERABLES.each do |type|
|
||||
define_method("#{type}s") do
|
||||
define_method(type.to_s.pluralize) do
|
||||
@references[type] ||= references(type)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -8427,9 +8427,6 @@ msgstr ""
|
|||
msgid "Delete Comment"
|
||||
msgstr ""
|
||||
|
||||
msgid "Delete Snippet"
|
||||
msgstr ""
|
||||
|
||||
msgid "Delete Value Stream"
|
||||
msgstr ""
|
||||
|
||||
|
@ -24059,9 +24056,6 @@ msgstr ""
|
|||
msgid "Snippets|Add another file %{num}/%{total}"
|
||||
msgstr ""
|
||||
|
||||
msgid "Snippets|Authored %{time_ago} by %{author}"
|
||||
msgstr ""
|
||||
|
||||
msgid "Snippets|Delete file"
|
||||
msgstr ""
|
||||
|
||||
|
@ -24878,9 +24872,6 @@ msgstr ""
|
|||
msgid "Submit a review"
|
||||
msgstr ""
|
||||
|
||||
msgid "Submit as spam"
|
||||
msgstr ""
|
||||
|
||||
msgid "Submit changes"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ fi
|
|||
|
||||
# Do not use 'README.md', instead use 'index.md'
|
||||
# Number of 'README.md's as of 2020-05-28
|
||||
NUMBER_READMES=41
|
||||
NUMBER_READMES=40
|
||||
FIND_READMES=$(find doc/ -name "README.md" | wc -l)
|
||||
echo '=> Checking for new README.md files...'
|
||||
echo
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
#!/bin/bash
|
||||
# This is copied from:
|
||||
# https://gitlab.com/gitlab-org/gitlab-qa/-/blob/master/bin/slack
|
||||
# This is based on https://gitlab.com/gitlab-org/gitlab-qa/-/blob/master/bin/slack
|
||||
#
|
||||
# Sends Slack notification MSG to CI_SLACK_WEBHOOK_URL (which needs to be set).
|
||||
# ICON_EMOJI needs to be set to an icon emoji name (without the `:` around it).
|
||||
|
@ -8,10 +7,11 @@
|
|||
CHANNEL=$1
|
||||
MSG=$2
|
||||
ICON_EMOJI=$3
|
||||
USERNAME=$4
|
||||
|
||||
if [ -z "$CHANNEL" ] || [ -z "$CI_SLACK_WEBHOOK_URL" ] || [ -z "$MSG" ] || [ -z "$ICON_EMOJI" ]; then
|
||||
echo "Missing argument(s) - Use: $0 channel message icon_emoji"
|
||||
if [ -z "$CHANNEL" ] || [ -z "$CI_SLACK_WEBHOOK_URL" ] || [ -z "$MSG" ] || [ -z "$ICON_EMOJI" ] || [ -z "$USERNAME" ]; then
|
||||
echo "Missing argument(s) - Use: $0 channel message icon_emoji username"
|
||||
echo "and set CI_SLACK_WEBHOOK_URL environment variable."
|
||||
else
|
||||
curl -X POST --data-urlencode 'payload={"channel": "#'"$CHANNEL"'", "username": "GitLab QA Bot", "text": "'"$MSG"'", "icon_emoji": "'":$ICON_EMOJI:"'"}' "$CI_SLACK_WEBHOOK_URL"
|
||||
curl -X POST --data-urlencode 'payload={"channel": "#'"$CHANNEL"'", "username": "'"$USERNAME"'", "text": "'"$MSG"'", "icon_emoji": "'":$ICON_EMOJI:"'"}' "$CI_SLACK_WEBHOOK_URL"
|
||||
fi
|
||||
|
|
|
@ -6,9 +6,12 @@ RSpec.describe Projects::Settings::OperationsController do
|
|||
let_it_be(:user) { create(:user) }
|
||||
let_it_be(:project, reload: true) { create(:project) }
|
||||
|
||||
before_all do
|
||||
project.add_maintainer(user)
|
||||
end
|
||||
|
||||
before do
|
||||
sign_in(user)
|
||||
project.add_maintainer(user)
|
||||
end
|
||||
|
||||
shared_examples 'PATCHable' do
|
||||
|
@ -163,10 +166,6 @@ RSpec.describe Projects::Settings::OperationsController do
|
|||
context 'updating each incident management setting' do
|
||||
let(:new_incident_management_settings) { {} }
|
||||
|
||||
before do
|
||||
project.add_maintainer(user)
|
||||
end
|
||||
|
||||
shared_examples 'a gitlab tracking event' do |params, event_key|
|
||||
it "creates a gitlab tracking event #{event_key}" do
|
||||
new_incident_management_settings = params
|
||||
|
@ -194,10 +193,6 @@ RSpec.describe Projects::Settings::OperationsController do
|
|||
end
|
||||
|
||||
describe 'POST #reset_pagerduty_token' do
|
||||
before do
|
||||
project.add_maintainer(user)
|
||||
end
|
||||
|
||||
context 'with existing incident management setting has active PagerDuty webhook' do
|
||||
let!(:incident_management_setting) do
|
||||
create(:project_incident_management_setting, project: project, pagerduty_active: true)
|
||||
|
@ -392,10 +387,6 @@ RSpec.describe Projects::Settings::OperationsController do
|
|||
end
|
||||
|
||||
describe 'POST #reset_alerting_token' do
|
||||
before do
|
||||
project.add_maintainer(user)
|
||||
end
|
||||
|
||||
context 'with existing alerting setting' do
|
||||
let!(:alerting_setting) do
|
||||
create(:project_alerting_setting, project: project)
|
||||
|
@ -478,6 +469,104 @@ RSpec.describe Projects::Settings::OperationsController do
|
|||
end
|
||||
end
|
||||
|
||||
context 'tracing integration' do
|
||||
describe 'GET #show' do
|
||||
context 'with existing setting' do
|
||||
let_it_be(:setting) do
|
||||
create(:project_tracing_setting, project: project)
|
||||
end
|
||||
|
||||
it 'loads existing setting' do
|
||||
get :show, params: project_params(project)
|
||||
|
||||
expect(controller.helpers.tracing_setting).to eq(setting)
|
||||
end
|
||||
end
|
||||
|
||||
context 'without an existing setting' do
|
||||
it 'builds a new setting' do
|
||||
get :show, params: project_params(project)
|
||||
|
||||
expect(controller.helpers.tracing_setting).to be_new_record
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'PATCH #update' do
|
||||
let_it_be(:external_url) { 'https://gitlab.com' }
|
||||
let(:params) do
|
||||
{
|
||||
tracing_setting_attributes: {
|
||||
external_url: external_url
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it_behaves_like 'PATCHable'
|
||||
|
||||
describe 'gitlab tracking', :snowplow, quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/259282#note_425243784' do
|
||||
shared_examples 'event tracking' do
|
||||
it 'tracks an event' do
|
||||
expect_snowplow_event(
|
||||
category: 'project:operations:tracing',
|
||||
action: 'external_url_populated'
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples 'no event tracking' do
|
||||
it 'does not track an event' do
|
||||
expect_no_snowplow_event
|
||||
end
|
||||
end
|
||||
|
||||
before do
|
||||
make_request
|
||||
end
|
||||
|
||||
subject(:make_request) do
|
||||
patch :update, params: project_params(project, params), format: :json
|
||||
end
|
||||
|
||||
context 'without existing setting' do
|
||||
context 'when creating a new setting' do
|
||||
it_behaves_like 'event tracking'
|
||||
end
|
||||
|
||||
context 'with invalid external_url' do
|
||||
let_it_be(:external_url) { nil }
|
||||
|
||||
it_behaves_like 'no event tracking'
|
||||
end
|
||||
end
|
||||
|
||||
context 'with existing setting' do
|
||||
let_it_be(:existing_setting) do
|
||||
create(:project_tracing_setting,
|
||||
project: project,
|
||||
external_url: external_url)
|
||||
end
|
||||
|
||||
context 'when changing external_url' do
|
||||
let_it_be(:external_url) { 'https://example.com' }
|
||||
|
||||
it_behaves_like 'no event tracking'
|
||||
end
|
||||
|
||||
context 'with unchanged external_url' do
|
||||
it_behaves_like 'no event tracking'
|
||||
end
|
||||
|
||||
context 'with invalid external_url' do
|
||||
let_it_be(:external_url) { nil }
|
||||
|
||||
it_behaves_like 'no event tracking'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def project_params(project, params = {})
|
||||
|
|
|
@ -8,7 +8,6 @@ RSpec.describe 'Thread Comments Snippet', :js do
|
|||
let_it_be(:snippet) { create(:project_snippet, :private, :repository, project: project, author: user) }
|
||||
|
||||
before do
|
||||
stub_feature_flags(snippets_vue: false)
|
||||
project.add_maintainer(user)
|
||||
sign_in(user)
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue