Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
bc9b43904d
commit
377d420e3d
|
|
@ -1,6 +1,5 @@
|
|||
import $ from 'jquery';
|
||||
import './autosize';
|
||||
import './markdown/render_gfm';
|
||||
import initCollapseSidebarOnWindowResize from './collapse_sidebar_on_window_resize';
|
||||
import initCopyToClipboard from './copy_to_clipboard';
|
||||
import installGlEmojiElement from './gl_emoji';
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
import $ from 'jquery';
|
||||
import { renderGFM } from '~/behaviors/markdown/render_gfm';
|
||||
|
||||
$.fn.renderGFM = function plugin() {
|
||||
this.get().forEach(renderGFM);
|
||||
return this;
|
||||
};
|
||||
requestIdleCallback(
|
||||
() => {
|
||||
renderGFM(document.body);
|
||||
},
|
||||
{ timeout: 500 },
|
||||
);
|
||||
|
|
@ -1,4 +1,3 @@
|
|||
import $ from 'jquery';
|
||||
import syntaxHighlight from '~/syntax_highlight';
|
||||
import highlightCurrentUser from './highlight_current_user';
|
||||
import { renderKroki } from './render_kroki';
|
||||
|
|
@ -8,40 +7,46 @@ import renderMetrics from './render_metrics';
|
|||
import renderObservability from './render_observability';
|
||||
import { renderJSONTable } from './render_json_table';
|
||||
|
||||
function initPopovers(elements) {
|
||||
if (!elements.length) return;
|
||||
import(/* webpackChunkName: 'IssuablePopoverBundle' */ '~/issuable/popover')
|
||||
.then(({ default: initIssuablePopovers }) => {
|
||||
initIssuablePopovers(elements);
|
||||
})
|
||||
.catch(() => {});
|
||||
}
|
||||
|
||||
// Render GitLab flavoured Markdown
|
||||
//
|
||||
// Delegates to syntax highlight and render math & mermaid diagrams.
|
||||
//
|
||||
$.fn.renderGFM = function renderGFM() {
|
||||
syntaxHighlight(this.find('.js-syntax-highlight').get());
|
||||
renderKroki(this.find('.js-render-kroki[hidden]').get());
|
||||
renderMath(this.find('.js-render-math'));
|
||||
renderSandboxedMermaid(this.find('.js-render-mermaid').get());
|
||||
renderJSONTable(
|
||||
Array.from(this.find('[lang="json"][data-lang-params="table"]').get()).map((e) => e.parentNode),
|
||||
);
|
||||
export function renderGFM(element) {
|
||||
const [
|
||||
highlightEls,
|
||||
krokiEls,
|
||||
mathEls,
|
||||
mermaidEls,
|
||||
tableEls,
|
||||
userEls,
|
||||
popoverEls,
|
||||
metricsEls,
|
||||
observabilityEls,
|
||||
] = [
|
||||
'.js-syntax-highlight',
|
||||
'.js-render-kroki[hidden]',
|
||||
'.js-render-math',
|
||||
'.js-render-mermaid',
|
||||
'[lang="json"][data-lang-params="table"]',
|
||||
'.gfm-project_member',
|
||||
'.gfm-issue, .gfm-merge_request',
|
||||
'.js-render-metrics',
|
||||
'.js-render-observability',
|
||||
].map((selector) => Array.from(element.querySelectorAll(selector)));
|
||||
|
||||
highlightCurrentUser(this.find('.gfm-project_member').get());
|
||||
|
||||
const issuablePopoverElements = this.find('.gfm-issue, .gfm-merge_request').get();
|
||||
if (issuablePopoverElements.length) {
|
||||
import(/* webpackChunkName: 'IssuablePopoverBundle' */ '~/issuable/popover')
|
||||
.then(({ default: initIssuablePopovers }) => {
|
||||
initIssuablePopovers(issuablePopoverElements);
|
||||
})
|
||||
.catch(() => {});
|
||||
}
|
||||
|
||||
renderMetrics(this.find('.js-render-metrics').get());
|
||||
renderObservability(this.find('.js-render-observability').get());
|
||||
return this;
|
||||
};
|
||||
|
||||
$(() => {
|
||||
window.requestIdleCallback(
|
||||
() => {
|
||||
$('body').renderGFM();
|
||||
},
|
||||
{ timeout: 500 },
|
||||
);
|
||||
});
|
||||
syntaxHighlight(highlightEls);
|
||||
renderKroki(krokiEls);
|
||||
renderMath(mathEls);
|
||||
renderSandboxedMermaid(mermaidEls);
|
||||
renderJSONTable(tableEls.map((e) => e.parentNode));
|
||||
highlightCurrentUser(userEls);
|
||||
renderMetrics(metricsEls);
|
||||
renderObservability(observabilityEls);
|
||||
initPopovers(popoverEls);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -175,14 +175,14 @@ class SafeMathRenderer {
|
|||
}
|
||||
}
|
||||
|
||||
export default function renderMath($els) {
|
||||
if (!$els.length) return;
|
||||
export default function renderMath(elements) {
|
||||
if (!elements.length) return;
|
||||
Promise.all([
|
||||
import(/* webpackChunkName: 'katex' */ 'katex'),
|
||||
import(/* webpackChunkName: 'katex' */ 'katex/dist/katex.min.css'),
|
||||
])
|
||||
.then(([katex]) => {
|
||||
const renderer = new SafeMathRenderer($els.get(), katex);
|
||||
const renderer = new SafeMathRenderer(elements, katex);
|
||||
renderer.render();
|
||||
renderer.attachEvents();
|
||||
})
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import $ from 'jquery';
|
|||
import { createAlert } from '~/flash';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { __ } from '~/locale';
|
||||
import '~/behaviors/markdown/init_gfm';
|
||||
|
||||
// MarkdownPreview
|
||||
//
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import $ from 'jquery';
|
||||
import '~/behaviors/markdown/render_gfm';
|
||||
import '~/behaviors/markdown/init_gfm';
|
||||
import { createAlert } from '~/flash';
|
||||
import { __ } from '~/locale';
|
||||
import {
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import { addEditorMarkdownListeners } from '~/lib/utils/text_markdown';
|
|||
import { insertFinalNewline } from '~/lib/utils/text_utility';
|
||||
import TemplateSelectorMediator from '../blob/file_template_mediator';
|
||||
import { BLOB_EDITOR_ERROR, BLOB_PREVIEW_ERROR } from './constants';
|
||||
import '~/behaviors/markdown/init_gfm';
|
||||
|
||||
export default class EditBlob {
|
||||
// The options object has:
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ import { localTimeAgo } from './lib/utils/datetime_utility';
|
|||
import { getLocationHash } from './lib/utils/url_utility';
|
||||
import { sprintf, s__, __ } from './locale';
|
||||
import TaskList from './task_list';
|
||||
import '~/behaviors/markdown/init_gfm';
|
||||
|
||||
window.autosize = Autosize;
|
||||
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ import {
|
|||
TASK_TYPE_NAME,
|
||||
WIDGET_TYPE_DESCRIPTION,
|
||||
} from '~/work_items/constants';
|
||||
import { renderGFM } from '~/behaviors/markdown/render_gfm';
|
||||
import animateMixin from '../mixins/animate';
|
||||
import { convertDescriptionWithNewSort } from '../utils';
|
||||
|
||||
|
|
@ -178,7 +179,7 @@ export default {
|
|||
},
|
||||
methods: {
|
||||
renderGFM() {
|
||||
$(this.$refs['gfm-content']).renderGFM();
|
||||
renderGFM(this.$refs['gfm-content']);
|
||||
|
||||
if (this.canUpdate) {
|
||||
// eslint-disable-next-line no-new
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import { createAlert } from '~/flash';
|
|||
import { getCookie, isMetaClick, parseBoolean, scrollToElement } from '~/lib/utils/common_utils';
|
||||
import { parseUrlPathname } from '~/lib/utils/url_utility';
|
||||
import createEventHub from '~/helpers/event_hub_factory';
|
||||
import { renderGFM } from '~/behaviors/markdown/render_gfm';
|
||||
import BlobForkSuggestion from './blob/blob_fork_suggestion';
|
||||
import Diff from './diff';
|
||||
import { initDiffStatsDropdown } from './init_diff_stats_dropdown';
|
||||
|
|
@ -346,7 +347,7 @@ export default class MergeRequestTabs {
|
|||
this.commitPipelinesTable = destroyPipelines(this.commitPipelinesTable);
|
||||
}
|
||||
|
||||
$('.detail-page-description').renderGFM();
|
||||
renderGFM(document.querySelector('.detail-page-description'));
|
||||
|
||||
if (shouldScroll) this.recallScroll(action);
|
||||
} else if (action === this.currentAction) {
|
||||
|
|
|
|||
|
|
@ -1,11 +1,10 @@
|
|||
<script>
|
||||
import $ from 'jquery';
|
||||
import { escape } from 'lodash';
|
||||
import { mapActions, mapGetters, mapState } from 'vuex';
|
||||
import SafeHtml from '~/vue_shared/directives/safe_html';
|
||||
import { __ } from '~/locale';
|
||||
import '~/behaviors/markdown/render_gfm';
|
||||
import Suggestions from '~/vue_shared/components/markdown/suggestions.vue';
|
||||
import { renderGFM } from '~/behaviors/markdown/render_gfm';
|
||||
import autosave from '../mixins/autosave';
|
||||
import NoteAttachment from './note_attachment.vue';
|
||||
import NoteAwardsList from './note_awards_list.vue';
|
||||
|
|
@ -121,7 +120,7 @@ export default {
|
|||
'removeSuggestionInfoFromBatch',
|
||||
]),
|
||||
renderGFM() {
|
||||
$(this.$refs['note-body']).renderGFM();
|
||||
renderGFM(this.$refs['note-body']);
|
||||
},
|
||||
handleFormUpdate(noteText, parentElement, callback, resolveDiscussion) {
|
||||
this.$emit('handleFormUpdate', { noteText, parentElement, callback, resolveDiscussion });
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import { ignoreWhilePending } from '~/lib/utils/ignore_while_pending';
|
|||
import { truncateSha } from '~/lib/utils/text_utility';
|
||||
import TimelineEntryItem from '~/vue_shared/components/notes/timeline_entry_item.vue';
|
||||
import { __, s__, sprintf } from '~/locale';
|
||||
import { renderGFM } from '~/behaviors/markdown/render_gfm';
|
||||
import eventHub from '../event_hub';
|
||||
import noteable from '../mixins/noteable';
|
||||
import resolvable from '../mixins/resolvable';
|
||||
|
|
@ -287,7 +288,7 @@ export default {
|
|||
this.isEditing = false;
|
||||
this.isRequesting = false;
|
||||
this.oldContent = null;
|
||||
$(this.$refs.noteBody.$el).renderGFM();
|
||||
renderGFM(this.$refs.noteBody.$el);
|
||||
this.$refs.noteBody.resetAutoSave();
|
||||
this.$emit('updateSuccess');
|
||||
},
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import { createAlert } from '~/flash';
|
|||
import { __ } from '~/locale';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { handleLocationHash } from '~/lib/utils/common_utils';
|
||||
import { renderGFM } from '../render_gfm_facade';
|
||||
import { renderGFM } from '~/behaviors/markdown/render_gfm';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
|
|
|
|||
|
|
@ -1,5 +0,0 @@
|
|||
import $ from 'jquery';
|
||||
|
||||
export const renderGFM = (el) => {
|
||||
return $(el).renderGFM();
|
||||
};
|
||||
|
|
@ -35,11 +35,6 @@ export default {
|
|||
required: true,
|
||||
default: () => [],
|
||||
},
|
||||
stagesClass: {
|
||||
type: [Array, Object, String],
|
||||
required: false,
|
||||
default: '',
|
||||
},
|
||||
updateDropdown: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
|
|
@ -59,7 +54,7 @@ export default {
|
|||
};
|
||||
</script>
|
||||
<template>
|
||||
<div class="stage-cell" data-testid="pipeline-mini-graph">
|
||||
<div data-testid="pipeline-mini-graph">
|
||||
<linked-pipelines-mini-list
|
||||
v-if="upstreamPipeline"
|
||||
:triggered-by="/* eslint-disable @gitlab/vue-no-new-non-primitive-in-template */ [
|
||||
|
|
@ -77,7 +72,6 @@ export default {
|
|||
:is-merge-train="isMergeTrain"
|
||||
:stages="stages"
|
||||
:update-dropdown="updateDropdown"
|
||||
:stages-class="stagesClass"
|
||||
data-testid="pipeline-stages"
|
||||
@miniGraphStageClick="$emit('miniGraphStageClick')"
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -17,11 +17,6 @@ export default {
|
|||
required: false,
|
||||
default: false,
|
||||
},
|
||||
stagesClass: {
|
||||
type: [Array, Object, String],
|
||||
required: false,
|
||||
default: '',
|
||||
},
|
||||
isMergeTrain: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
|
|
@ -35,8 +30,7 @@ export default {
|
|||
<div
|
||||
v-for="stage in stages"
|
||||
:key="stage.name"
|
||||
:class="stagesClass"
|
||||
class="dropdown gl-display-inline-block gl-mr-2 gl-my-2 gl-vertical-align-middle stage-container"
|
||||
class="pipeline-mini-graph-stage-container dropdown gl-display-inline-block gl-mr-2 gl-my-2 gl-vertical-align-middle"
|
||||
>
|
||||
<pipeline-stage
|
||||
:stage="stage"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
<script>
|
||||
import $ from 'jquery';
|
||||
import { isEmpty } from 'lodash';
|
||||
import SafeHtml from '~/vue_shared/directives/safe_html';
|
||||
import { scrollToElement } from '~/lib/utils/common_utils';
|
||||
|
|
@ -7,7 +6,7 @@ import { slugify } from '~/lib/utils/text_utility';
|
|||
import { getLocationHash } from '~/lib/utils/url_utility';
|
||||
import { CREATED_ASC } from '~/releases/constants';
|
||||
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
|
||||
import '~/behaviors/markdown/render_gfm';
|
||||
import { renderGFM } from '~/behaviors/markdown/render_gfm';
|
||||
import EvidenceBlock from './evidence_block.vue';
|
||||
import ReleaseBlockAssets from './release_block_assets.vue';
|
||||
import ReleaseBlockFooter from './release_block_footer.vue';
|
||||
|
|
@ -86,7 +85,7 @@ export default {
|
|||
},
|
||||
methods: {
|
||||
renderGFM() {
|
||||
$(this.$refs['gfm-content']).renderGFM();
|
||||
renderGFM(this.$refs['gfm-content']);
|
||||
},
|
||||
},
|
||||
safeHtmlConfig: { ADD_TAGS: ['gl-emoji'] },
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
<script>
|
||||
import { GlIcon, GlLink, GlLoadingIcon } from '@gitlab/ui';
|
||||
import $ from 'jquery';
|
||||
import SafeHtml from '~/vue_shared/directives/safe_html';
|
||||
import '~/behaviors/markdown/render_gfm';
|
||||
import { handleLocationHash } from '~/lib/utils/common_utils';
|
||||
import { renderGFM } from '~/behaviors/markdown/render_gfm';
|
||||
import readmeQuery from '../../queries/readme.query.graphql';
|
||||
|
||||
export default {
|
||||
|
|
@ -43,7 +42,7 @@ export default {
|
|||
if (newVal) {
|
||||
this.$nextTick(() => {
|
||||
handleLocationHash();
|
||||
$(this.$refs.readme).renderGFM();
|
||||
renderGFM(this.$refs.readme);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
<script>
|
||||
import $ from 'jquery';
|
||||
import { GlButton, GlIntersectionObserver } from '@gitlab/ui';
|
||||
import SafeHtml from '~/vue_shared/directives/safe_html';
|
||||
|
||||
|
|
@ -7,8 +6,8 @@ import { FLASH_TYPES, FLASH_CLOSED_EVENT } from '~/flash';
|
|||
import { isLoggedIn } from '~/lib/utils/common_utils';
|
||||
import { __ } from '~/locale';
|
||||
import csrf from '~/lib/utils/csrf';
|
||||
import '~/behaviors/markdown/render_gfm';
|
||||
import { trackTrialAcceptTerms } from '~/google_tag_manager';
|
||||
import { renderGFM } from '~/behaviors/markdown/render_gfm';
|
||||
|
||||
export default {
|
||||
name: 'TermsApp',
|
||||
|
|
@ -55,7 +54,7 @@ export default {
|
|||
},
|
||||
methods: {
|
||||
renderGFM() {
|
||||
$(this.$refs.gfmContainer).renderGFM();
|
||||
renderGFM(this.$refs.gfmContainer);
|
||||
},
|
||||
handleBottomReached() {
|
||||
this.acceptDisabled = false;
|
||||
|
|
|
|||
|
|
@ -190,7 +190,7 @@ export default {
|
|||
</template>
|
||||
<template v-else-if="hasPipeline">
|
||||
<a :href="status.details_path" class="gl-align-self-center gl-mr-3">
|
||||
<ci-icon :status="status" :size="24" />
|
||||
<ci-icon :status="status" :size="24" class="gl-display-flex" />
|
||||
</a>
|
||||
<div class="ci-widget-container d-flex">
|
||||
<div class="ci-widget-content">
|
||||
|
|
@ -280,7 +280,6 @@ export default {
|
|||
:pipeline-path="pipeline.path"
|
||||
:stages="pipeline.details.stages"
|
||||
:upstream-pipeline="pipeline.triggered_by"
|
||||
stages-class="mr-widget-pipeline-stages"
|
||||
/>
|
||||
<pipeline-artifacts :pipeline-id="pipeline.id" :artifacts="artifacts" class="gl-ml-3" />
|
||||
</span>
|
||||
|
|
|
|||
|
|
@ -1,11 +1,10 @@
|
|||
<script>
|
||||
import { GlSkeletonLoader } from '@gitlab/ui';
|
||||
import $ from 'jquery';
|
||||
import '~/behaviors/markdown/render_gfm';
|
||||
import { forEach, escape } from 'lodash';
|
||||
import SafeHtml from '~/vue_shared/directives/safe_html';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { __ } from '~/locale';
|
||||
import { renderGFM } from '~/behaviors/markdown/render_gfm';
|
||||
|
||||
const { CancelToken } = axios;
|
||||
let axiosSource;
|
||||
|
|
@ -97,7 +96,7 @@ export default {
|
|||
this.isLoading = false;
|
||||
|
||||
this.$nextTick(() => {
|
||||
$(this.$refs.markdownPreview).renderGFM();
|
||||
renderGFM(this.$refs.markdownPreview);
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
<script>
|
||||
import { GlIcon } from '@gitlab/ui';
|
||||
import $ from 'jquery';
|
||||
import '~/behaviors/markdown/render_gfm';
|
||||
import { debounce, unescape } from 'lodash';
|
||||
import { createAlert } from '~/flash';
|
||||
import GLForm from '~/gl_form';
|
||||
|
|
@ -11,6 +10,7 @@ import { stripHtml } from '~/lib/utils/text_utility';
|
|||
import { __, sprintf } from '~/locale';
|
||||
import Suggestions from '~/vue_shared/components/markdown/suggestions.vue';
|
||||
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
|
||||
import { renderGFM } from '~/behaviors/markdown/render_gfm';
|
||||
import MarkdownHeader from './header.vue';
|
||||
import MarkdownToolbar from './toolbar.vue';
|
||||
|
||||
|
|
@ -314,7 +314,9 @@ export default {
|
|||
this.markdownPreview = data.body || __('Nothing to preview.');
|
||||
|
||||
this.$nextTick()
|
||||
.then(() => $(this.$refs['markdown-preview']).renderGFM())
|
||||
.then(() => {
|
||||
renderGFM(this.$refs['markdown-preview']);
|
||||
})
|
||||
.catch(() =>
|
||||
createAlert({
|
||||
message: __('Error rendering Markdown preview'),
|
||||
|
|
|
|||
|
|
@ -1,15 +1,9 @@
|
|||
<script>
|
||||
import $ from 'jquery';
|
||||
import '~/behaviors/markdown/render_gfm';
|
||||
import { renderGFM } from '~/behaviors/markdown/render_gfm';
|
||||
|
||||
export default {
|
||||
mounted() {
|
||||
this.renderGFM();
|
||||
},
|
||||
methods: {
|
||||
renderGFM() {
|
||||
$(this.$el).renderGFM();
|
||||
},
|
||||
renderGFM(this.$el);
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1,10 +1,9 @@
|
|||
<script>
|
||||
import { GlDrawer, GlAlert, GlSkeletonLoader } from '@gitlab/ui';
|
||||
import $ from 'jquery';
|
||||
import SafeHtml from '~/vue_shared/directives/safe_html';
|
||||
import '~/behaviors/markdown/render_gfm';
|
||||
import { s__ } from '~/locale';
|
||||
import { contentTop } from '~/lib/utils/common_utils';
|
||||
import { renderGFM } from '~/behaviors/markdown/render_gfm';
|
||||
import { getRenderedMarkdown } from './utils/fetch';
|
||||
|
||||
export const cache = {};
|
||||
|
|
@ -78,7 +77,7 @@ export default {
|
|||
},
|
||||
renderGLFM() {
|
||||
this.$nextTick(() => {
|
||||
$(this.$refs['content-element']).renderGFM();
|
||||
renderGFM(this.$refs['content-element']);
|
||||
});
|
||||
},
|
||||
closeDrawer() {
|
||||
|
|
|
|||
|
|
@ -21,12 +21,12 @@ import $ from 'jquery';
|
|||
import { mapGetters, mapActions, mapState } from 'vuex';
|
||||
import SafeHtml from '~/vue_shared/directives/safe_html';
|
||||
import descriptionVersionHistoryMixin from 'ee_else_ce/notes/mixins/description_version_history';
|
||||
import '~/behaviors/markdown/render_gfm';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { __ } from '~/locale';
|
||||
import NoteHeader from '~/notes/components/note_header.vue';
|
||||
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
|
||||
import { spriteIcon } from '~/lib/utils/common_utils';
|
||||
import { renderGFM } from '~/behaviors/markdown/render_gfm';
|
||||
import TimelineEntryItem from './timeline_entry_item.vue';
|
||||
|
||||
const MAX_VISIBLE_COMMIT_LIST_COUNT = 3;
|
||||
|
|
@ -89,7 +89,7 @@ export default {
|
|||
},
|
||||
},
|
||||
mounted() {
|
||||
$(this.$refs['gfm-content']).renderGFM();
|
||||
renderGFM(this.$refs['gfm-content']);
|
||||
},
|
||||
methods: {
|
||||
...mapActions(['fetchDescriptionVersion', 'softDeleteDescriptionVersion']),
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
<script>
|
||||
import $ from 'jquery';
|
||||
import SafeHtml from '~/vue_shared/directives/safe_html';
|
||||
import '~/behaviors/markdown/render_gfm';
|
||||
import { renderGFM } from '~/behaviors/markdown/render_gfm';
|
||||
|
||||
export default {
|
||||
directives: {
|
||||
|
|
@ -26,12 +25,7 @@ export default {
|
|||
},
|
||||
},
|
||||
mounted() {
|
||||
this.renderGFM();
|
||||
},
|
||||
methods: {
|
||||
renderGFM() {
|
||||
$(this.$refs.gfmContainer).renderGFM();
|
||||
},
|
||||
renderGFM(this.$refs.gfmContainer);
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -17,9 +17,9 @@
|
|||
*/
|
||||
import { GlButton, GlSkeletonLoader, GlTooltipDirective, GlIcon } from '@gitlab/ui';
|
||||
import $ from 'jquery';
|
||||
import { renderGFM } from '~/behaviors/markdown/render_gfm';
|
||||
import SafeHtml from '~/vue_shared/directives/safe_html';
|
||||
import descriptionVersionHistoryMixin from 'ee_else_ce/notes/mixins/description_version_history';
|
||||
import '~/behaviors/markdown/render_gfm';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { getLocationHash } from '~/lib/utils/url_utility';
|
||||
import { __ } from '~/locale';
|
||||
|
|
@ -89,7 +89,7 @@ export default {
|
|||
},
|
||||
},
|
||||
mounted() {
|
||||
$(this.$refs['gfm-content']).renderGFM();
|
||||
renderGFM(this.$refs['gfm-content']);
|
||||
},
|
||||
methods: {
|
||||
fetchDescriptionVersion() {},
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
<script>
|
||||
import { GlButton, GlTooltipDirective } from '@gitlab/ui';
|
||||
import $ from 'jquery';
|
||||
import '~/behaviors/markdown/render_gfm';
|
||||
import SafeHtml from '~/vue_shared/directives/safe_html';
|
||||
import { renderGFM } from '~/behaviors/markdown/render_gfm';
|
||||
|
||||
const isCheckbox = (target) => target?.classList.contains('task-list-item-checkbox');
|
||||
|
||||
|
|
@ -47,7 +46,7 @@ export default {
|
|||
async renderGFM() {
|
||||
await this.$nextTick();
|
||||
|
||||
$(this.$refs['gfm-content']).renderGFM();
|
||||
renderGFM(this.$refs['gfm-content']);
|
||||
|
||||
if (this.canEdit) {
|
||||
this.checkboxes = this.$el.querySelectorAll('.task-list-item-checkbox');
|
||||
|
|
|
|||
|
|
@ -70,33 +70,20 @@
|
|||
}
|
||||
}
|
||||
|
||||
// Mini Pipelines
|
||||
// Pipeline mini graph
|
||||
.pipeline-mini-graph-stage-container {
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.stage-cell {
|
||||
.stage-container {
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
// Hack to show a button tooltip inline
|
||||
button.has-tooltip + .tooltip {
|
||||
min-width: 105px;
|
||||
}
|
||||
|
||||
// Bootstrap way of showing the content inline for anchors.
|
||||
a.has-tooltip {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
&:not(:last-child) {
|
||||
&::after {
|
||||
content: '';
|
||||
border-bottom: 2px solid $gray-200;
|
||||
position: absolute;
|
||||
right: -4px;
|
||||
top: 11px;
|
||||
width: 4px;
|
||||
}
|
||||
&:not(:last-child) {
|
||||
&::after {
|
||||
content: '';
|
||||
border-bottom: 2px solid $gray-200;
|
||||
position: absolute;
|
||||
right: -4px;
|
||||
top: 11px;
|
||||
width: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -135,6 +135,7 @@ class RegistrationsController < Devise::RegistrationsController
|
|||
|
||||
return identity_verification_redirect_path if custom_confirmation_enabled?
|
||||
|
||||
Gitlab::Tracking.event(self.class.name, 'render', user: resource)
|
||||
users_almost_there_path(email: resource.email)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Ci
|
||||
class FreezePeriodsFinder
|
||||
def initialize(project, current_user = nil)
|
||||
@project = project
|
||||
@current_user = current_user
|
||||
end
|
||||
|
||||
def execute
|
||||
return Ci::FreezePeriod.none unless Ability.allowed?(@current_user, :read_freeze_period, @project)
|
||||
|
||||
@project.freeze_periods
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class FreezePeriodsFinder
|
||||
def initialize(project, current_user = nil)
|
||||
@project = project
|
||||
@current_user = current_user
|
||||
end
|
||||
|
||||
def execute
|
||||
return Ci::FreezePeriod.none unless Ability.allowed?(@current_user, :read_freeze_period, @project)
|
||||
|
||||
@project.freeze_periods
|
||||
end
|
||||
end
|
||||
|
|
@ -3,7 +3,5 @@
|
|||
class DependencyProxy::GroupSetting < ApplicationRecord
|
||||
belongs_to :group
|
||||
|
||||
attribute :enabled, default: true
|
||||
|
||||
validates :group, presence: true
|
||||
end
|
||||
|
|
|
|||
|
|
@ -53,9 +53,7 @@
|
|||
= ci_label_for_status(@last_pipeline.status)
|
||||
- if @last_pipeline.stages_count.nonzero?
|
||||
#{ n_(s_('Pipeline|with stage'), s_('Pipeline|with stages'), @last_pipeline.stages_count) }
|
||||
.mr-widget-pipeline-graph
|
||||
.stage-cell
|
||||
.js-commit-pipeline-mini-graph{ data: { stages: @last_pipeline_stages.to_json.html_safe, full_path: @project.full_path, iid: @last_pipeline.iid, graphql_resource_etag: graphql_etag_pipeline_path(@last_pipeline) } }
|
||||
.js-commit-pipeline-mini-graph{ data: { stages: @last_pipeline_stages.to_json.html_safe, full_path: @project.full_path, iid: @last_pipeline.iid, graphql_resource_etag: graphql_etag_pipeline_path(@last_pipeline) } }
|
||||
- if @last_pipeline.duration
|
||||
in
|
||||
= time_interval_in_words @last_pipeline.duration
|
||||
|
|
|
|||
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
name: automated_email_provision
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/75872
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/348317
|
||||
milestone: '14.6'
|
||||
type: development
|
||||
group: group::license
|
||||
default_enabled: true
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class ChangeEnabledDefaultInDependencyProxyGroupSettings < Gitlab::Database::Migration[2.0]
|
||||
def change
|
||||
change_column_default :dependency_proxy_group_settings, :enabled, from: false, to: true
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1 @@
|
|||
b14a060e05fc73c9d76d7c8bec3f9e1fa99b33eae6ec0057b4a398b28414a02a
|
||||
|
|
@ -14733,7 +14733,7 @@ CREATE TABLE dependency_proxy_group_settings (
|
|||
group_id integer NOT NULL,
|
||||
created_at timestamp with time zone NOT NULL,
|
||||
updated_at timestamp with time zone NOT NULL,
|
||||
enabled boolean DEFAULT false NOT NULL
|
||||
enabled boolean DEFAULT true NOT NULL
|
||||
);
|
||||
|
||||
CREATE SEQUENCE dependency_proxy_group_settings_id_seq
|
||||
|
|
|
|||
|
|
@ -70,39 +70,6 @@ a single URL used by all Geo sites, including the primary.
|
|||
|
||||
In Kubernetes, you can use the same domain under `global.hosts.domain` as for the primary site.
|
||||
|
||||
## Disable Geo proxying
|
||||
|
||||
You can disable the secondary proxying on each Geo site, separately, by following these steps with Omnibus-based packages:
|
||||
|
||||
1. SSH into each application node (serving user traffic directly) on your secondary Geo site
|
||||
and add the following environment variable:
|
||||
|
||||
```shell
|
||||
sudo editor /etc/gitlab/gitlab.rb
|
||||
```
|
||||
|
||||
```ruby
|
||||
gitlab_workhorse['env'] = {
|
||||
"GEO_SECONDARY_PROXY" => "0"
|
||||
}
|
||||
```
|
||||
|
||||
1. Reconfigure the updated nodes for the change to take effect:
|
||||
|
||||
```shell
|
||||
gitlab-ctl reconfigure
|
||||
```
|
||||
|
||||
In Kubernetes, you can use `--set gitlab.webservice.extraEnv.GEO_SECONDARY_PROXY="0"`,
|
||||
or specify the following in your values file:
|
||||
|
||||
```yaml
|
||||
gitlab:
|
||||
webservice:
|
||||
extraEnv:
|
||||
GEO_SECONDARY_PROXY: "0"
|
||||
```
|
||||
|
||||
## Geo proxying with Separate URLs
|
||||
|
||||
> Geo secondary proxying for separate URLs is [enabled by default](https://gitlab.com/gitlab-org/gitlab/-/issues/346112) in GitLab 15.1.
|
||||
|
|
@ -192,3 +159,42 @@ It does not cover all data types, more will be added in the future as they are t
|
|||
1. Git reads are served from the local secondary while pushes get proxied to the primary.
|
||||
Selective sync or cases where repositories don't exist locally on the Geo secondary throw a "not found" error.
|
||||
1. Pages can use the same URL (without access control), but must be configured separately and are not proxied.
|
||||
|
||||
## Disable Geo proxying
|
||||
|
||||
Secondary proxying is enabled by default on a secondary site when it uses a unified URL, meaning, the same `external_url` as the primary site. Disabling proxying in this case tends to not be helpful due to completely different behavior being served at the same URL, depending on routing.
|
||||
|
||||
Secondary proxying is enabled by default in GitLab 15.1 on a secondary site even without a unified URL. If proxying needs to be disabled on a secondary site, it is much easier to disable the feature flag in [Geo proxying with Separate URLs](#geo-proxying-with-separate-urls). However, if there are multiple secondary sites, then the instructions in this section can be used to disable secondary proxying per site.
|
||||
|
||||
Additionally, the `gitlab-workhorse` service polls `/api/v4/geo/proxy` every 10 seconds. In GitLab 15.2 and later, it is only polled once, if Geo is not enabled. Prior to GitLab 15.2, you can stop this polling by disabling secondary proxying.
|
||||
|
||||
You can disable the secondary proxying on each Geo site, separately, by following these steps with Omnibus-based packages:
|
||||
|
||||
1. SSH into each application node (serving user traffic directly) on your secondary Geo site
|
||||
and add the following environment variable:
|
||||
|
||||
```shell
|
||||
sudo editor /etc/gitlab/gitlab.rb
|
||||
```
|
||||
|
||||
```ruby
|
||||
gitlab_workhorse['env'] = {
|
||||
"GEO_SECONDARY_PROXY" => "0"
|
||||
}
|
||||
```
|
||||
|
||||
1. Reconfigure the updated nodes for the change to take effect:
|
||||
|
||||
```shell
|
||||
gitlab-ctl reconfigure
|
||||
```
|
||||
|
||||
In Kubernetes, you can use `--set gitlab.webservice.extraEnv.GEO_SECONDARY_PROXY="0"`,
|
||||
or specify the following in your values file:
|
||||
|
||||
```yaml
|
||||
gitlab:
|
||||
webservice:
|
||||
extraEnv:
|
||||
GEO_SECONDARY_PROXY: "0"
|
||||
```
|
||||
|
|
|
|||
|
|
@ -0,0 +1,141 @@
|
|||
---
|
||||
stage: Data Stores
|
||||
group: Pods
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
---
|
||||
|
||||
# Multiple Databases **(FREE SELF)**
|
||||
|
||||
> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/6168) in GitLab 15.7.
|
||||
|
||||
WARNING:
|
||||
This feature is not ready for production use
|
||||
|
||||
By default, GitLab uses a single application database, referred to as the `main` database.
|
||||
|
||||
To scale GitLab, you can configure GitLab to use multiple application databases.
|
||||
|
||||
Due to [known issues](#known-issues), configuring GitLab with multiple databases is in [**Alpha**](../../policy/alpha-beta-support.md#alpha-features).
|
||||
|
||||
## Known issues
|
||||
|
||||
- Migrating data from the `main` database to the `ci` database is not supported or documented yet.
|
||||
- Once data is migrated to the `ci` database, you cannot migrate it back.
|
||||
|
||||
## Set up multiple databases
|
||||
|
||||
Use the following content to set up multiple databases with a new GitLab installation.
|
||||
|
||||
There is no documentation for existing GitLab installations yet.
|
||||
|
||||
After you have set up multiple databases, GitLab uses a second application database for
|
||||
[CI/CD features](../../ci/index.md), referred to as the `ci` database. For
|
||||
example, GitLab reads and writes to the `ci_pipelines` table in the `ci`
|
||||
database.
|
||||
|
||||
WARNING:
|
||||
You must stop GitLab before setting up multiple databases. This prevents
|
||||
split-brain situations, where `main` data is written to the `ci` database, and
|
||||
the other way around.
|
||||
|
||||
### Installations from source
|
||||
|
||||
1. [Back up GitLab](../../raketasks/backup_restore.md)
|
||||
in case of unforeseen issues.
|
||||
|
||||
1. Stop GitLab:
|
||||
|
||||
```shell
|
||||
sudo service gitlab stop
|
||||
```
|
||||
|
||||
1. Open `config/database.yml`, and add a `ci:` section under
|
||||
`production:`. See `config/database.yml.decomposed-postgresql` for possible
|
||||
values for this new `ci:` section. Once modified, the `config/database.yml` should
|
||||
look like:
|
||||
|
||||
```yaml
|
||||
production:
|
||||
main:
|
||||
# ...
|
||||
ci:
|
||||
adapter: postgresql
|
||||
encoding: unicode
|
||||
database: gitlabhq_production_ci
|
||||
# ...
|
||||
```
|
||||
|
||||
1. Save the `config/database.yml` file.
|
||||
|
||||
1. Create the `gitlabhq_production_ci` database:
|
||||
|
||||
```shell
|
||||
sudo -u postgres psql -d template1 -c "CREATE DATABASE gitlabhq_production OWNER git;"
|
||||
sudo -u git -H bundle exec rake db:schema:load:ci
|
||||
```
|
||||
|
||||
1. Lock writes for `ci` tables in `main` database, and the other way around:
|
||||
|
||||
```shell
|
||||
sudo -u git -H bundle exec rake gitlab:db:lock_writes
|
||||
```
|
||||
|
||||
1. Restart GitLab:
|
||||
|
||||
```shell
|
||||
sudo service gitlab restart
|
||||
```
|
||||
|
||||
### Omnibus GitLab installations
|
||||
|
||||
1. [Back up GitLab](../../raketasks/backup_restore.md)
|
||||
in case of unforeseen issues.
|
||||
|
||||
1. Stop GitLab:
|
||||
|
||||
```shell
|
||||
sudo gitlab-ctl stop
|
||||
```
|
||||
|
||||
1. Edit `/etc/gitlab/gitlab.rb` and add the following lines:
|
||||
|
||||
```ruby
|
||||
gitlab_rails['databases']['ci']['enable'] = true
|
||||
gitlab_rails['databases']['ci']['db_database'] = 'gitlabhq_production_ci'
|
||||
```
|
||||
|
||||
1. Save the `/etc/gitlab/gitlab.rb` file.
|
||||
|
||||
1. Reconfigure GitLab:
|
||||
|
||||
```shell
|
||||
sudo gitlab-ctl reconfigure
|
||||
```
|
||||
|
||||
1. Optional. Reconfiguring GitLab should create the `gitlabhq_production_ci`. If it did not, manually create the `gitlabhq_production_ci`:
|
||||
|
||||
```shell
|
||||
sudo gitlab-ctl start postgresql
|
||||
sudo -u gitlab-psql /opt/gitlab/embedded/bin/psql -h /var/opt/gitlab/postgresql -d template1 -c "CREATE DATABASE gitlabhq_production_ci OWNER gitlab;"
|
||||
sudo gitlab-rake db:schema:load:ci
|
||||
|
||||
1. Lock writes for `ci` tables in `main` database, and the other way around:
|
||||
|
||||
```shell
|
||||
sudo gitlab-ctl start postgresql
|
||||
sudo gitlab-rake gitlab:db:lock_writes
|
||||
```
|
||||
|
||||
1. Restart GitLab:
|
||||
|
||||
```shell
|
||||
sudo gitlab-ctl restart
|
||||
```
|
||||
|
||||
## Further information
|
||||
|
||||
For more information on multiple databases, see [issue 6168](https://gitlab.com/groups/gitlab-org/-/epics/6168).
|
||||
|
||||
For more information on how multiple databases work in GitLab, see the [development guide for multiple databases](../../development/database/multiple_databases.md).
|
||||
|
||||
Since 2022-07-02, GitLab.com has been running with two separate databases. For more information, see this [blog post](https://about.gitlab.com/blog/2022/06/02/splitting-database-into-main-and-ci/).
|
||||
|
|
@ -199,10 +199,16 @@ You can configure GitLab to use multiple SAML 2.0 identity providers if:
|
|||
|
||||
Example multiple providers configuration for Omnibus GitLab:
|
||||
|
||||
To allow your users to use SAML to sign up without having to manually create an account from either of the providers, add the following values to your configuration.
|
||||
|
||||
```ruby
|
||||
gitlab_rails['omniauth_allow_single_sign_on'] = ['saml', 'saml1']
|
||||
```
|
||||
|
||||
```ruby
|
||||
gitlab_rails['omniauth_providers'] = [
|
||||
{
|
||||
name: 'saml',
|
||||
name: 'saml', # This must match the following name configuration parameter
|
||||
args: {
|
||||
name: 'saml', # This is mandatory and must match the provider name
|
||||
strategy_class: 'OmniAuth::Strategies::SAML',
|
||||
|
|
@ -212,7 +218,7 @@ gitlab_rails['omniauth_providers'] = [
|
|||
label: 'Provider 1' # Differentiate the two buttons and providers in the UI
|
||||
},
|
||||
{
|
||||
name: 'saml1',
|
||||
name: 'saml1', # This must match the following name configuration parameter
|
||||
args: {
|
||||
name: 'saml1', # This is mandatory and must match the provider name
|
||||
strategy_class: 'OmniAuth::Strategies::SAML',
|
||||
|
|
@ -351,13 +357,19 @@ For a full list of supported assertions, see the [OmniAuth SAML gem](https://git
|
|||
|
||||
## Configure users based on SAML group membership
|
||||
|
||||
You can require users to be members of a certain group, or assign users [external](../user/admin_area/external_users.md), administrator or [auditor](../administration/auditor_users.md) access levels based on group membership.
|
||||
These groups are checked on each SAML login and user attributes updated as necessary.
|
||||
This feature **does not** allow you to
|
||||
automatically add users to GitLab [Groups](../user/group/index.md).
|
||||
You can:
|
||||
|
||||
Support for these groups depends on your [subscription](https://about.gitlab.com/pricing/)
|
||||
and whether you've installed [GitLab Enterprise Edition (EE)](https://about.gitlab.com/install/).
|
||||
- Require users to be members of a certain group.
|
||||
- Assign users [external](../user/admin_area/external_users.md), administrator or [auditor](../administration/auditor_users.md) roles based on group membership.
|
||||
|
||||
GitLab checks these groups on each SAML sign in and updates user attributes as necessary.
|
||||
This feature **does not** allow you to automatically add users to GitLab
|
||||
[Groups](../user/group/index.md).
|
||||
|
||||
Support for these groups depends on:
|
||||
|
||||
- Your [subscription](https://about.gitlab.com/pricing/).
|
||||
- Whether you've installed [GitLab Enterprise Edition (EE)](https://about.gitlab.com/install/).
|
||||
|
||||
| Group | Tier | GitLab Enterprise Edition (EE) Only? |
|
||||
|------------------------------|--------------------|--------------------------------------|
|
||||
|
|
@ -368,9 +380,9 @@ and whether you've installed [GitLab Enterprise Edition (EE)](https://about.gitl
|
|||
|
||||
### Prerequisites
|
||||
|
||||
First tell GitLab where to look for group information. For this, you
|
||||
must make sure that your IdP server sends a specific `AttributeStatement` along
|
||||
with the regular SAML response. Here is an example:
|
||||
You must tell GitLab where to look for group information. To do this, make sure
|
||||
that your IdP server sends a specific `AttributeStatement` along with the regular
|
||||
SAML response. For example:
|
||||
|
||||
```xml
|
||||
<saml:AttributeStatement>
|
||||
|
|
@ -383,9 +395,9 @@ with the regular SAML response. Here is an example:
|
|||
</saml:AttributeStatement>
|
||||
```
|
||||
|
||||
The name of the attribute can be anything you like, but it must contain the groups
|
||||
to which a user belongs. To tell GitLab where to find these groups, you need
|
||||
to add a `groups_attribute:` element to your SAML settings.
|
||||
The name of the attribute must contain the groups that a user belongs to.
|
||||
To tell GitLab where to find these groups, add a `groups_attribute:`
|
||||
element to your SAML settings.
|
||||
|
||||
### Required groups
|
||||
|
||||
|
|
@ -585,17 +597,13 @@ list.
|
|||
|
||||
## Validate response signatures
|
||||
|
||||
We require Identity Providers to sign SAML responses to ensure that the assertions are
|
||||
not tampered with.
|
||||
IdPs must sign SAML responses to ensure that the assertions are not tampered with.
|
||||
|
||||
This prevents user impersonation and prevents privilege escalation when specific group
|
||||
membership is required. Typically this:
|
||||
This prevents user impersonation and privilege escalation when specific group
|
||||
membership is required.
|
||||
|
||||
- Is configured using `idp_cert_fingerprint`.
|
||||
- Includes the full certificate in the response, although if your Identity Provider
|
||||
doesn't support this, you can directly configure GitLab using the `idp_cert` option.
|
||||
|
||||
Example configuration with `idp_cert_fingerprint`:
|
||||
You configure the response signature validation using `idp_cert_fingerprint`.
|
||||
An example configuration:
|
||||
|
||||
```yaml
|
||||
args: {
|
||||
|
|
@ -607,7 +615,8 @@ args: {
|
|||
}
|
||||
```
|
||||
|
||||
Example configuration with `idp_cert`:
|
||||
If your IdP does not support configuring this using `idp_cert_fingerprint`, you
|
||||
can instead configure GitLab directly using `idp_cert`. An example configuration:
|
||||
|
||||
```yaml
|
||||
args: {
|
||||
|
|
@ -621,15 +630,14 @@ args: {
|
|||
}
|
||||
```
|
||||
|
||||
If the response signature validation is configured incorrectly, you can see error messages
|
||||
such as:
|
||||
If you have configured the response signature validation incorrectly, you might see
|
||||
error messages such as:
|
||||
|
||||
- A key validation error.
|
||||
- Digest mismatch.
|
||||
- Fingerprint mismatch.
|
||||
|
||||
Refer to the [troubleshooting section](#troubleshooting) for more information on
|
||||
solving these errors.
|
||||
For more information on solving these errors, see the [troubleshooting SAML guide](../user/group/saml_sso/troubleshooting.md).
|
||||
|
||||
## Customize SAML settings
|
||||
|
||||
|
|
|
|||
|
|
@ -76,7 +76,9 @@ The following AWS regions are not available:
|
|||
- Cape Town (`af-south-1`)
|
||||
- Milan (`eu-south-1`)
|
||||
- Paris (`eu-west-3`)
|
||||
- GovCloud
|
||||
- Zurich (`eu-central-2`)
|
||||
- GovCloud (US-East) (`us-gov-east-1`)
|
||||
- GovCloud (US-West) (`us-gov-west-1`)
|
||||
|
||||
## Planned features
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ You can migrate groups in two ways:
|
|||
- By direct transfer (recommended).
|
||||
- By uploading an export file.
|
||||
|
||||
If you migrate from GitLab.com to self-managed GitLab, an administrator can create users on the self-managed GitLab instance.
|
||||
|
||||
## Migrate groups by direct transfer (recommended)
|
||||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/249160) in GitLab 13.7 for group resources [with a flag](../../feature_flags.md) named `bulk_import`. Disabled by default.
|
||||
|
|
@ -68,6 +70,12 @@ GitLab maps users and their contributions correctly provided:
|
|||
You might need to reconfigure your firewall to prevent blocking the connection on the self-managed
|
||||
instance.
|
||||
|
||||
If you use [SAML SSO for GitLab.com groups](../../group/saml_sso/index.md),
|
||||
contributing users must have [linked their SAML identity to their GitLab.com account](../../group/saml_sso/index.md#linking-saml-to-your-existing-gitlabcom-account).
|
||||
|
||||
When migrating to GitLab.com, you must create users manually unless [SCIM](../../group/saml_sso/scim_setup.md) is used. Creating users with the API is only
|
||||
available to self-managed instances because it requires administrator access.
|
||||
|
||||
### Connect to the source GitLab instance
|
||||
|
||||
Create the group you want to import to and connect the source:
|
||||
|
|
@ -252,6 +260,22 @@ import = BulkImports::Entity.where(namespace_id: Group.id).map(&:bulk_import)
|
|||
import.status #=> 3 means that the import timed out.
|
||||
```
|
||||
|
||||
#### Error: `404 Group Not Found`
|
||||
|
||||
If you attempt to import a group that has a path comprised of only numbers (for example, `5000`), GitLab attempts to
|
||||
find the group by ID instead of the path. This causes a `404 Group Not Found` error in GitLab 15.4 and earlier.
|
||||
|
||||
To solve this, you must change the source group path to include a non-numerical character using either:
|
||||
|
||||
- The GitLab UI:
|
||||
|
||||
1. On the top bar, select **Main menu > Groups** and find your group.
|
||||
1. On the left sidebar, select **Settings > General**.
|
||||
1. Expand **Advanced**.
|
||||
1. Under **Change group URL**, change the group URL to include non-numeric characters.
|
||||
|
||||
- The [Groups API](../../../api/groups.md#update-group).
|
||||
|
||||
### Provide feedback
|
||||
|
||||
Please leave your feedback about migrating groups by direct transfer in
|
||||
|
|
@ -286,7 +310,7 @@ Professional Services team.
|
|||
Note the following:
|
||||
|
||||
- Exports are stored in a temporary directory and are deleted every 24 hours by a specific worker.
|
||||
- To preserve group-level relationships from imported projects, run the Group Import/Export first, to allow projects to
|
||||
- To preserve group-level relationships from imported projects, export and import groups first so that projects can
|
||||
be imported into the desired group structure.
|
||||
- Imported groups are given a `private` visibility level, unless imported into a parent group.
|
||||
- If imported into a parent group, a subgroup inherits the same level of visibility unless otherwise restricted.
|
||||
|
|
@ -360,7 +384,7 @@ To export the contents of a group:
|
|||
1. In the **Advanced** section, select **Download export**.
|
||||
You can also generate a new file by selecting **Regenerate export**.
|
||||
|
||||
You can also use the [group import/export API](../../../api/group_import_export.md).
|
||||
You can also export a group [using the API](../../../api/group_import_export.md).
|
||||
|
||||
### Import the group
|
||||
|
||||
|
|
|
|||
Binary file not shown.
|
Before Width: | Height: | Size: 28 KiB |
|
|
@ -5,99 +5,59 @@ group: Import
|
|||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
---
|
||||
|
||||
# Migrate projects to a GitLab instance **(FREE)**
|
||||
# Import and migrate projects **(FREE)**
|
||||
|
||||
See these documents to migrate to GitLab:
|
||||
If you want to bring existing projects to GitLab or copy GitLab projects to a different location, you can:
|
||||
|
||||
- [From Bitbucket Cloud](bitbucket.md)
|
||||
- [From Bitbucket Server (also known as Stash)](bitbucket_server.md)
|
||||
- [From ClearCase](clearcase.md)
|
||||
- [From CVS](cvs.md)
|
||||
- [From FogBugz](fogbugz.md)
|
||||
- [From GitHub.com or GitHub Enterprise](github.md)
|
||||
- [From GitLab.com](gitlab_com.md)
|
||||
- [From Gitea](gitea.md)
|
||||
- [From Perforce](perforce.md)
|
||||
- Import projects from external systems using one of the [available importers](#available-project-importers).
|
||||
- Migrate GitLab projects:
|
||||
- Between two GitLab self-managed instances.
|
||||
- Between a self-managed instance and GitLab.com in both directions.
|
||||
- In the same GitLab instance.
|
||||
|
||||
For any type of source and target, you can migrate projects:
|
||||
|
||||
- As part of a [GitLab group migration](../../group/import/index.md). You can't migrate only chosen projects,
|
||||
but you can migrate many projects at once within a group.
|
||||
- Using [file exports](../settings/import_export.md). With this method you can migrate projects one by one. No network
|
||||
connection between instances is required.
|
||||
|
||||
If you only need to migrate Git repositories, you can [import each project by URL](repo_by_url.md). However, you can't
|
||||
import issues and merge requests this way. To retain metadata like issues and merge requests, either:
|
||||
|
||||
- [Migrate projects with groups](../../group/import/index.md).
|
||||
- Use [file exports](../settings/import_export.md) to import projects.
|
||||
|
||||
Keep in mind the limitations of [migrating using file exports](../settings/import_export.md#items-that-are-exported).
|
||||
When migrating from self-managed to GitLab.com, user associations (such as comment author)
|
||||
are changed to the user who is importing the projects.
|
||||
|
||||
## Available project importers
|
||||
|
||||
You can import projects from:
|
||||
|
||||
- [Bitbucket Cloud](bitbucket.md)
|
||||
- [Bitbucket Server (also known as Stash)](bitbucket_server.md)
|
||||
- [ClearCase](clearcase.md)
|
||||
- [CVS](cvs.md)
|
||||
- [FogBugz](fogbugz.md)
|
||||
- [GitHub.com or GitHub Enterprise](github.md)
|
||||
- [GitLab.com](gitlab_com.md)
|
||||
- [Gitea](gitea.md)
|
||||
- [Perforce](perforce.md)
|
||||
- [From SVN](https://git-scm.com/book/en/v2/Git-and-Other-Systems-Git-as-a-Client)
|
||||
- [From TFVC](tfvc.md)
|
||||
- [From repository by URL](repo_by_url.md)
|
||||
- [By uploading a manifest file (AOSP)](manifest.md)
|
||||
- [From Phabricator](phabricator.md)
|
||||
- [From Jira (issues only)](jira.md)
|
||||
- [TFVC](tfvc.md)
|
||||
- [Repository by URL](repo_by_url.md)
|
||||
- [Uloading a manifest file (AOSP)](manifest.md)
|
||||
- [Phabricator](phabricator.md)
|
||||
- [Jira (issues only)](jira.md)
|
||||
|
||||
You can also import any Git repository through HTTP from the **New Project** page. Note that if the
|
||||
repository is too large, the import can timeout.
|
||||
|
||||
You can also [connect your external repository to get CI/CD benefits](../../../ci/ci_cd_for_external_repos/index.md).
|
||||
You can then [connect your external repository to get CI/CD benefits](../../../ci/ci_cd_for_external_repos/index.md).
|
||||
|
||||
## Project import history
|
||||
|
||||
You can view all project imports created by you. This list includes the following:
|
||||
|
||||
- Source (without credentials for security reasons)
|
||||
- Destination
|
||||
- Status
|
||||
- Error details if the import failed
|
||||
|
||||
To view project import history:
|
||||
|
||||
1. Sign in to GitLab.
|
||||
1. On the top bar, select **New** (**{plus}**).
|
||||
1. Select **New project/repository**.
|
||||
1. Select **Import project**.
|
||||
1. Select **History**.
|
||||
|
||||

|
||||
|
||||
The history also includes projects created from [built-in](../working_with_projects.md#create-a-project-from-a-built-in-template)
|
||||
or [custom](../working_with_projects.md#create-a-project-from-a-built-in-template)
|
||||
templates. GitLab uses [import repository by URL](repo_by_url.md)
|
||||
to create a new project from a template.
|
||||
|
||||
## LFS authentication
|
||||
|
||||
When importing a project that contains LFS objects, if the project has an [`.lfsconfig`](https://github.com/git-lfs/git-lfs/blob/master/docs/man/git-lfs-config.5.ronn)
|
||||
file with a URL host (`lfs.url`) different from the repository URL host, LFS files are not downloaded.
|
||||
|
||||
## Migrate from self-managed GitLab to GitLab.com
|
||||
|
||||
Depending on your requirements, there are several ways to migrate from self-managed GitLab to GitLab.com.
|
||||
|
||||
### Migrate using GitLab Migration (recommended)
|
||||
|
||||
Using [GitLab Migration](../../group/import/index.md), you can migrate top-level groups you are the Owner of, with all their subgroups and projects included.
|
||||
|
||||
GitLab Migration maps users and their contributions correctly on GitLab.com provided:
|
||||
|
||||
- Contributing users exist on GitLab.com at the time of the import.
|
||||
- Those users have a public email on the source GitLab instance that matches their primary email on GitLab.com.
|
||||
|
||||
If you use [SAML SSO for GitLab.com groups](../../group/saml_sso/index.md),
|
||||
contributing users must have [linked their SAML identity to their GitLab.com account](../../group/saml_sso/index.md#linking-saml-to-your-existing-gitlabcom-account).
|
||||
|
||||
When migrating to GitLab.com, you must create users manually unless [SCIM](../../group/saml_sso/scim_setup.md) is used. Creating users with the API is only
|
||||
available to self-managed instances because it requires administrator access.
|
||||
|
||||
### Migrate specific projects only
|
||||
|
||||
If you only need to migrate Git repositories, you can [import each project by URL](repo_by_url.md).
|
||||
However, you can't import issues and merge requests this way. To retain metadata like issues and
|
||||
merge requests, use the [import/export feature](../settings/import_export.md)
|
||||
to export projects from self-managed GitLab and import those projects into GitLab.com.
|
||||
|
||||
GitLab maps user contributions correctly when an admin access token is used to perform the import.
|
||||
|
||||
As a result, the import/export feature does not map user contributions correctly when you are importing projects from a self-managed instance to GitLab.com.
|
||||
|
||||
Instead, all GitLab user associations (such as comment author) are changed to the user importing the project. For more
|
||||
information, see the prerequisites and important notes in these sections:
|
||||
|
||||
- [Export a project and its data](../settings/import_export.md#export-a-project-and-its-data).
|
||||
- [Import the project](../settings/import_export.md#import-a-project-and-its-data).
|
||||
|
||||
To preserve contribution history, [migrate using GitLab Migration](#migrate-using-gitlab-migration-recommended).
|
||||
|
||||
### Migrate using the API
|
||||
## Migrate using the API
|
||||
|
||||
To migrate all data from self-managed to GitLab.com, you can leverage the [API](../../../api/index.md).
|
||||
Migrate the assets in this order:
|
||||
|
|
@ -106,17 +66,9 @@ Migrate the assets in this order:
|
|||
1. [Projects](../../../api/projects.md)
|
||||
1. [Project variables](../../../api/project_level_variables.md)
|
||||
|
||||
Keep in mind the limitations of the [import/export feature](../settings/import_export.md#items-that-are-exported). As with [Migrating specific projects using the import/export feature](#migrate-specific-projects-only) user associations (such as comment author) are changed to the user importing projects when migrating from self-managed to GitLab.com.
|
||||
|
||||
You must still migrate your [Container Registry](../../packages/container_registry/index.md)
|
||||
over a series of Docker pulls and pushes. Re-run any CI pipelines to retrieve any build artifacts.
|
||||
|
||||
## Migrate from GitLab.com to self-managed GitLab
|
||||
|
||||
The process is essentially the same as [migrating from self-managed GitLab to GitLab.com](#migrate-from-self-managed-gitlab-to-gitlabcom).
|
||||
The main difference is that an administrator can create users on the self-managed GitLab instance
|
||||
through the UI or the [users API](../../../api/users.md#user-creation).
|
||||
|
||||
## Migrate between two self-managed GitLab instances
|
||||
|
||||
To migrate from an existing self-managed GitLab instance to a new self-managed GitLab instance, it's
|
||||
|
|
@ -128,12 +80,36 @@ The backups produced don't depend on the operating system running GitLab. You ca
|
|||
the restore method to switch between different operating system distributions or versions, as long
|
||||
as the same GitLab version [is available for installation](../../../administration/package_information/supported_os.md).
|
||||
|
||||
To instead merge two self-managed GitLab instances together, use the instructions in
|
||||
[Migrate from self-managed GitLab to GitLab.com](#migrate-from-self-managed-gitlab-to-gitlabcom).
|
||||
This method is useful when both self-managed instances have existing data that must be preserved.
|
||||
Also note that administrators can use the [Users API](../../../api/users.md) to migrate users.
|
||||
|
||||
Also note that administrators can use the [Users API](../../../api/users.md)
|
||||
to migrate users.
|
||||
## View project import history
|
||||
|
||||
You can view all project imports created by you. This list includes the following:
|
||||
|
||||
- Paths of source projects if projects were imported from external systems, or import method if GitLab projects were migrated.
|
||||
- Paths of destination projects.
|
||||
- Start date of each import.
|
||||
- Status of each import.
|
||||
- Error details if any errors occurred.
|
||||
|
||||
To view project import history:
|
||||
|
||||
1. Sign in to GitLab.
|
||||
1. On the top bar, select **Create new...** (**{plus-square}**).
|
||||
1. Select **New project/repository**.
|
||||
1. Select **Import project**.
|
||||
1. Select **History** in the upper right corner.
|
||||
1. If there are any errors for a particular import, you can see them by selecting **Details**.
|
||||
|
||||
The history also includes projects created from [built-in](../working_with_projects.md#create-a-project-from-a-built-in-template)
|
||||
or [custom](../working_with_projects.md#create-a-project-from-a-built-in-template)
|
||||
templates. GitLab uses [import repository by URL](repo_by_url.md)
|
||||
to create a new project from a template.
|
||||
|
||||
## LFS authentication
|
||||
|
||||
When importing a project that contains LFS objects, if the project has an [`.lfsconfig`](https://github.com/git-lfs/git-lfs/blob/master/docs/man/git-lfs-config.5.ronn)
|
||||
file with a URL host (`lfs.url`) different from the repository URL host, LFS files are not downloaded.
|
||||
|
||||
## Project aliases **(PREMIUM SELF)**
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,22 @@ then imported into a new GitLab instance. You can also:
|
|||
- [Migrate groups](../../group/import/index.md) using the preferred method.
|
||||
- [Migrate groups using file exports](../../group/settings/import_export.md).
|
||||
|
||||
## Set up project import/export
|
||||
GitLab maps user contributions correctly when an admin access token is used to perform the import.
|
||||
|
||||
As a result, migrating projects using file exports does not map user contributions correctly when you are importing
|
||||
projects from a self-managed instance to GitLab.com.
|
||||
|
||||
Instead, all GitLab user associations (such as comment author) are changed to the user importing the project. For more
|
||||
information, see the prerequisites and important notes in these sections:
|
||||
|
||||
- [Export a project and its data](../settings/import_export.md#export-a-project-and-its-data).
|
||||
- [Import the project](../settings/import_export.md#import-a-project-and-its-data).
|
||||
|
||||
To preserve contribution history, [migrate using direct transfer](../../group/import/index.md#migrate-groups-by-direct-transfer-recommended).
|
||||
|
||||
If you migrate from GitLab.com to self-managed GitLab, an administrator can create users on the self-managed GitLab instance.
|
||||
|
||||
## Set up project to migrate using file exports
|
||||
|
||||
Before you can import or export a project and its data, you must set it up.
|
||||
|
||||
|
|
@ -24,8 +39,7 @@ Before you can import or export a project and its data, you must set it up.
|
|||
## Between CE and EE
|
||||
|
||||
You can export projects from the [Community Edition to the Enterprise Edition](https://about.gitlab.com/install/ce-or-ee/)
|
||||
and vice versa. This assumes [version history](#version-history)
|
||||
requirements are met.
|
||||
and vice versa. This assumes [version history](#version-history) requirements are met.
|
||||
|
||||
If you're exporting a project from the Enterprise Edition to the Community Edition, you may lose
|
||||
data that is retained only in the Enterprise Edition. For more information, see
|
||||
|
|
@ -37,8 +51,7 @@ Before you can import a project, you must export it.
|
|||
|
||||
Prerequisites:
|
||||
|
||||
- Review the list of [items that are exported](#items-that-are-exported).
|
||||
Not all items are exported.
|
||||
- Review the list of [items that are exported](#items-that-are-exported). Not all items are exported.
|
||||
- You must have at least the Maintainer role for the project.
|
||||
|
||||
To export a project and its data, follow these steps:
|
||||
|
|
@ -134,7 +147,7 @@ To import a project:
|
|||
1. Enter your project name and URL. Then select the file you exported previously.
|
||||
1. Select **Import project** to begin importing. Your newly imported project page appears shortly.
|
||||
|
||||
To get the status of an import, you can query it through the [Project import/export API](../../../api/project_import_export.md#import-status).
|
||||
To get the status of an import, you can query it through the [API](../../../api/project_import_export.md#import-status).
|
||||
As described in the API documentation, the query may return an import error or exceptions.
|
||||
|
||||
### Changes to imported items
|
||||
|
|
@ -218,36 +231,9 @@ For example:
|
|||
| 13.0 | 13.0, 12.10, 12.9 |
|
||||
| 13.1 | 13.1, 13.0, 12.10 |
|
||||
|
||||
### 12.x
|
||||
|
||||
Prior to 13.0 this was a defined compatibility table:
|
||||
|
||||
| Exporting GitLab version | Importing GitLab version |
|
||||
| -------------------------- | -------------------------- |
|
||||
| 11.7 to 12.10 | 11.7 to 12.10 |
|
||||
| 11.1 to 11.6 | 11.1 to 11.6 |
|
||||
| 10.8 to 11.0 | 10.8 to 11.0 |
|
||||
| 10.4 to 10.7 | 10.4 to 10.7 |
|
||||
| 10.3 | 10.3 |
|
||||
| 10.0 to 10.2 | 10.0 to 10.2 |
|
||||
| 9.4 to 9.6 | 9.4 to 9.6 |
|
||||
| 9.2 to 9.3 | 9.2 to 9.3 |
|
||||
| 8.17 to 9.1 | 8.17 to 9.1 |
|
||||
| 8.13 to 8.16 | 8.13 to 8.16 |
|
||||
| 8.12 | 8.12 |
|
||||
| 8.10.3 to 8.11 | 8.10.3 to 8.11 |
|
||||
| 8.10.0 to 8.10.2 | 8.10.0 to 8.10.2 |
|
||||
| 8.9.5 to 8.9.11 | 8.9.5 to 8.9.11 |
|
||||
| 8.9.0 to 8.9.4 | 8.9.0 to 8.9.4 |
|
||||
|
||||
Projects can be exported and imported only between versions of GitLab with matching Import/Export versions.
|
||||
|
||||
For example, 8.10.3 and 8.11 have the same Import/Export version (0.1.3)
|
||||
and the exports between them are compatible.
|
||||
|
||||
## Related topics
|
||||
|
||||
- [Project import/export API](../../../api/project_import_export.md)
|
||||
- [Project import/export administration Rake tasks](../../../administration/raketasks/project_import_export.md)
|
||||
- [Group import/export](../../group/settings/import_export.md)
|
||||
- [Group import/export API](../../../api/group_import_export.md)
|
||||
- [Project import and export API](../../../api/project_import_export.md)
|
||||
- [Project import and export administration Rake tasks](../../../administration/raketasks/project_import_export.md)
|
||||
- [Migrating GitLab groups](../../group/import/index.md)
|
||||
- [Group import and export API](../../../api/group_import_export.md)
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ module API
|
|||
get ":id/freeze_periods" do
|
||||
authorize! :read_freeze_period, user_project
|
||||
|
||||
freeze_periods = ::FreezePeriodsFinder.new(user_project, current_user).execute
|
||||
freeze_periods = ::Ci::FreezePeriodsFinder.new(user_project, current_user).execute
|
||||
|
||||
present paginate(freeze_periods), with: Entities::FreezePeriod, current_user: current_user
|
||||
end
|
||||
|
|
|
|||
|
|
@ -750,6 +750,9 @@ msgstr ""
|
|||
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
|
||||
msgstr ""
|
||||
|
||||
msgid "%{key} is not a valid URL."
|
||||
msgstr ""
|
||||
|
||||
msgid "%{labelStart}Actual response:%{labelEnd} %{headers}"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -49329,9 +49332,6 @@ msgstr ""
|
|||
msgid "is not a descendant of the Group owning the template"
|
||||
msgstr ""
|
||||
|
||||
msgid "is not a valid URL."
|
||||
msgstr ""
|
||||
|
||||
msgid "is not a valid X509 certificate."
|
||||
msgstr ""
|
||||
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ class MetricsServer # rubocop:disable Gitlab/NamespacedClass
|
|||
path = options[:path]&.then { |p| Pathname.new(p) } || Pathname.new('')
|
||||
cmd = path.join('gitlab-metrics-exporter').to_path
|
||||
env = {
|
||||
'GOGC' => '10', # Set Go GC heap goal to 10% to curb memory growth.
|
||||
'GME_MMAP_METRICS_DIR' => metrics_dir.to_s,
|
||||
'GME_PROBES' => 'self,mmap',
|
||||
'GME_SERVER_HOST' => settings['address'],
|
||||
|
|
|
|||
|
|
@ -167,6 +167,16 @@ RSpec.describe RegistrationsController do
|
|||
expect(controller.current_user).to be_nil
|
||||
end
|
||||
|
||||
it 'tracks an almost there redirect' do
|
||||
post_create
|
||||
|
||||
expect_snowplow_event(
|
||||
category: described_class.name,
|
||||
action: 'render',
|
||||
user: User.find_by(email: base_user_params[:email])
|
||||
)
|
||||
end
|
||||
|
||||
context 'when registration is triggered from an accepted invite' do
|
||||
context 'when it is part from the initial invite email', :snowplow do
|
||||
let_it_be(:member) { create(:project_member, :invited, invite_email: user_params.dig(:user, :email)) }
|
||||
|
|
@ -260,6 +270,16 @@ RSpec.describe RegistrationsController do
|
|||
expect(response).to redirect_to(users_sign_up_welcome_path)
|
||||
end
|
||||
|
||||
it 'does not track an almost there redirect' do
|
||||
post_create
|
||||
|
||||
expect_no_snowplow_event(
|
||||
category: described_class.name,
|
||||
action: 'render',
|
||||
user: User.find_by(email: base_user_params[:email])
|
||||
)
|
||||
end
|
||||
|
||||
context 'when invite email matches email used on registration' do
|
||||
let(:session_params) { { invite_email: user_params.dig(:user, :email) } }
|
||||
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ RSpec.describe 'Merge request > User sees pipelines', :js, feature_category: :co
|
|||
end
|
||||
wait_for_requests
|
||||
|
||||
expect(page).to have_selector('.stage-cell')
|
||||
expect(page).to have_css('[data-testid="pipeline-mini-graph"]')
|
||||
end
|
||||
|
||||
context 'with a detached merge request pipeline' do
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe FreezePeriodsFinder do
|
||||
RSpec.describe Ci::FreezePeriodsFinder, feature_category: :release_orchestration do
|
||||
subject(:finder) { described_class.new(project, user).execute }
|
||||
|
||||
let(:project) { create(:project, :private) }
|
||||
|
|
@ -6,9 +6,10 @@ import DraftNote from '~/batch_comments/components/draft_note.vue';
|
|||
import PublishButton from '~/batch_comments/components/publish_button.vue';
|
||||
import { createStore } from '~/batch_comments/stores';
|
||||
import NoteableNote from '~/notes/components/noteable_note.vue';
|
||||
import '~/behaviors/markdown/render_gfm';
|
||||
import { createDraft } from '../mock_data';
|
||||
|
||||
jest.mock('~/behaviors/markdown/render_gfm');
|
||||
|
||||
const NoteableNoteStub = stubComponent(NoteableNote, {
|
||||
template: `
|
||||
<div>
|
||||
|
|
|
|||
|
|
@ -3,9 +3,10 @@ import PreviewItem from '~/batch_comments/components/preview_item.vue';
|
|||
import { createStore } from '~/batch_comments/stores';
|
||||
import diffsModule from '~/diffs/store/modules';
|
||||
import notesModule from '~/notes/stores/modules';
|
||||
import '~/behaviors/markdown/render_gfm';
|
||||
import { createDraft } from '../mock_data';
|
||||
|
||||
jest.mock('~/behaviors/markdown/render_gfm');
|
||||
|
||||
describe('Batch comments draft preview item component', () => {
|
||||
let wrapper;
|
||||
let draft;
|
||||
|
|
|
|||
|
|
@ -4,9 +4,10 @@ import Vue from 'vue';
|
|||
import Vuex from 'vuex';
|
||||
import PreviewDropdown from '~/batch_comments/components/preview_dropdown.vue';
|
||||
import { createStore } from '~/mr_notes/stores';
|
||||
import '~/behaviors/markdown/render_gfm';
|
||||
import { createDraft } from '../mock_data';
|
||||
|
||||
jest.mock('~/behaviors/markdown/render_gfm');
|
||||
|
||||
Vue.use(Vuex);
|
||||
|
||||
describe('Batch comments publish dropdown component', () => {
|
||||
|
|
|
|||
|
|
@ -5,9 +5,10 @@ import { createStore } from '~/mr_notes/stores';
|
|||
import DiscussionNotes from '~/notes/components/discussion_notes.vue';
|
||||
import NoteableDiscussion from '~/notes/components/noteable_discussion.vue';
|
||||
import TimelineEntryItem from '~/vue_shared/components/notes/timeline_entry_item.vue';
|
||||
import '~/behaviors/markdown/render_gfm';
|
||||
import discussionsMockData from '../mock_data/diff_discussions';
|
||||
|
||||
jest.mock('~/behaviors/markdown/render_gfm');
|
||||
|
||||
describe('DiffDiscussions', () => {
|
||||
let store;
|
||||
let wrapper;
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import { editor as monacoEditor, Range } from 'monaco-editor';
|
|||
import Vue, { nextTick } from 'vue';
|
||||
import Vuex from 'vuex';
|
||||
import { shallowMount } from '@vue/test-utils';
|
||||
import '~/behaviors/markdown/render_gfm';
|
||||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
import { stubPerformanceWebAPI } from 'helpers/performance';
|
||||
import { exampleConfigs, exampleFiles } from 'jest/ide/lib/editorconfig/mock_data';
|
||||
|
|
@ -27,6 +26,7 @@ import ContentViewer from '~/vue_shared/components/content_viewer/content_viewer
|
|||
import SourceEditorInstance from '~/editor/source_editor_instance';
|
||||
import { file } from '../helpers';
|
||||
|
||||
jest.mock('~/behaviors/markdown/render_gfm');
|
||||
jest.mock('~/editor/extensions/source_editor_ci_schema_ext');
|
||||
|
||||
const PREVIEW_MARKDOWN_PATH = '/foo/bar/preview_markdown';
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures';
|
|||
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
|
||||
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
|
||||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
import '~/behaviors/markdown/render_gfm';
|
||||
import { createAlert } from '~/flash';
|
||||
import { IssuableStatus, IssuableStatusText, IssuableType } from '~/issues/constants';
|
||||
import IssuableApp from '~/issues/show/components/app.vue';
|
||||
|
|
@ -30,6 +29,7 @@ import {
|
|||
jest.mock('~/flash');
|
||||
jest.mock('~/issues/show/event_hub');
|
||||
jest.mock('~/lib/utils/url_utility');
|
||||
jest.mock('~/behaviors/markdown/render_gfm');
|
||||
|
||||
const REALTIME_REQUEST_STACK = [initialRequest, secondRequest];
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import $ from 'jquery';
|
||||
import Vue, { nextTick } from 'vue';
|
||||
import VueApollo from 'vue-apollo';
|
||||
import '~/behaviors/markdown/render_gfm';
|
||||
import { GlTooltip, GlModal } from '@gitlab/ui';
|
||||
|
||||
import setWindowLocation from 'helpers/set_window_location_helper';
|
||||
|
|
@ -21,6 +20,7 @@ import createWorkItemFromTaskMutation from '~/work_items/graphql/create_work_ite
|
|||
import TaskList from '~/task_list';
|
||||
import WorkItemDetailModal from '~/work_items/components/work_item_detail_modal.vue';
|
||||
import { TRACKING_CATEGORY_SHOW } from '~/work_items/constants';
|
||||
import { renderGFM } from '~/behaviors/markdown/render_gfm';
|
||||
import {
|
||||
projectWorkItemTypesQueryResponse,
|
||||
createWorkItemFromTaskMutationResponse,
|
||||
|
|
@ -37,6 +37,7 @@ jest.mock('~/lib/utils/url_utility', () => ({
|
|||
updateHistory: jest.fn(),
|
||||
}));
|
||||
jest.mock('~/task_list');
|
||||
jest.mock('~/behaviors/markdown/render_gfm');
|
||||
|
||||
const showModal = jest.fn();
|
||||
const hideModal = jest.fn();
|
||||
|
|
@ -161,7 +162,6 @@ describe('Description component', () => {
|
|||
});
|
||||
|
||||
it('applies syntax highlighting and math when description changed', async () => {
|
||||
const prototypeSpy = jest.spyOn($.prototype, 'renderGFM');
|
||||
createComponent();
|
||||
|
||||
await wrapper.setProps({
|
||||
|
|
@ -169,7 +169,7 @@ describe('Description component', () => {
|
|||
});
|
||||
|
||||
expect(findGfmContent().exists()).toBe(true);
|
||||
expect(prototypeSpy).toHaveBeenCalled();
|
||||
expect(renderGFM).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('sets data-update-url', () => {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import { getByRole } from '@testing-library/dom';
|
||||
import { shallowMount, mount } from '@vue/test-utils';
|
||||
import '~/behaviors/markdown/render_gfm';
|
||||
import { nextTick } from 'vue';
|
||||
import DiscussionNotes from '~/notes/components/discussion_notes.vue';
|
||||
import NoteableNote from '~/notes/components/noteable_note.vue';
|
||||
|
|
@ -11,6 +10,8 @@ import PlaceholderSystemNote from '~/vue_shared/components/notes/placeholder_sys
|
|||
import SystemNote from '~/vue_shared/components/notes/system_note.vue';
|
||||
import { noteableDataMock, discussionMock, notesDataMock } from '../mock_data';
|
||||
|
||||
jest.mock('~/behaviors/markdown/render_gfm');
|
||||
|
||||
const LINE_RANGE = {};
|
||||
const DISCUSSION_WITH_LINE_RANGE = {
|
||||
...discussionMock,
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ import ResolveWithIssueButton from '~/notes/components/discussion_resolve_with_i
|
|||
import NoteForm from '~/notes/components/note_form.vue';
|
||||
import NoteableDiscussion from '~/notes/components/noteable_discussion.vue';
|
||||
import createStore from '~/notes/stores';
|
||||
import '~/behaviors/markdown/render_gfm';
|
||||
import {
|
||||
noteableDataMock,
|
||||
discussionMock,
|
||||
|
|
@ -18,6 +17,8 @@ import {
|
|||
userDataMock,
|
||||
} from '../mock_data';
|
||||
|
||||
jest.mock('~/behaviors/markdown/render_gfm');
|
||||
|
||||
describe('noteable_discussion component', () => {
|
||||
let store;
|
||||
let wrapper;
|
||||
|
|
|
|||
|
|
@ -14,11 +14,12 @@ import NotesApp from '~/notes/components/notes_app.vue';
|
|||
import NotesActivityHeader from '~/notes/components/notes_activity_header.vue';
|
||||
import * as constants from '~/notes/constants';
|
||||
import createStore from '~/notes/stores';
|
||||
import '~/behaviors/markdown/render_gfm';
|
||||
// TODO: use generated fixture (https://gitlab.com/gitlab-org/gitlab-foss/issues/62491)
|
||||
import OrderedLayout from '~/vue_shared/components/ordered_layout.vue';
|
||||
import * as mockData from '../mock_data';
|
||||
|
||||
jest.mock('~/behaviors/markdown/render_gfm');
|
||||
|
||||
const TYPE_COMMENT_FORM = 'comment-form';
|
||||
const TYPE_NOTES_LIST = 'notes-list';
|
||||
const TEST_NOTES_FILTER_VALUE = 1;
|
||||
|
|
|
|||
|
|
@ -3,13 +3,13 @@ import { nextTick } from 'vue';
|
|||
import { shallowMount } from '@vue/test-utils';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import WikiContent from '~/pages/shared/wikis/components/wiki_content.vue';
|
||||
import { renderGFM } from '~/pages/shared/wikis/render_gfm_facade';
|
||||
import { renderGFM } from '~/behaviors/markdown/render_gfm';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import httpStatus from '~/lib/utils/http_status';
|
||||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
import { handleLocationHash } from '~/lib/utils/common_utils';
|
||||
|
||||
jest.mock('~/pages/shared/wikis/render_gfm_facade');
|
||||
jest.mock('~/behaviors/markdown/render_gfm');
|
||||
jest.mock('~/lib/utils/common_utils');
|
||||
|
||||
describe('pages/shared/wikis/components/wiki_content', () => {
|
||||
|
|
|
|||
|
|
@ -48,7 +48,6 @@ describe('Pipeline Mini Graph', () => {
|
|||
isMergeTrain: false,
|
||||
pipelinePath: '',
|
||||
stages: expect.any(Array),
|
||||
stagesClass: '',
|
||||
updateDropdown: false,
|
||||
upstreamPipeline: undefined,
|
||||
});
|
||||
|
|
@ -83,7 +82,6 @@ describe('Pipeline Mini Graph', () => {
|
|||
isMergeTrain: false,
|
||||
pipelinePath: '',
|
||||
stages: expect.any(Array),
|
||||
stagesClass: '',
|
||||
updateDropdown: false,
|
||||
upstreamPipeline: expect.any(Object),
|
||||
});
|
||||
|
|
@ -115,7 +113,6 @@ describe('Pipeline Mini Graph', () => {
|
|||
isMergeTrain: false,
|
||||
pipelinePath: 'my/pipeline/path',
|
||||
stages: expect.any(Array),
|
||||
stagesClass: '',
|
||||
updateDropdown: false,
|
||||
upstreamPipeline: undefined,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -26,12 +26,6 @@ describe('Pipeline Stages', () => {
|
|||
expect(findPipelineStages()).toHaveLength(mockStages.length);
|
||||
});
|
||||
|
||||
it('renders stages with a custom class', () => {
|
||||
createComponent({ stagesClass: 'my-class' });
|
||||
|
||||
expect(wrapper.findAll('.my-class')).toHaveLength(mockStages.length);
|
||||
});
|
||||
|
||||
it('does not fail when stages are empty', () => {
|
||||
createComponent({ stages: [] });
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import { mount } from '@vue/test-utils';
|
||||
import $ from 'jquery';
|
||||
import { nextTick } from 'vue';
|
||||
import originalOneReleaseQueryResponse from 'test_fixtures/graphql/releases/graphql/queries/one_release.query.graphql.json';
|
||||
import { convertOneReleaseGraphQLResponse } from '~/releases/util';
|
||||
|
|
@ -10,6 +9,9 @@ import ReleaseBlock from '~/releases/components/release_block.vue';
|
|||
import ReleaseBlockFooter from '~/releases/components/release_block_footer.vue';
|
||||
import { BACK_URL_PARAM } from '~/releases/constants';
|
||||
import timeagoMixin from '~/vue_shared/mixins/timeago';
|
||||
import { renderGFM } from '~/behaviors/markdown/render_gfm';
|
||||
|
||||
jest.mock('~/behaviors/markdown/render_gfm');
|
||||
|
||||
describe('Release block', () => {
|
||||
let wrapper;
|
||||
|
|
@ -34,7 +36,6 @@ describe('Release block', () => {
|
|||
const editButton = () => wrapper.find('.js-edit-button');
|
||||
|
||||
beforeEach(() => {
|
||||
jest.spyOn($.fn, 'renderGFM');
|
||||
release = convertOneReleaseGraphQLResponse(originalOneReleaseQueryResponse).data;
|
||||
});
|
||||
|
||||
|
|
@ -62,7 +63,7 @@ describe('Release block', () => {
|
|||
|
||||
it('renders release description', () => {
|
||||
expect(wrapper.vm.$refs['gfm-content']).toBeDefined();
|
||||
expect($.fn.renderGFM).toHaveBeenCalledTimes(1);
|
||||
expect(renderGFM).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('renders release date', () => {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import $ from 'jquery';
|
||||
import { merge } from 'lodash';
|
||||
import { GlIntersectionObserver } from '@gitlab/ui';
|
||||
import { nextTick } from 'vue';
|
||||
|
|
@ -7,13 +6,14 @@ import { mountExtended } from 'helpers/vue_test_utils_helper';
|
|||
import { FLASH_TYPES, FLASH_CLOSED_EVENT } from '~/flash';
|
||||
import { isLoggedIn } from '~/lib/utils/common_utils';
|
||||
import TermsApp from '~/terms/components/app.vue';
|
||||
import { renderGFM } from '~/behaviors/markdown/render_gfm';
|
||||
|
||||
jest.mock('~/lib/utils/csrf', () => ({ token: 'mock-csrf-token' }));
|
||||
jest.mock('~/lib/utils/common_utils');
|
||||
jest.mock('~/behaviors/markdown/render_gfm');
|
||||
|
||||
describe('TermsApp', () => {
|
||||
let wrapper;
|
||||
let renderGFMSpy;
|
||||
|
||||
const defaultProvide = {
|
||||
terms: 'foo bar',
|
||||
|
|
@ -35,7 +35,6 @@ describe('TermsApp', () => {
|
|||
};
|
||||
|
||||
beforeEach(() => {
|
||||
renderGFMSpy = jest.spyOn($.fn, 'renderGFM');
|
||||
isLoggedIn.mockReturnValue(true);
|
||||
});
|
||||
|
||||
|
|
@ -65,7 +64,7 @@ describe('TermsApp', () => {
|
|||
createComponent();
|
||||
|
||||
expect(wrapper.findByText(defaultProvide.terms).exists()).toBe(true);
|
||||
expect(renderGFMSpy).toHaveBeenCalled();
|
||||
expect(renderGFM).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe('accept button', () => {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
import { mount } from '@vue/test-utils';
|
||||
import { GREEN_BOX_IMAGE_URL } from 'spec/test_constants';
|
||||
import ContentViewer from '~/vue_shared/components/content_viewer/content_viewer.vue';
|
||||
import '~/behaviors/markdown/render_gfm';
|
||||
|
||||
jest.mock('~/behaviors/markdown/render_gfm');
|
||||
|
||||
describe('ContentViewer', () => {
|
||||
let wrapper;
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
import { GlSkeletonLoader } from '@gitlab/ui';
|
||||
import { mount } from '@vue/test-utils';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import $ from 'jquery';
|
||||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import MarkdownViewer from '~/vue_shared/components/content_viewer/viewers/markdown_viewer.vue';
|
||||
|
||||
jest.mock('~/behaviors/markdown/render_gfm');
|
||||
|
||||
describe('MarkdownViewer', () => {
|
||||
let wrapper;
|
||||
let mock;
|
||||
|
|
@ -26,7 +27,6 @@ describe('MarkdownViewer', () => {
|
|||
mock = new MockAdapter(axios);
|
||||
|
||||
jest.spyOn(axios, 'post');
|
||||
jest.spyOn($.fn, 'renderGFM');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
|
|
|||
|
|
@ -1,12 +1,14 @@
|
|||
import { nextTick } from 'vue';
|
||||
import AxiosMockAdapter from 'axios-mock-adapter';
|
||||
import $ from 'jquery';
|
||||
import { TEST_HOST, FIXTURES_PATH } from 'spec/test_constants';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import MarkdownField from '~/vue_shared/components/markdown/field.vue';
|
||||
import MarkdownFieldHeader from '~/vue_shared/components/markdown/header.vue';
|
||||
import MarkdownToolbar from '~/vue_shared/components/markdown/toolbar.vue';
|
||||
import { mountExtended } from 'helpers/vue_test_utils_helper';
|
||||
import { renderGFM } from '~/behaviors/markdown/render_gfm';
|
||||
|
||||
jest.mock('~/behaviors/markdown/render_gfm');
|
||||
|
||||
const markdownPreviewPath = `${TEST_HOST}/preview`;
|
||||
const markdownDocsPath = `${TEST_HOST}/docs`;
|
||||
|
|
@ -138,15 +140,13 @@ describe('Markdown field component', () => {
|
|||
});
|
||||
|
||||
it('renders markdown preview and GFM', async () => {
|
||||
const renderGFMSpy = jest.spyOn($.fn, 'renderGFM');
|
||||
|
||||
previewLink = getPreviewLink();
|
||||
|
||||
previewLink.vm.$emit('click', { target: {} });
|
||||
|
||||
await axios.waitFor(markdownPreviewPath);
|
||||
expect(subject.find('.md-preview-holder').element.innerHTML).toContain(previewHTML);
|
||||
expect(renderGFMSpy).toHaveBeenCalled();
|
||||
expect(renderGFM).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('calls video.pause() on comment input when isSubmitting is changed to true', async () => {
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
import { shallowMount } from '@vue/test-utils';
|
||||
import $ from 'jquery';
|
||||
|
||||
import MarkdownFieldView from '~/vue_shared/components/markdown/field_view.vue';
|
||||
import { renderGFM } from '~/behaviors/markdown/render_gfm';
|
||||
|
||||
jest.mock('~/behaviors/markdown/render_gfm');
|
||||
|
||||
describe('Markdown Field View component', () => {
|
||||
let renderGFMSpy;
|
||||
let wrapper;
|
||||
|
||||
function createComponent() {
|
||||
|
|
@ -12,7 +13,6 @@ describe('Markdown Field View component', () => {
|
|||
}
|
||||
|
||||
beforeEach(() => {
|
||||
renderGFMSpy = jest.spyOn($.fn, 'renderGFM');
|
||||
createComponent();
|
||||
});
|
||||
|
||||
|
|
@ -21,6 +21,6 @@ describe('Markdown Field View component', () => {
|
|||
});
|
||||
|
||||
it('processes rendering with GFM', () => {
|
||||
expect(renderGFMSpy).toHaveBeenCalledTimes(1);
|
||||
expect(renderGFM).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
import MockAdapter from 'axios-mock-adapter';
|
||||
import { mount } from '@vue/test-utils';
|
||||
import $ from 'jquery';
|
||||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
import createStore from '~/notes/stores';
|
||||
import IssueSystemNote from '~/vue_shared/components/notes/system_note.vue';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { renderGFM } from '~/behaviors/markdown/render_gfm';
|
||||
|
||||
jest.mock('~/behaviors/markdown/render_gfm');
|
||||
|
||||
describe('system note component', () => {
|
||||
let vm;
|
||||
|
|
@ -75,11 +77,9 @@ describe('system note component', () => {
|
|||
});
|
||||
|
||||
it('should renderGFM onMount', () => {
|
||||
const renderGFMSpy = jest.spyOn($.fn, 'renderGFM');
|
||||
|
||||
createComponent(props);
|
||||
|
||||
expect(renderGFMSpy).toHaveBeenCalled();
|
||||
expect(renderGFM).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('renders outdated code lines', async () => {
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
import { shallowMount } from '@vue/test-utils';
|
||||
import $ from 'jquery';
|
||||
|
||||
import IssuableDescription from '~/vue_shared/issuable/show/components/issuable_description.vue';
|
||||
import { renderGFM } from '~/behaviors/markdown/render_gfm';
|
||||
|
||||
import { mockIssuable } from '../mock_data';
|
||||
|
||||
jest.mock('~/behaviors/markdown/render_gfm');
|
||||
|
||||
const createComponent = ({
|
||||
issuable = mockIssuable,
|
||||
enableTaskList = true,
|
||||
|
|
@ -16,11 +18,9 @@ const createComponent = ({
|
|||
});
|
||||
|
||||
describe('IssuableDescription', () => {
|
||||
let renderGFMSpy;
|
||||
let wrapper;
|
||||
|
||||
beforeEach(() => {
|
||||
renderGFMSpy = jest.spyOn($.fn, 'renderGFM');
|
||||
wrapper = createComponent();
|
||||
});
|
||||
|
||||
|
|
@ -30,17 +30,7 @@ describe('IssuableDescription', () => {
|
|||
|
||||
describe('mounted', () => {
|
||||
it('calls `renderGFM`', () => {
|
||||
expect(renderGFMSpy).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('methods', () => {
|
||||
describe('renderGFM', () => {
|
||||
it('calls `renderGFM` on container element', () => {
|
||||
wrapper.vm.renderGFM();
|
||||
|
||||
expect(renderGFMSpy).toHaveBeenCalled();
|
||||
});
|
||||
expect(renderGFM).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,14 @@
|
|||
import { GlIcon } from '@gitlab/ui';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import { shallowMount } from '@vue/test-utils';
|
||||
import $ from 'jquery';
|
||||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
import { renderGFM } from '~/behaviors/markdown/render_gfm';
|
||||
import WorkItemSystemNote from '~/work_items/components/notes/system_note.vue';
|
||||
import NoteHeader from '~/notes/components/note_header.vue';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
|
||||
jest.mock('~/behaviors/markdown/render_gfm');
|
||||
|
||||
describe('system note component', () => {
|
||||
let wrapper;
|
||||
let props;
|
||||
|
|
@ -84,11 +86,9 @@ describe('system note component', () => {
|
|||
});
|
||||
|
||||
it('should renderGFM onMount', () => {
|
||||
const renderGFMSpy = jest.spyOn($.fn, 'renderGFM');
|
||||
|
||||
createComponent(props);
|
||||
|
||||
expect(renderGFMSpy).toHaveBeenCalled();
|
||||
expect(renderGFM).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
// eslint-disable-next-line jest/no-disabled-tests
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
import { shallowMount } from '@vue/test-utils';
|
||||
import $ from 'jquery';
|
||||
import { nextTick } from 'vue';
|
||||
import WorkItemDescriptionRendered from '~/work_items/components/work_item_description_rendered.vue';
|
||||
import { renderGFM } from '~/behaviors/markdown/render_gfm';
|
||||
import { descriptionTextWithCheckboxes, descriptionHtmlWithCheckboxes } from '../mock_data';
|
||||
|
||||
jest.mock('~/behaviors/markdown/render_gfm');
|
||||
|
||||
describe('WorkItemDescription', () => {
|
||||
let wrapper;
|
||||
|
||||
|
|
@ -32,13 +34,11 @@ describe('WorkItemDescription', () => {
|
|||
});
|
||||
|
||||
it('renders gfm', async () => {
|
||||
const renderGFMSpy = jest.spyOn($.fn, 'renderGFM');
|
||||
|
||||
createComponent();
|
||||
|
||||
await nextTick();
|
||||
|
||||
expect(renderGFMSpy).toHaveBeenCalled();
|
||||
expect(renderGFM).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe('with checkboxes', () => {
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@ import CreateWorkItem from '~/work_items/pages/create_work_item.vue';
|
|||
import WorkItemsRoot from '~/work_items/pages/work_item_root.vue';
|
||||
import { createRouter } from '~/work_items/router';
|
||||
|
||||
jest.mock('~/behaviors/markdown/render_gfm');
|
||||
|
||||
describe('Work items router', () => {
|
||||
let wrapper;
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ require 'spec_helper'
|
|||
|
||||
require_relative '../../metrics_server/metrics_server'
|
||||
|
||||
RSpec.describe MetricsServer do # rubocop:disable RSpec/FilePath
|
||||
RSpec.describe MetricsServer, feature_category: :application_performance do # rubocop:disable RSpec/FilePath
|
||||
let(:prometheus_config) { ::Prometheus::Client.configuration }
|
||||
let(:metrics_dir) { Dir.mktmpdir }
|
||||
|
||||
|
|
@ -118,6 +118,7 @@ RSpec.describe MetricsServer do # rubocop:disable RSpec/FilePath
|
|||
let(:expected_port) { target == 'puma' ? '8083' : '8082' }
|
||||
let(:expected_env) do
|
||||
{
|
||||
'GOGC' => '10',
|
||||
'GME_MMAP_METRICS_DIR' => metrics_dir,
|
||||
'GME_PROBES' => 'self,mmap',
|
||||
'GME_SERVER_HOST' => 'localhost',
|
||||
|
|
|
|||
|
|
@ -183,25 +183,25 @@ RSpec.describe PipelineSerializer do
|
|||
|
||||
context 'with triggered pipelines' do
|
||||
before do
|
||||
pipeline_1 = create(:ci_pipeline)
|
||||
pipeline_1 = create(:ci_pipeline, project: project)
|
||||
build_1 = create(:ci_build, pipeline: pipeline_1)
|
||||
create(:ci_sources_pipeline, source_job: build_1)
|
||||
|
||||
pipeline_2 = create(:ci_pipeline)
|
||||
build_2 = create(:ci_build, pipeline: pipeline_2)
|
||||
create(:ci_sources_pipeline, source_job: build_2)
|
||||
end
|
||||
|
||||
it 'verifies number of queries', :request_store do
|
||||
recorded = ActiveRecord::QueryRecorder.new { subject }
|
||||
control = ActiveRecord::QueryRecorder.new do
|
||||
serializer.represent(Ci::Pipeline.all, preload: true)
|
||||
end
|
||||
|
||||
# Existing numbers are high and require performance optimization
|
||||
# Ongoing issue:
|
||||
# https://gitlab.com/gitlab-org/gitlab/-/issues/225156
|
||||
expected_queries = Gitlab.ee? ? 78 : 74
|
||||
pipeline_2 = create(:ci_pipeline, project: project)
|
||||
build_2 = create(:ci_build, pipeline: pipeline_2)
|
||||
create(:ci_sources_pipeline, source_job: build_2)
|
||||
|
||||
expect(recorded.count).to be_within(2).of(expected_queries)
|
||||
expect(recorded.cached_count).to eq(0)
|
||||
recorded = ActiveRecord::QueryRecorder.new do
|
||||
serializer.represent(Ci::Pipeline.all, preload: true)
|
||||
end
|
||||
|
||||
expect(recorded).not_to exceed_query_limit(control)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue