diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-07-28 00:09:42 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-07-28 00:09:42 +0300 |
commit | 6456305e5810391463cdf58d9b4952903047c05a (patch) | |
tree | 3a770fdf551d1fbba8bd9950a9961029c92f9c59 | |
parent | c241fef1814b6f2fc5931f3d1e26de0378c02ccf (diff) |
Add latest changes from gitlab-org/gitlab@master
70 files changed, 452 insertions, 500 deletions
diff --git a/.gitlab/ci/frontend.gitlab-ci.yml b/.gitlab/ci/frontend.gitlab-ci.yml index 3aa8ab1591a..318ac20435e 100644 --- a/.gitlab/ci/frontend.gitlab-ci.yml +++ b/.gitlab/ci/frontend.gitlab-ci.yml @@ -15,6 +15,9 @@ variables: SETUP_DB: "false" WEBPACK_VENDOR_DLL: "true" + # Disable warnings in browserslist which can break on backports + # https://github.com/browserslist/browserslist/blob/a287ec6/node.js#L367-L384 + BROWSERSLIST_IGNORE_OLD_DATA: "true" stage: prepare script: - *yarn-install @@ -164,6 +167,10 @@ graphql-schema-dump: extends: - .default-retry - .yarn-cache + variables: + # Disable warnings in browserslist which can break on backports + # https://github.com/browserslist/browserslist/blob/a287ec6/node.js#L367-L384 + BROWSERSLIST_IGNORE_OLD_DATA: "true" stage: test eslint-as-if-foss: diff --git a/.gitlab/ci/rails.gitlab-ci.yml b/.gitlab/ci/rails.gitlab-ci.yml index eda1ba49254..af0861dd8b3 100644 --- a/.gitlab/ci/rails.gitlab-ci.yml +++ b/.gitlab/ci/rails.gitlab-ci.yml @@ -234,6 +234,9 @@ update-gitaly-binaries-cache: variables: SETUP_DB: "false" ENABLE_SPRING: "1" + # Disable warnings in browserslist which can break on backports + # https://github.com/browserslist/browserslist/blob/a287ec6/node.js#L367-L384 + BROWSERSLIST_IGNORE_OLD_DATA: "true" update-static-analysis-cache: extends: @@ -394,7 +394,7 @@ group :development, :test do end group :development, :test, :danger do - gem 'gitlab-dangerfiles', '~> 2.2.2', require: false + gem 'gitlab-dangerfiles', '~> 2.3.0', require: false end group :development, :test, :coverage do diff --git a/Gemfile.lock b/Gemfile.lock index 617e1f18caa..7cd04312b94 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -460,7 +460,7 @@ GEM terminal-table (~> 1.5, >= 1.5.1) gitlab-chronic (0.10.5) numerizer (~> 0.2) - gitlab-dangerfiles (2.2.2) + gitlab-dangerfiles (2.3.0) danger (>= 8.3.1) danger-gitlab (>= 8.0.0) gitlab-experiment (0.6.2) @@ -1467,7 +1467,7 @@ DEPENDENCIES gitaly (~> 14.1.0.pre.rc4) github-markup (~> 1.7.0) gitlab-chronic (~> 0.10.5) - gitlab-dangerfiles (~> 2.2.2) + gitlab-dangerfiles (~> 2.3.0) gitlab-experiment (~> 0.6.2) gitlab-fog-azure-rm (~> 1.1.1) gitlab-labkit (~> 0.21.0) diff --git a/app/assets/javascripts/blob/csv/csv_viewer.vue b/app/assets/javascripts/blob/csv/csv_viewer.vue index 050f2785d9a..1f9d20a487f 100644 --- a/app/assets/javascripts/blob/csv/csv_viewer.vue +++ b/app/assets/javascripts/blob/csv/csv_viewer.vue @@ -1,11 +1,12 @@ <script> -import { GlAlert, GlLoadingIcon, GlTable } from '@gitlab/ui'; +import { GlLoadingIcon, GlTable } from '@gitlab/ui'; import Papa from 'papaparse'; +import PapaParseAlert from '~/vue_shared/components/papa_parse_alert.vue'; export default { components: { + PapaParseAlert, GlTable, - GlAlert, GlLoadingIcon, }, props: { @@ -17,7 +18,7 @@ export default { data() { return { items: [], - errorMessage: null, + papaParseErrors: [], loading: true, }; }, @@ -26,7 +27,7 @@ export default { this.items = parsed.data; if (parsed.errors.length) { - this.errorMessage = parsed.errors.map((e) => e.message).join('. '); + this.papaParseErrors = parsed.errors; } this.loading = false; @@ -40,9 +41,7 @@ export default { <gl-loading-icon class="gl-mt-5" size="lg" /> </div> <div v-else> - <gl-alert v-if="errorMessage" variant="danger" :dismissible="false"> - {{ errorMessage }} - </gl-alert> + <papa-parse-alert v-if="papaParseErrors.length" :papa-parse-errors="papaParseErrors" /> <gl-table :empty-text="__('No CSV data to display.')" :items="items" diff --git a/app/assets/javascripts/content_editor/components/toolbar_link_button.vue b/app/assets/javascripts/content_editor/components/toolbar_link_button.vue index 8f57959a73f..f9d2be7070b 100644 --- a/app/assets/javascripts/content_editor/components/toolbar_link_button.vue +++ b/app/assets/javascripts/content_editor/components/toolbar_link_button.vue @@ -9,10 +9,9 @@ import { GlTooltipDirective as GlTooltip, } from '@gitlab/ui'; import { Editor as TiptapEditor } from '@tiptap/vue-2'; +import Link from '../extensions/link'; import { hasSelection } from '../services/utils'; -export const linkContentType = 'link'; - export default { components: { GlDropdown, @@ -38,12 +37,12 @@ export default { }, computed: { isActive() { - return this.tiptapEditor.isActive(linkContentType); + return this.tiptapEditor.isActive(Link.name); }, }, mounted() { this.tiptapEditor.on('selectionUpdate', ({ editor }) => { - const { canonicalSrc, href } = editor.getAttributes(linkContentType); + const { canonicalSrc, href } = editor.getAttributes(Link.name); this.linkHref = canonicalSrc || href; }); @@ -60,20 +59,20 @@ export default { }) .run(); - this.$emit('execute', { contentType: linkContentType }); + this.$emit('execute', { contentType: Link.name }); }, selectLink() { const { tiptapEditor } = this; // a selection has already been made by the user, so do nothing if (!hasSelection(tiptapEditor)) { - tiptapEditor.chain().focus().extendMarkRange(linkContentType).run(); + tiptapEditor.chain().focus().extendMarkRange(Link.name).run(); } }, removeLink() { this.tiptapEditor.chain().focus().unsetLink().run(); - this.$emit('execute', { contentType: linkContentType }); + this.$emit('execute', { contentType: Link.name }); }, }, }; diff --git a/app/assets/javascripts/content_editor/extensions/blockquote.js b/app/assets/javascripts/content_editor/extensions/blockquote.js index a4297b4550c..45f53fe230b 100644 --- a/app/assets/javascripts/content_editor/extensions/blockquote.js +++ b/app/assets/javascripts/content_editor/extensions/blockquote.js @@ -1,5 +1 @@ -import { Blockquote } from '@tiptap/extension-blockquote'; -import { defaultMarkdownSerializer } from 'prosemirror-markdown/src/to_markdown'; - -export const tiptapExtension = Blockquote; -export const serializer = defaultMarkdownSerializer.nodes.blockquote; +export { Blockquote as default } from '@tiptap/extension-blockquote'; diff --git a/app/assets/javascripts/content_editor/extensions/bold.js b/app/assets/javascripts/content_editor/extensions/bold.js index e90e7b59da0..0b7b22265b6 100644 --- a/app/assets/javascripts/content_editor/extensions/bold.js +++ b/app/assets/javascripts/content_editor/extensions/bold.js @@ -1,5 +1 @@ -import { Bold } from '@tiptap/extension-bold'; -import { defaultMarkdownSerializer } from 'prosemirror-markdown/src/to_markdown'; - -export const tiptapExtension = Bold; -export const serializer = defaultMarkdownSerializer.marks.strong; +export { Bold as default } from '@tiptap/extension-bold'; diff --git a/app/assets/javascripts/content_editor/extensions/bullet_list.js b/app/assets/javascripts/content_editor/extensions/bullet_list.js index 178b798e2d4..01ead571fe1 100644 --- a/app/assets/javascripts/content_editor/extensions/bullet_list.js +++ b/app/assets/javascripts/content_editor/extensions/bullet_list.js @@ -1,5 +1 @@ -import { BulletList } from '@tiptap/extension-bullet-list'; -import { defaultMarkdownSerializer } from 'prosemirror-markdown/src/to_markdown'; - -export const tiptapExtension = BulletList; -export const serializer = defaultMarkdownSerializer.nodes.bullet_list; +export { BulletList as default } from '@tiptap/extension-bullet-list'; diff --git a/app/assets/javascripts/content_editor/extensions/code.js b/app/assets/javascripts/content_editor/extensions/code.js index 8be50dc39c5..f93c22ad10e 100644 --- a/app/assets/javascripts/content_editor/extensions/code.js +++ b/app/assets/javascripts/content_editor/extensions/code.js @@ -1,5 +1 @@ -import { Code } from '@tiptap/extension-code'; -import { defaultMarkdownSerializer } from 'prosemirror-markdown/src/to_markdown'; - -export const tiptapExtension = Code; -export const serializer = defaultMarkdownSerializer.marks.code; +export { Code as default } from '@tiptap/extension-code'; diff --git a/app/assets/javascripts/content_editor/extensions/code_block_highlight.js b/app/assets/javascripts/content_editor/extensions/code_block_highlight.js index 50d72f4089a..177ea4c2e7d 100644 --- a/app/assets/javascripts/content_editor/extensions/code_block_highlight.js +++ b/app/assets/javascripts/content_editor/extensions/code_block_highlight.js @@ -1,10 +1,9 @@ import { CodeBlockLowlight } from '@tiptap/extension-code-block-lowlight'; import * as lowlight from 'lowlight'; -import { defaultMarkdownSerializer } from 'prosemirror-markdown/src/to_markdown'; const extractLanguage = (element) => element.getAttribute('lang'); -const ExtendedCodeBlockLowlight = CodeBlockLowlight.extend({ +export default CodeBlockLowlight.extend({ addAttributes() { return { language: { @@ -38,6 +37,3 @@ const ExtendedCodeBlockLowlight = CodeBlockLowlight.extend({ }).configure({ lowlight, }); - -export const tiptapExtension = ExtendedCodeBlockLowlight; -export const serializer = defaultMarkdownSerializer.nodes.code_block; diff --git a/app/assets/javascripts/content_editor/extensions/document.js b/app/assets/javascripts/content_editor/extensions/document.js index 99aa8d6235a..27496fd60b7 100644 --- a/app/assets/javascripts/content_editor/extensions/document.js +++ b/app/assets/javascripts/content_editor/extensions/document.js @@ -1,3 +1 @@ -import Document from '@tiptap/extension-document'; - -export const tiptapExtension = Document; +export { Document as default } from '@tiptap/extension-document'; diff --git a/app/assets/javascripts/content_editor/extensions/dropcursor.js b/app/assets/javascripts/content_editor/extensions/dropcursor.js index 44c378ac7db..825dc73b9d9 100644 --- a/app/assets/javascripts/content_editor/extensions/dropcursor.js +++ b/app/assets/javascripts/content_editor/extensions/dropcursor.js @@ -1,3 +1 @@ -import Dropcursor from '@tiptap/extension-dropcursor'; - -export const tiptapExtension = Dropcursor; +export { Dropcursor as default } from '@tiptap/extension-dropcursor'; diff --git a/app/assets/javascripts/content_editor/extensions/gapcursor.js b/app/assets/javascripts/content_editor/extensions/gapcursor.js index 2db862e4580..ef88cd92b4e 100644 --- a/app/assets/javascripts/content_editor/extensions/gapcursor.js +++ b/app/assets/javascripts/content_editor/extensions/gapcursor.js @@ -1,3 +1 @@ -import Gapcursor from '@tiptap/extension-gapcursor'; - -export const tiptapExtension = Gapcursor; +export { Gapcursor as default } from '@tiptap/extension-gapcursor'; diff --git a/app/assets/javascripts/content_editor/extensions/hard_break.js b/app/assets/javascripts/content_editor/extensions/hard_break.js index 756eefa875c..fb81c6b79b6 100644 --- a/app/assets/javascripts/content_editor/extensions/hard_break.js +++ b/app/assets/javascripts/content_editor/extensions/hard_break.js @@ -1,13 +1,9 @@ import { HardBreak } from '@tiptap/extension-hard-break'; -import { defaultMarkdownSerializer } from 'prosemirror-markdown/src/to_markdown'; -const ExtendedHardBreak = HardBreak.extend({ +export default HardBreak.extend({ addKeyboardShortcuts() { return { 'Shift-Enter': () => this.editor.commands.setHardBreak(), }; }, }); - -export const tiptapExtension = ExtendedHardBreak; -export const serializer = defaultMarkdownSerializer.nodes.hard_break; diff --git a/app/assets/javascripts/content_editor/extensions/heading.js b/app/assets/javascripts/content_editor/extensions/heading.js index f69869d1e09..48303cdeca4 100644 --- a/app/assets/javascripts/content_editor/extensions/heading.js +++ b/app/assets/javascripts/content_editor/extensions/heading.js @@ -1,5 +1 @@ -import { Heading } from '@tiptap/extension-heading'; -import { defaultMarkdownSerializer } from 'prosemirror-markdown/src/to_markdown'; - -export const tiptapExtension = Heading; -export const serializer = defaultMarkdownSerializer.nodes.heading; +export { Heading as default } from '@tiptap/extension-heading'; diff --git a/app/assets/javascripts/content_editor/extensions/history.js b/app/assets/javascripts/content_editor/extensions/history.js index 554d797d30a..7c9d92d7b4e 100644 --- a/app/assets/javascripts/content_editor/extensions/history.js +++ b/app/assets/javascripts/content_editor/extensions/history.js @@ -1,3 +1 @@ -import History from '@tiptap/extension-history'; - -export const tiptapExtension = History; +export { History as default } from '@tiptap/extension-history'; diff --git a/app/assets/javascripts/content_editor/extensions/horizontal_rule.js b/app/assets/javascripts/content_editor/extensions/horizontal_rule.js index c287938af5c..c8ec45d835c 100644 --- a/app/assets/javascripts/content_editor/extensions/horizontal_rule.js +++ b/app/assets/javascripts/content_editor/extensions/horizontal_rule.js @@ -1,12 +1,10 @@ import { nodeInputRule } from '@tiptap/core'; import { HorizontalRule } from '@tiptap/extension-horizontal-rule'; -import { defaultMarkdownSerializer } from 'prosemirror-markdown/src/to_markdown'; export const hrInputRuleRegExp = /^---$/; -export const tiptapExtension = HorizontalRule.extend({ +export default HorizontalRule.extend({ addInputRules() { return [nodeInputRule(hrInputRuleRegExp, this.type)]; }, }); -export const serializer = defaultMarkdownSerializer.nodes.horizontal_rule; diff --git a/app/assets/javascripts/content_editor/extensions/image.js b/app/assets/javascripts/content_editor/extensions/image.js index 4dd8a1376ad..6051098d776 100644 --- a/app/assets/javascripts/content_editor/extensions/image.js +++ b/app/assets/javascripts/content_editor/extensions/image.js @@ -48,11 +48,12 @@ const handleFileEvent = ({ editor, file, uploadsPath, renderMarkdown }) => { return false; }; -const ExtendedImage = Image.extend({ +export default Image.extend({ defaultOptions: { ...Image.options, uploadsPath: null, renderMarkdown: null, + inline: true, }, addAttributes() { return { @@ -152,17 +153,3 @@ const ExtendedImage = Image.extend({ return VueNodeViewRenderer(ImageWrapper); }, }); - -const serializer = (state, node) => { - const { alt, canonicalSrc, src, title } = node.attrs; - const quotedTitle = title ? ` ${state.quote(title)}` : ''; - - state.write(`![${state.esc(alt || '')}](${state.esc(canonicalSrc || src)}${quotedTitle})`); -}; - -export const configure = ({ renderMarkdown, uploadsPath }) => { - return { - tiptapExtension: ExtendedImage.configure({ inline: true, renderMarkdown, uploadsPath }), - serializer, - }; -}; diff --git a/app/assets/javascripts/content_editor/extensions/italic.js b/app/assets/javascripts/content_editor/extensions/italic.js index b8a7c4aba3e..99e9922044d 100644 --- a/app/assets/javascripts/content_editor/extensions/italic.js +++ b/app/assets/javascripts/content_editor/extensions/italic.js @@ -1,4 +1 @@ -import { Italic } from '@tiptap/extension-italic'; - -export const tiptapExtension = Italic; -export const serializer = { open: '_', close: '_', mixable: true, expelEnclosingWhitespace: true }; +export { Italic as default } from '@tiptap/extension-italic'; diff --git a/app/assets/javascripts/content_editor/extensions/link.js b/app/assets/javascripts/content_editor/extensions/link.js index 12019ab4636..38834ad1b87 100644 --- a/app/assets/javascripts/content_editor/extensions/link.js +++ b/app/assets/javascripts/content_editor/extensions/link.js @@ -20,7 +20,7 @@ export const extractHrefFromMarkdownLink = (match) => { return extractHrefFromMatch(match); }; -export const tiptapExtension = Link.extend({ +export default Link.extend({ addInputRules() { return [ markInputRule(markdownLinkSyntaxInputRuleRegExp, this.type, extractHrefFromMarkdownLink), @@ -51,13 +51,3 @@ export const tiptapExtension = Link.extend({ }).configure({ openOnClick: false, }); - -export const serializer = { - open() { - return '['; - }, - close(state, mark) { - const href = mark.attrs.canonicalSrc || mark.attrs.href; - return `](${state.esc(href)}${mark.attrs.title ? ` ${state.quote(mark.attrs.title)}` : ''})`; - }, -}; diff --git a/app/assets/javascripts/content_editor/extensions/list_item.js b/app/assets/javascripts/content_editor/extensions/list_item.js index 86da98f6df7..72454b0905d 100644 --- a/app/assets/javascripts/content_editor/extensions/list_item.js +++ b/app/assets/javascripts/content_editor/extensions/list_item.js @@ -1,5 +1 @@ -import { ListItem } from '@tiptap/extension-list-item'; -import { defaultMarkdownSerializer } from 'prosemirror-markdown/src/to_markdown'; - -export const tiptapExtension = ListItem; -export const serializer = defaultMarkdownSerializer.nodes.list_item; +export { ListItem as default } from '@tiptap/extension-list-item'; diff --git a/app/assets/javascripts/content_editor/extensions/ordered_list.js b/app/assets/javascripts/content_editor/extensions/ordered_list.js index d980ab8bf10..9a79187d9c1 100644 --- a/app/assets/javascripts/content_editor/extensions/ordered_list.js +++ b/app/assets/javascripts/content_editor/extensions/ordered_list.js @@ -1,5 +1 @@ -import { OrderedList } from '@tiptap/extension-ordered-list'; -import { defaultMarkdownSerializer } from 'prosemirror-markdown/src/to_markdown'; - -export const tiptapExtension = OrderedList; -export const serializer = defaultMarkdownSerializer.nodes.ordered_list; +export { OrderedList as default } from '@tiptap/extension-ordered-list'; diff --git a/app/assets/javascripts/content_editor/extensions/paragraph.js b/app/assets/javascripts/content_editor/extensions/paragraph.js index 6c9f204b8ac..33bf1c94003 100644 --- a/app/assets/javascripts/content_editor/extensions/paragraph.js +++ b/app/assets/javascripts/content_editor/extensions/paragraph.js @@ -1,5 +1 @@ -import { Paragraph } from '@tiptap/extension-paragraph'; -import { defaultMarkdownSerializer } from 'prosemirror-markdown/src/to_markdown'; - -export const tiptapExtension = Paragraph; -export const serializer = defaultMarkdownSerializer.nodes.paragraph; +export { Paragraph as default } from '@tiptap/extension-paragraph'; diff --git a/app/assets/javascripts/content_editor/extensions/strike.js b/app/assets/javascripts/content_editor/extensions/strike.js index 6f228e00994..b6c9a968fc2 100644 --- a/app/assets/javascripts/content_editor/extensions/strike.js +++ b/app/assets/javascripts/content_editor/extensions/strike.js @@ -1,9 +1 @@ -import { Strike } from '@tiptap/extension-strike'; - -export const tiptapExtension = Strike; -export const serializer = { - open: '~~', - close: '~~', - mixable: true, - expelEnclosingWhitespace: true, -}; +export { Strike as default } from '@tiptap/extension-strike'; diff --git a/app/assets/javascripts/content_editor/extensions/table.js b/app/assets/javascripts/content_editor/extensions/table.js index 566f7a21a85..0f0477cba2e 100644 --- a/app/assets/javascripts/content_editor/extensions/table.js +++ b/app/assets/javascripts/content_editor/extensions/table.js @@ -1,7 +1 @@ -import { Table } from '@tiptap/extension-table'; - -export const tiptapExtension = Table; - -export function serializer(state, node) { - state.renderContent(node); -} +export { Table as default } from '@tiptap/extension-table'; diff --git a/app/assets/javascripts/content_editor/extensions/table_cell.js b/app/assets/javascripts/content_editor/extensions/table_cell.js index 6c25b867466..5bdc39231a1 100644 --- a/app/assets/javascripts/content_editor/extensions/table_cell.js +++ b/app/assets/javascripts/content_editor/extensions/table_cell.js @@ -1,9 +1,5 @@ import { TableCell } from '@tiptap/extension-table-cell'; -export const tiptapExtension = TableCell.extend({ +export default TableCell.extend({ content: 'inline*', }); - -export function serializer(state, node) { - state.renderInline(node); -} diff --git a/app/assets/javascripts/content_editor/extensions/table_header.js b/app/assets/javascripts/content_editor/extensions/table_header.js index 3475857b9e6..23509706e4b 100644 --- a/app/assets/javascripts/content_editor/extensions/table_header.js +++ b/app/assets/javascripts/content_editor/extensions/table_header.js @@ -1,9 +1,5 @@ import { TableHeader } from '@tiptap/extension-table-header'; -export const tiptapExtension = TableHeader.extend({ +export default TableHeader.extend({ content: 'inline*', }); - -export function serializer(state, node) { - state.renderInline(node); -} diff --git a/app/assets/javascripts/content_editor/extensions/table_row.js b/app/assets/javascripts/content_editor/extensions/table_row.js index 07d2eb4faa2..541257a6cbf 100644 --- a/app/assets/javascripts/content_editor/extensions/table_row.js +++ b/app/assets/javascripts/content_editor/extensions/table_row.js @@ -1,51 +1,5 @@ import { TableRow } from '@tiptap/extension-table-row'; -export const tiptapExtension = TableRow.extend({ +export default TableRow.extend({ allowGapCursor: false, }); - -export function serializer(state, node) { - const isHeaderRow = node.child(0).type.name === 'tableHeader'; - - const renderRow = () => { - const cellWidths = []; - - state.flushClose(1); - - state.write('| '); - node.forEach((cell, _, i) => { - if (i) state.write(' | '); - - const { length } = state.out; - state.render(cell, node, i); - cellWidths.push(state.out.length - length); - }); - state.write(' |'); - - state.closeBlock(node); - - return cellWidths; - }; - - const renderHeaderRow = (cellWidths) => { - state.flushClose(1); - - state.write('|'); - node.forEach((cell, _, i) => { - if (i) state.write('|'); - - state.write(cell.attrs.align === 'center' ? ':' : '-'); - state.write(state.repeat('-', cellWidths[i])); - state.write(cell.attrs.align === 'center' || cell.attrs.align === 'right' ? ':' : '-'); - }); - state.write('|'); - - state.closeBlock(node); - }; - - if (isHeaderRow) { - renderHeaderRow(renderRow()); - } else { - renderRow(); - } -} diff --git a/app/assets/javascripts/content_editor/extensions/text.js b/app/assets/javascripts/content_editor/extensions/text.js index 0d76aa1f1a7..a2865e7010b 100644 --- a/app/assets/javascripts/content_editor/extensions/text.js +++ b/app/assets/javascripts/content_editor/extensions/text.js @@ -1,5 +1 @@ -import { Text } from '@tiptap/extension-text'; -import { defaultMarkdownSerializer } from 'prosemirror-markdown/src/to_markdown'; - -export const tiptapExtension = Text; -export const serializer = defaultMarkdownSerializer.nodes.text; +export { Text as default } from '@tiptap/extension-text'; diff --git a/app/assets/javascripts/content_editor/services/build_serializer_config.js b/app/assets/javascripts/content_editor/services/build_serializer_config.js deleted file mode 100644 index 75e2b0f9eba..00000000000 --- a/app/assets/javascripts/content_editor/services/build_serializer_config.js +++ /dev/null @@ -1,22 +0,0 @@ -const buildSerializerConfig = (extensions = []) => - extensions - .filter(({ serializer }) => serializer) - .reduce( - (serializers, { serializer, tiptapExtension: { name, type } }) => { - const collection = `${type}s`; - - return { - ...serializers, - [collection]: { - ...serializers[collection], - [name]: serializer, - }, - }; - }, - { - nodes: {}, - marks: {}, - }, - ); - -export default buildSerializerConfig; diff --git a/app/assets/javascripts/content_editor/services/create_content_editor.js b/app/assets/javascripts/content_editor/services/create_content_editor.js index 9251fdbbdc5..eceedc8bbf8 100644 --- a/app/assets/javascripts/content_editor/services/create_content_editor.js +++ b/app/assets/javascripts/content_editor/services/create_content_editor.js @@ -1,38 +1,34 @@ import { Editor } from '@tiptap/vue-2'; import { isFunction } from 'lodash'; import { PROVIDE_SERIALIZER_OR_RENDERER_ERROR } from '../constants'; -import * as Blockquote from '../extensions/blockquote'; -import * as Bold from '../extensions/bold'; -import * as BulletList from '../extensions/bullet_list'; -import * as Code from '../extensions/code'; -import * as CodeBlockHighlight from '../extensions/code_block_highlight'; -import * as Document from '../extensions/document'; -import * as Dropcursor from '../extensions/dropcursor'; -import * as Gapcursor from '../extensions/gapcursor'; -import * as HardBreak from '../extensions/hard_break'; -import * as Heading from '../extensions/heading'; -import * as History from '../extensions/history'; -import * as HorizontalRule from '../extensions/horizontal_rule'; -import * as Image from '../extensions/image'; -import * as Italic from '../extensions/italic'; -import * as Link from '../extensions/link'; -import * as ListItem from '../extensions/list_item'; -import * as OrderedList from '../extensions/ordered_list'; -import * as Paragraph from '../extensions/paragraph'; -import * as Strike from '../extensions/strike'; -import * as Table from '../extensions/table'; -import * as TableCell from '../extensions/table_cell'; -import * as TableHeader from '../extensions/table_header'; -import * as TableRow from '../extensions/table_row'; -import * as Text from '../extensions/text'; -import buildSerializerConfig from './build_serializer_config'; +import Blockquote from '../extensions/blockquote'; +import Bold from '../extensions/bold'; +import BulletList from '../extensions/bullet_list'; +import Code from '../extensions/code'; +import CodeBlockHighlight from '../extensions/code_block_highlight'; +import Document from '../extensions/document'; +import Dropcursor from '../extensions/dropcursor'; +import Gapcursor from '../extensions/gapcursor'; +import HardBreak from '../extensions/hard_break'; +import Heading from '../extensions/heading'; +import History from '../extensions/history'; +import HorizontalRule from '../extensions/horizontal_rule'; +import Image from '../extensions/image'; +import Italic from '../extensions/italic'; +import Link from '../extensions/link'; +import ListItem from '../extensions/list_item'; +import OrderedList from '../extensions/ordered_list'; +import Paragraph from '../extensions/paragraph'; +import Strike from '../extensions/strike'; +import Table from '../extensions/table'; +import TableCell from '../extensions/table_cell'; +import TableHeader from '../extensions/table_header'; +import TableRow from '../extensions/table_row'; +import Text from '../extensions/text'; import { ContentEditor } from './content_editor'; import createMarkdownSerializer from './markdown_serializer'; import trackInputRulesAndShortcuts from './track_input_rules_and_shortcuts'; -const collectTiptapExtensions = (extensions = []) => - extensions.map(({ tiptapExtension }) => tiptapExtension); - const createTiptapEditor = ({ extensions = [], ...options } = {}) => new Editor({ extensions: [...extensions], @@ -48,6 +44,7 @@ export const createContentEditor = ({ renderMarkdown, uploadsPath, extensions = [], + serializerConfig = { marks: {}, nodes: {} }, tiptapOptions, } = {}) => { if (!isFunction(renderMarkdown)) { @@ -82,9 +79,8 @@ export const createContentEditor = ({ ]; const allExtensions = [...builtInContentEditorExtensions, ...extensions]; - const tiptapExtensions = collectTiptapExtensions(allExtensions).map(trackInputRulesAndShortcuts); - const tiptapEditor = createTiptapEditor({ extensions: tiptapExtensions, ...tiptapOptions }); - const serializerConfig = buildSerializerConfig(allExtensions); + const trackedExtensions = allExtensions.map(trackInputRulesAndShortcuts); + const tiptapEditor = createTiptapEditor({ extensions: trackedExtensions, ...tiptapOptions }); const serializer = createMarkdownSerializer({ render: renderMarkdown, serializerConfig }); return new ContentEditor({ tiptapEditor, serializer }); diff --git a/app/assets/javascripts/content_editor/services/markdown_serializer.js b/app/assets/javascripts/content_editor/services/markdown_serializer.js index f121cc9affd..8b635e168ed 100644 --- a/app/assets/javascripts/content_editor/services/markdown_serializer.js +++ b/app/assets/javascripts/content_editor/services/markdown_serializer.js @@ -1,5 +1,125 @@ -import { MarkdownSerializer as ProseMirrorMarkdownSerializer } from 'prosemirror-markdown/src/to_markdown'; +import { + MarkdownSerializer as ProseMirrorMarkdownSerializer, + defaultMarkdownSerializer, +} from 'prosemirror-markdown/src/to_markdown'; import { DOMParser as ProseMirrorDOMParser } from 'prosemirror-model'; +import Blockquote from '../extensions/blockquote'; +import Bold from '../extensions/bold'; +import BulletList from '../extensions/bullet_list'; +import Code from '../extensions/code'; +import CodeBlockHighlight from '../extensions/code_block_highlight'; +import HardBreak from '../extensions/hard_break'; +import Heading from '../extensions/heading'; +import HorizontalRule from '../extensions/horizontal_rule'; +import Image from '../extensions/image'; +import Italic from '../extensions/italic'; +import Link from '../extensions/link'; +import ListItem from '../extensions/list_item'; +import OrderedList from '../extensions/ordered_list'; +import Paragraph from '../extensions/paragraph'; +import Strike from '../extensions/strike'; +import Table from '../extensions/table'; +import TableCell from '../extensions/table_cell'; +import TableHeader from '../extensions/table_header'; +import TableRow from '../extensions/table_row'; +import Text from '../extensions/text'; + +const defaultSerializerConfig = { + marks: { + [Bold.name]: defaultMarkdownSerializer.marks.strong, + [Code.name]: defaultMarkdownSerializer.marks.code, + [Italic.name]: { open: '_', close: '_', mixable: true, expelEnclosingWhitespace: true }, + [Link.name]: { + open() { + return '['; + }, + close(state, mark) { + const href = mark.attrs.canonicalSrc || mark.attrs.href; + return `](${state.esc(href)}${ + mark.attrs.title ? ` ${state.quote(mark.attrs.title)}` : '' + })`; + }, + }, + [Strike.name]: { + open: '~~', + close: '~~', + mixable: true, + expelEnclosingWhitespace: true, + }, + }, + nodes: { + [Blockquote.name]: defaultMarkdownSerializer.nodes.blockquote, + [BulletList.name]: defaultMarkdownSerializer.nodes.bullet_list, + [CodeBlockHighlight.name]: defaultMarkdownSerializer.nodes.code_block, + [HardBreak.name]: defaultMarkdownSerializer.nodes.hard_break, + [Heading.name]: defaultMarkdownSerializer.nodes.heading, + [HorizontalRule.name]: defaultMarkdownSerializer.nodes.horizontal_rule, + [Image.name]: (state, node) => { + const { alt, canonicalSrc, src, title } = node.attrs; + const quotedTitle = title ? ` ${state.quote(title)}` : ''; + + state.write(`![${state.esc(alt || '')}](${state.esc(canonicalSrc || src)}${quotedTitle})`); + }, + [ListItem.name]: defaultMarkdownSerializer.nodes.list_item, + [OrderedList.name]: defaultMarkdownSerializer.nodes.ordered_list, + [Paragraph.name]: defaultMarkdownSerializer.nodes.paragraph, + [Table.name]: (state, node) => { + state.renderContent(node); + }, + [TableCell.name]: (state, node) => { + state.renderInline(node); + }, + [TableHeader.name]: (state, node) => { + state.renderInline(node); + }, + [TableRow.name]: (state, node) => { + const isHeaderRow = node.child(0).type.name === 'tableHeader'; + + const renderRow = () => { + const cellWidths = []; + + state.flushClose(1); + + state.write('| '); + node.forEach((cell, _, i) => { + if (i) state.write(' | '); + + const { length } = state.out; + state.render(cell, node, i); + cellWidths.push(state.out.length - length); + }); + state.write(' |'); + + state.closeBlock(node); + + return cellWidths; + }; + + const renderHeaderRow = (cellWidths) => { + state.flushClose(1); + + state.write('|'); + node.forEach((cell, _, i) => { + if (i) state.write('|'); + + state.write(cell.attrs.align === 'center' ? ':' : '-'); + state.write(state.repeat('-', cellWidths[i])); + state.write(cell.attrs.align === 'center' || cell.attrs.align === 'right' ? ':' : '-'); + }); + state.write('|'); + + state.closeBlock(node); + }; + + if (isHeaderRow) { + renderHeaderRow(renderRow()); + } else { + renderRow(); + } + }, + [Text.name]: defaultMarkdownSerializer.nodes.text, + }, +}; const wrapHtmlPayload = (payload) => `<div>${payload}</div>`; @@ -50,8 +170,16 @@ export default ({ render = () => null, serializerConfig }) => ({ */ serialize: ({ schema, content }) => { const proseMirrorDocument = schema.nodeFromJSON(content); - const { nodes, marks } = serializerConfig; - const serializer = new ProseMirrorMarkdownSerializer(nodes, marks); + const serializer = new ProseMirrorMarkdownSerializer( + { + ...defaultSerializerConfig.nodes, + ...serializerConfig.nodes, + }, + { + ...defaultSerializerConfig.marks, + ...serializerConfig.marks, + }, + ); return serializer.serialize(proseMirrorDocument, { tightLists: true, diff --git a/app/assets/javascripts/vue_shared/components/papa_parse_alert.vue b/app/assets/javascripts/vue_shared/components/papa_parse_alert.vue new file mode 100644 index 00000000000..fa11661255f --- /dev/null +++ b/app/assets/javascripts/vue_shared/components/papa_parse_alert.vue @@ -0,0 +1,44 @@ +<script> +import { GlAlert } from '@gitlab/ui'; +import { s__ } from '~/locale'; + +export default { + components: { + GlAlert, + }, + i18n: { + genericErrorMessage: s__('CsvParser|Failed to render the CSV file for the following reasons:'), + MissingQuotes: s__('CsvParser|Quoted field unterminated'), + InvalidQuotes: s__('CsvParser|Trailing quote on quoted field is malformed'), + UndetectableDelimiter: s__('CsvParser|Unable to auto-detect delimiter; defaulted to ","'), + TooManyFields: s__('CsvParser|Too many fields'), + TooFewFields: s__('CsvParser|Too few fields'), + }, + props: { + papaParseErrors: { + type: Array, + required: false, + default: () => [], + }, + }, + computed: { + errorMessages() { + const errorMessages = this.papaParseErrors.map( + (error) => this.$options.i18n[error.code] ?? error.message, + ); + return new Set(errorMessages); + }, + }, +}; +</script> + +<template> + <gl-alert variant="danger" :dismissible="false"> + {{ $options.i18n.genericErrorMessage }} + <ul class="gl-mb-0!"> + <li v-for="error in errorMessages" :key="error"> + {{ error }} + </li> + </ul> + </gl-alert> +</template> diff --git a/app/policies/project_policy.rb b/app/policies/project_policy.rb index 85547834a2e..b6e063f5584 100644 --- a/app/policies/project_policy.rb +++ b/app/policies/project_policy.rb @@ -159,10 +159,6 @@ class ProjectPolicy < BasePolicy ::Feature.enabled?(:build_service_proxy, @subject) end - condition(:respect_protected_tag_for_release_permissions) do - ::Feature.enabled?(:evalute_protected_tag_for_release_permissions, @subject, default_enabled: :yaml) - end - condition(:user_defined_variables_allowed) do !@subject.restrict_user_defined_variables? end @@ -374,6 +370,7 @@ class ProjectPolicy < BasePolicy enable :update_deployment enable :create_release enable :update_release + enable :destroy_release enable :create_metrics_dashboard_annotation enable :delete_metrics_dashboard_annotation enable :update_metrics_dashboard_annotation @@ -657,10 +654,6 @@ class ProjectPolicy < BasePolicy rule { build_service_proxy_enabled }.enable :build_service_proxy_enabled - rule { respect_protected_tag_for_release_permissions & can?(:developer_access) }.policy do - enable :destroy_release - end - rule { can?(:download_code) }.policy do enable :read_repository_graphs end diff --git a/app/policies/release_policy.rb b/app/policies/release_policy.rb index bff80d83bef..077e4764b34 100644 --- a/app/policies/release_policy.rb +++ b/app/policies/release_policy.rb @@ -9,11 +9,7 @@ class ReleasePolicy < BasePolicy !access.can_create_tag?(@subject.tag) end - condition(:respect_protected_tag) do - ::Feature.enabled?(:evalute_protected_tag_for_release_permissions, @subject.project, default_enabled: :yaml) - end - - rule { respect_protected_tag & protected_tag }.policy do + rule { protected_tag }.policy do prevent :create_release prevent :update_release prevent :destroy_release diff --git a/app/services/releases/base_service.rb b/app/services/releases/base_service.rb index b4b493624e7..249333e6d13 100644 --- a/app/services/releases/base_service.rb +++ b/app/services/releases/base_service.rb @@ -83,15 +83,6 @@ module Releases release.execute_hooks(action) end - def track_protected_tag_access_error! - unless ::Gitlab::UserAccess.new(current_user, container: project).can_create_tag?(tag_name) - Gitlab::ErrorTracking.log_exception( - ReleaseProtectedTagAccessError.new, - project_id: project.id, - user_id: current_user.id) - end - end - # overridden in EE def project_group_id; end end diff --git a/app/services/releases/create_service.rb b/app/services/releases/create_service.rb index 2aac5644b84..caa6a003205 100644 --- a/app/services/releases/create_service.rb +++ b/app/services/releases/create_service.rb @@ -7,8 +7,6 @@ module Releases return error('Release already exists', 409) if release return error("Milestone(s) not found: #{inexistent_milestones.join(', ')}", 400) if inexistent_milestones.any? - track_protected_tag_access_error! - # should be found before the creation of new tag # because tag creation can spawn new pipeline # which won't have any data for evidence yet @@ -48,8 +46,6 @@ module Releases end def can_create_tag? - return true unless ::Feature.enabled?(:evalute_protected_tag_for_release_permissions, project, default_enabled: :yaml) - ::Gitlab::UserAccess.new(current_user, container: project).can_create_tag?(tag_name) end diff --git a/app/services/releases/destroy_service.rb b/app/services/releases/destroy_service.rb index 36cf29c955d..8abf9308689 100644 --- a/app/services/releases/destroy_service.rb +++ b/app/services/releases/destroy_service.rb @@ -6,8 +6,6 @@ module Releases return error('Release does not exist', 404) unless release return error('Access Denied', 403) unless allowed? - track_protected_tag_access_error! - if release.destroy success(tag: existing_tag, release: release) else diff --git a/app/services/releases/update_service.rb b/app/services/releases/update_service.rb index 011cb2e481d..2e0a2f8488a 100644 --- a/app/services/releases/update_service.rb +++ b/app/services/releases/update_service.rb @@ -7,8 +7,6 @@ module Releases return error end - track_protected_tag_access_error! - if param_for_milestone_titles_provided? previous_milestones = release.milestones.map(&:title) params[:milestones] = milestones diff --git a/config/feature_flags/development/evalute_protected_tag_for_release_permissions.yml b/config/feature_flags/development/evalute_protected_tag_for_release_permissions.yml deleted file mode 100644 index a314c0263ba..00000000000 --- a/config/feature_flags/development/evalute_protected_tag_for_release_permissions.yml +++ /dev/null @@ -1,8 +0,0 @@ ---- -name: evalute_protected_tag_for_release_permissions -introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/64693 -rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/334368 -milestone: '14.1' -type: development -group: group::release -default_enabled: true diff --git a/danger/specialization_labels/Dangerfile b/danger/specialization_labels/Dangerfile index 35125f20b14..e86d66f5fbc 100644 --- a/danger/specialization_labels/Dangerfile +++ b/danger/specialization_labels/Dangerfile @@ -8,7 +8,7 @@ SPECIALIZATIONS = { frontend: 'frontend', docs: 'documentation', qa: 'QA', - engineering_productivity: 'Engineering Productivity', + tooling: 'tooling', ci_template: 'ci::templates', feature_flag: 'feature flag' }.freeze diff --git a/doc/administration/get_started.md b/doc/administration/get_started.md index 7d1080148ea..ac717769d4f 100644 --- a/doc/administration/get_started.md +++ b/doc/administration/get_started.md @@ -83,6 +83,8 @@ While this isn't an exhaustive list, following these steps gives you a solid sta - Configure [user and IP rate limits](https://about.gitlab.com/blog/2020/05/20/gitlab-instance-security-best-practices/#user-and-ip-rate-limits). - Limit [webhooks local access](https://about.gitlab.com/blog/2020/05/20/gitlab-instance-security-best-practices/#webhooks). - Set [rate limits for protected paths](../user/admin_area/settings/protected_paths.md). +- Sign up for [Security Alerts](https://about.gitlab.com/company/preference-center/) from the Communication Preference Center. +- Keep track of security best practices on our [blog page](https://about.gitlab.com/blog/2020/05/20/gitlab-instance-security-best-practices/). ## Monitor GitLab performance diff --git a/doc/api/experiments.md b/doc/api/experiments.md index 3c8efa35b78..c5e217a3d66 100644 --- a/doc/api/experiments.md +++ b/doc/api/experiments.md @@ -28,13 +28,51 @@ Example response: ```json [ - { - "key": "experiment_1", - "enabled": true + { + "key": "code_quality_walkthrough", + "definition": { + "name": "code_quality_walkthrough", + "introduced_by_url": "https://gitlab.com/gitlab-org/gitlab/-/merge_requests/58900", + "rollout_issue_url": "https://gitlab.com/gitlab-org/gitlab/-/issues/327229", + "milestone": "13.12", + "type": "experiment", + "group": "group::activation", + "default_enabled": false }, - { - "key": "experiment_2", - "enabled": false + "current_status": { + "state": "conditional", + "gates": [ + { + "key": "boolean", + "value": false + }, + { + "key": "percentage_of_actors", + "value": 25 + } + ] } + }, + { + "key": "ci_runner_templates", + "definition": { + "name": "ci_runner_templates", + "introduced_by_url": "https://gitlab.com/gitlab-org/gitlab/-/merge_requests/58357", + "rollout_issue_url": "https://gitlab.com/gitlab-org/gitlab/-/issues/326725", + "milestone": "14.0", + "type": "experiment", + "group": "group::activation", + "default_enabled": false + }, + "current_status": { + "state": "off", + "gates": [ + { + "key": "boolean", + "value": false + } + ] + } + } ] ``` diff --git a/doc/api/users.md b/doc/api/users.md index e074bd44c7a..15fa397823e 100644 --- a/doc/api/users.md +++ b/doc/api/users.md @@ -109,6 +109,7 @@ GET /users | `two_factor` | string | no | Filter users by Two-factor authentication. Filter values are `enabled` or `disabled`. By default it returns all users | | `without_projects` | boolean | no | Filter users without projects. Default is `false`, which means that all users are returned, with and without projects. | | `admins` | boolean | no | Return only admin users. Default is `false` | +| `saml_provider_id` **(PREMIUM)** | number | no | Return only users created by the specified SAML provider ID. If not included, it returns all users. | ```json [ diff --git a/doc/development/documentation/styleguide/index.md b/doc/development/documentation/styleguide/index.md index b0f0168c42c..903c2543de5 100644 --- a/doc/development/documentation/styleguide/index.md +++ b/doc/development/documentation/styleguide/index.md @@ -1,7 +1,5 @@ --- -stage: none -group: Style Guide -info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments +info: For assistance with this Style Guide page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments-to-other-projects-and-subjects. description: 'Writing styles, markup, formatting, and other standards for GitLab Documentation.' --- diff --git a/doc/user/application_security/dast/index.md b/doc/user/application_security/dast/index.md index d694bb4fb1a..78197cb32f3 100644 --- a/doc/user/application_security/dast/index.md +++ b/doc/user/application_security/dast/index.md @@ -304,7 +304,7 @@ For more details, including setup instructions, see [DAST browser-based crawler] ### Full scan -DAST can be configured to perform [ZAP Full Scan](https://github.com/zaproxy/zaproxy/wiki/ZAP-Full-Scan), which +DAST can be configured to perform [ZAP Full Scan](https://www.zaproxy.org/docs/docker/full-scan/), which includes both passive and active scanning against the same target website: ```yaml @@ -786,7 +786,7 @@ You can use CI/CD variables to customize DAST. | `DAST_SKIP_TARGET_CHECK` | boolean | Set to `true` to prevent DAST from checking that the target is available before scanning. Default: `false`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/229067) in GitLab 13.8. | | `DAST_MASK_HTTP_HEADERS` | string | Comma-separated list of request and response headers to be masked (GitLab 13.1). Must contain **all** headers to be masked. Refer to [list of headers that are masked by default](#hide-sensitive-information). | | `DAST_EXCLUDE_URLS` <sup>1</sup> | URLs | The URLs to skip during the authenticated scan; comma-separated. Regular expression syntax can be used to match multiple URLs. For example, `.*` matches an arbitrary character sequence. Not supported for API scans. | -| `DAST_FULL_SCAN_ENABLED` <sup>1</sup> | boolean | Set to `true` to run a [ZAP Full Scan](https://github.com/zaproxy/zaproxy/wiki/ZAP-Full-Scan) instead of a [ZAP Baseline Scan](https://github.com/zaproxy/zaproxy/wiki/ZAP-Baseline-Scan). Default: `false` | +| `DAST_FULL_SCAN_ENABLED` <sup>1</sup> | boolean | Set to `true` to run a [ZAP Full Scan](https://www.zaproxy.org/docs/docker/full-scan/) instead of a [ZAP Baseline Scan](https://www.zaproxy.org/docs/docker/baseline-scan/). Default: `false` | | `DAST_FULL_SCAN_DOMAIN_VALIDATION_REQUIRED` | boolean | **{warning}** **[Removed](https://gitlab.com/gitlab-org/gitlab/-/issues/293595)** in GitLab 14.0. Set to `true` to require domain validation when running DAST full scans. Not supported for API scans. Default: `false` | | `DAST_AUTO_UPDATE_ADDONS` | boolean | ZAP add-ons are pinned to specific versions in the DAST Docker image. Set to `true` to download the latest versions when the scan starts. Default: `false` | | `DAST_API_HOST_OVERRIDE` <sup>1</sup> | string | Used to override domains defined in API specification files. Only supported when importing the API specification from a URL. Example: `example.com:8080` | diff --git a/doc/user/group/settings/img/export_panel_v13_0.png b/doc/user/group/settings/img/export_panel_v13_0.png Binary files differdeleted file mode 100644 index 36549e1f3f5..00000000000 --- a/doc/user/group/settings/img/export_panel_v13_0.png +++ /dev/null diff --git a/doc/user/group/settings/import_export.md b/doc/user/group/settings/import_export.md index 4ed781b82cb..a0930867b2a 100644 --- a/doc/user/group/settings/import_export.md +++ b/doc/user/group/settings/import_export.md @@ -19,9 +19,11 @@ See also: - [Project Import/Export](../../project/settings/import_export.md) - [Project Import/Export API](../../../api/project_import_export.md) -To enable GitLab import/export: +Users with the [Owner role](../../permissions.md) for a group can enable +import and export for that group: -1. On the top bar, go to **Menu > Admin > Settings > General > Visibility and access controls**. +1. On the top bar, select **Menu >** **{admin}** **Admin**. +1. On the left sidebar, select **Settings > General > Visibility and access controls**. 1. Scroll to **Import sources**. 1. Enable the desired **Import sources**. @@ -48,7 +50,8 @@ The following items are exported: - Subgroups (including all the aforementioned data) - Epics - Events -- Wikis **(PREMIUM SELF)** (Introduced in [GitLab 13.9](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/53247)) +- [Wikis](../../project/wiki/index.md#group-wikis) **(PREMIUM SELF)** + (Introduced in [GitLab 13.9](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/53247)) The following items are **not** exported: @@ -60,21 +63,21 @@ NOTE: For more details on the specific data persisted in a group export, see the [`import_export.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/import_export/group/import_export.yml) file. -## Exporting a Group +## Export a group -1. Navigate to your group's homepage. - -1. Click **Settings** in the sidebar. - -1. In the **Advanced** section, click the **Export Group** button. - - ![Export group panel](img/export_panel_v13_0.png) +Users with the [Owner role](../../permissions.md) for a group can export the +contents of that group: +1. On the top bar, select **Menu >** **Groups** and find your group. +1. In the left sidebar, select **Settings**. +1. Scroll to the **Advanced** section, and select **Export Group**. 1. After the export is generated, you should receive an email with a link to the [exported contents](#exported-contents) in a compressed tar archive, with contents in NDJSON format. +1. Alternatively, you can download the export from the UI: -1. Alternatively, you can come back to the project settings and download the - file from there by clicking **Download export**, or generate a new file by clicking **Regenerate export**. + 1. Return to your group's **Settings > General** page. + 1. Scroll to the **Advanced** section, and select **Download export**. + You can also generate a new file by clicking **Regenerate export**. NOTE: The maximum import file size can be set by the Administrator, default is `0` (unlimited). @@ -103,7 +106,7 @@ on an existing group's page. 1. Click **Choose file** -1. Select the file that you exported in the [exporting a group](#exporting-a-group) section. +1. Select the file that you exported in the [Export a group](#export-a-group) section. 1. Click **Import group** to begin importing. Your newly imported group page appears after the operation completes. diff --git a/doc/user/project/releases/index.md b/doc/user/project/releases/index.md index 3a25b148fdf..6a10e3747c4 100644 --- a/doc/user/project/releases/index.md +++ b/doc/user/project/releases/index.md @@ -589,25 +589,6 @@ As an example of release permission control, you can allow only to create, update, and delete releases by protecting the tag with a wildcard (`*`), and set **Maintainer** in the **Allowed to create** column. -#### Enable or disable protected tag evaluation on releases **(FREE SELF)** - -Protected tag evaluation on release permissions is under development but ready for production use. -It is deployed behind a feature flag that is **enabled by default**. -[GitLab administrators with access to the GitLab Rails console](../../../administration/feature_flags.md) -can opt to disable it. - -To enable it: - -```ruby -Feature.enable(:evalute_protected_tag_for_release_permissions) -``` - -To disable it: - -```ruby -Feature.disable(:evalute_protected_tag_for_release_permissions) -``` - ## Release Command Line > [Introduced](https://gitlab.com/gitlab-org/release-cli/-/merge_requests/6) in GitLab 12.10. diff --git a/doc/user/project/wiki/index.md b/doc/user/project/wiki/index.md index f657b541aae..a1ebe5bc2ee 100644 --- a/doc/user/project/wiki/index.md +++ b/doc/user/project/wiki/index.md @@ -253,6 +253,14 @@ Group wikis can be edited by members with the [Developer role](../../permissions and above. Group wiki repositories can be moved using the [Group repository storage moves API](../../../api/group_repository_storage_moves.md). +### Export a group wiki **(PREMIUM)** + +Users with the [Owner role](../../permissions.md) in a group can +[import and export group wikis](../../group/settings/import_export.md) when importing +or exporting a group. + +Content created in a group wiki is not deleted when an account is downgraded or a GitLab trial ends. + ## Link an external wiki To add a link to an external wiki from a project's left sidebar: diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 260922a00ca..80242fddd64 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -9642,6 +9642,24 @@ msgstr "" msgid "Crowd" msgstr "" +msgid "CsvParser|Failed to render the CSV file for the following reasons:" +msgstr "" + +msgid "CsvParser|Quoted field unterminated" +msgstr "" + +msgid "CsvParser|Too few fields" +msgstr "" + +msgid "CsvParser|Too many fields" +msgstr "" + +msgid "CsvParser|Trailing quote on quoted field is malformed" +msgstr "" + +msgid "CsvParser|Unable to auto-detect delimiter; defaulted to \",\"" +msgstr "" + msgid "Current" msgstr "" diff --git a/spec/frontend/blob/csv/csv_viewer_spec.js b/spec/frontend/blob/csv/csv_viewer_spec.js index abb914b8f57..17973c709c1 100644 --- a/spec/frontend/blob/csv/csv_viewer_spec.js +++ b/spec/frontend/blob/csv/csv_viewer_spec.js @@ -1,8 +1,9 @@ -import { GlAlert, GlLoadingIcon, GlTable } from '@gitlab/ui'; +import { GlLoadingIcon, GlTable } from '@gitlab/ui'; import { getAllByRole } from '@testing-library/dom'; import { shallowMount, mount } from '@vue/test-utils'; import { nextTick } from 'vue'; -import CSVViewer from '~/blob/csv/csv_viewer.vue'; +import CsvViewer from '~/blob/csv/csv_viewer.vue'; +import PapaParseAlert from '~/vue_shared/components/papa_parse_alert.vue'; const validCsv = 'one,two,three'; const brokenCsv = '{\n "json": 1,\n "key": [1, 2, 3]\n}'; @@ -11,7 +12,7 @@ describe('app/assets/javascripts/blob/csv/csv_viewer.vue', () => { let wrapper; const createComponent = ({ csv = validCsv, mountFunction = shallowMount } = {}) => { - wrapper = mountFunction(CSVViewer, { + wrapper = mountFunction(CsvViewer, { propsData: { csv, }, @@ -20,7 +21,7 @@ describe('app/assets/javascripts/blob/csv/csv_viewer.vue', () => { const findCsvTable = () => wrapper.findComponent(GlTable); const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon); - const findAlert = () => wrapper.findComponent(GlAlert); + const findAlert = () => wrapper.findComponent(PapaParseAlert); afterEach(() => { wrapper.destroy(); @@ -35,12 +36,12 @@ describe('app/assets/javascripts/blob/csv/csv_viewer.vue', () => { }); describe('when the CSV contains errors', () => { - it('should render alert', async () => { + it('should render alert with correct props', async () => { createComponent({ csv: brokenCsv }); await nextTick; expect(findAlert().props()).toMatchObject({ - variant: 'danger', + papaParseErrors: [{ code: 'UndetectableDelimiter' }], }); }); }); diff --git a/spec/frontend/content_editor/components/toolbar_image_button_spec.js b/spec/frontend/content_editor/components/toolbar_image_button_spec.js index 701dcf83476..6553d8fd357 100644 --- a/spec/frontend/content_editor/components/toolbar_image_button_spec.js +++ b/spec/frontend/content_editor/components/toolbar_image_button_spec.js @@ -1,7 +1,7 @@ import { GlButton, GlFormInputGroup } from '@gitlab/ui'; import { mountExtended } from 'helpers/vue_test_utils_helper'; import ToolbarImageButton from '~/content_editor/components/toolbar_image_button.vue'; -import { configure as configureImageExtension } from '~/content_editor/extensions/image'; +import Image from '~/content_editor/extensions/image'; import { createTestEditor, mockChainedCommands } from '../test_utils'; describe('content_editor/components/toolbar_image_button', () => { @@ -29,13 +29,13 @@ describe('content_editor/components/toolbar_image_button', () => { }; beforeEach(() => { - const { tiptapExtension: Image } = configureImageExtension({ - renderMarkdown: jest.fn(), - uploadsPath: '/uploads/', - }); - editor = createTestEditor({ - extensions: [Image], + extensions: [ + Image.configure({ + renderMarkdown: jest.fn(), + uploadsPath: '/uploads/', + }), + ], }); buildWrapper(); diff --git a/spec/frontend/content_editor/components/toolbar_link_button_spec.js b/spec/frontend/content_editor/components/toolbar_link_button_spec.js index 576a2912f72..89a40c42590 100644 --- a/spec/frontend/content_editor/components/toolbar_link_button_spec.js +++ b/spec/frontend/content_editor/components/toolbar_link_button_spec.js @@ -1,7 +1,7 @@ import { GlDropdown, GlDropdownDivider, GlButton, GlFormInputGroup } from '@gitlab/ui'; import { mountExtended } from 'helpers/vue_test_utils_helper'; import ToolbarLinkButton from '~/content_editor/components/toolbar_link_button.vue'; -import { tiptapExtension as Link } from '~/content_editor/extensions/link'; +import Link from '~/content_editor/extensions/link'; import { hasSelection } from '~/content_editor/services/utils'; import { createTestEditor, mockChainedCommands } from '../test_utils'; @@ -25,9 +25,7 @@ describe('content_editor/components/toolbar_link_button', () => { const findRemoveLinkButton = () => wrapper.findByText('Remove link'); beforeEach(() => { - editor = createTestEditor({ - extensions: [Link], - }); + editor = createTestEditor(); }); afterEach(() => { diff --git a/spec/frontend/content_editor/components/toolbar_table_button_spec.js b/spec/frontend/content_editor/components/toolbar_table_button_spec.js index 237b2848246..fe5212cfe3c 100644 --- a/spec/frontend/content_editor/components/toolbar_table_button_spec.js +++ b/spec/frontend/content_editor/components/toolbar_table_button_spec.js @@ -1,10 +1,6 @@ import { GlDropdown, GlButton } from '@gitlab/ui'; import { mountExtended } from 'helpers/vue_test_utils_helper'; import ToolbarTableButton from '~/content_editor/components/toolbar_table_button.vue'; -import { tiptapExtension as Table } from '~/content_editor/extensions/table'; -import { tiptapExtension as TableCell } from '~/content_editor/extensions/table_cell'; -import { tiptapExtension as TableHeader } from '~/content_editor/extensions/table_header'; -import { tiptapExtension as TableRow } from '~/content_editor/extensions/table_row'; import { createTestEditor, mockChainedCommands } from '../test_utils'; describe('content_editor/components/toolbar_table_button', () => { @@ -23,9 +19,7 @@ describe('content_editor/components/toolbar_table_button', () => { const getNumButtons = () => findDropdown().findAllComponents(GlButton).length; beforeEach(() => { - editor = createTestEditor({ - extensions: [Table, TableCell, TableRow, TableHeader], - }); + editor = createTestEditor(); buildWrapper(); }); diff --git a/spec/frontend/content_editor/components/toolbar_text_style_dropdown_spec.js b/spec/frontend/content_editor/components/toolbar_text_style_dropdown_spec.js index 9a46e27404f..8c98fe95bd4 100644 --- a/spec/frontend/content_editor/components/toolbar_text_style_dropdown_spec.js +++ b/spec/frontend/content_editor/components/toolbar_text_style_dropdown_spec.js @@ -2,7 +2,7 @@ import { GlDropdown, GlDropdownItem } from '@gitlab/ui'; import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; import ToolbarTextStyleDropdown from '~/content_editor/components/toolbar_text_style_dropdown.vue'; import { TEXT_STYLE_DROPDOWN_ITEMS } from '~/content_editor/constants'; -import { tiptapExtension as Heading } from '~/content_editor/extensions/heading'; +import Heading from '~/content_editor/extensions/heading'; import { createTestEditor, mockChainedCommands } from '../test_utils'; describe('content_editor/components/toolbar_headings_dropdown', () => { diff --git a/spec/frontend/content_editor/extensions/code_block_highlight_spec.js b/spec/frontend/content_editor/extensions/code_block_highlight_spec.js index cc695ffe241..79e55db30cd 100644 --- a/spec/frontend/content_editor/extensions/code_block_highlight_spec.js +++ b/spec/frontend/content_editor/extensions/code_block_highlight_spec.js @@ -1,4 +1,4 @@ -import { tiptapExtension as CodeBlockHighlight } from '~/content_editor/extensions/code_block_highlight'; +import CodeBlockHighlight from '~/content_editor/extensions/code_block_highlight'; import { loadMarkdownApiResult } from '../markdown_processing_examples'; import { createTestEditor } from '../test_utils'; diff --git a/spec/frontend/content_editor/extensions/hard_break_spec.js b/spec/frontend/content_editor/extensions/hard_break_spec.js index ebd58e60b0c..9e2e28b6e72 100644 --- a/spec/frontend/content_editor/extensions/hard_break_spec.js +++ b/spec/frontend/content_editor/extensions/hard_break_spec.js @@ -1,4 +1,4 @@ -import { tiptapExtension as HardBreak } from '~/content_editor/extensions/hard_break'; +import HardBreak from '~/content_editor/extensions/hard_break'; import { createTestEditor, createDocBuilder } from '../test_utils'; describe('content_editor/extensions/hard_break', () => { diff --git a/spec/frontend/content_editor/extensions/image_spec.js b/spec/frontend/content_editor/extensions/image_spec.js index 922966b813a..09b7274839e 100644 --- a/spec/frontend/content_editor/extensions/image_spec.js +++ b/spec/frontend/content_editor/extensions/image_spec.js @@ -2,7 +2,7 @@ import axios from 'axios'; import MockAdapter from 'axios-mock-adapter'; import { once } from 'lodash'; import waitForPromises from 'helpers/wait_for_promises'; -import * as Image from '~/content_editor/extensions/image'; +import Image from '~/content_editor/extensions/image'; import httpStatus from '~/lib/utils/http_status'; import { loadMarkdownApiResult } from '../markdown_processing_examples'; import { createTestEditor, createDocBuilder } from '../test_utils'; @@ -24,16 +24,16 @@ describe('content_editor/extensions/image', () => { .fn() .mockResolvedValue(loadMarkdownApiResult('project_wiki_attachment_image').body); - const { tiptapExtension } = Image.configure({ renderMarkdown, uploadsPath }); - - tiptapEditor = createTestEditor({ extensions: [tiptapExtension] }); + tiptapEditor = createTestEditor({ + extensions: [Image.configure({ renderMarkdown, uploadsPath })], + }); ({ builders: { doc, p, image }, eq, } = createDocBuilder({ tiptapEditor, - names: { image: { nodeType: tiptapExtension.name } }, + names: { image: { nodeType: Image.name } }, })); mock = new MockAdapter(axios); diff --git a/spec/frontend/content_editor/services/build_serializer_config_spec.js b/spec/frontend/content_editor/services/build_serializer_config_spec.js deleted file mode 100644 index 532e0493830..00000000000 --- a/spec/frontend/content_editor/services/build_serializer_config_spec.js +++ /dev/null @@ -1,38 +0,0 @@ -import * as Blockquote from '~/content_editor/extensions/blockquote'; -import * as Bold from '~/content_editor/extensions/bold'; -import * as Dropcursor from '~/content_editor/extensions/dropcursor'; -import * as Paragraph from '~/content_editor/extensions/paragraph'; - -import buildSerializerConfig from '~/content_editor/services/build_serializer_config'; - -describe('content_editor/services/build_serializer_config', () => { - describe('given one or more content editor extensions', () => { - it('creates a serializer config that collects all extension serializers by type', () => { - const extensions = [Bold, Blockquote, Paragraph]; - const serializerConfig = buildSerializerConfig(extensions); - - extensions.forEach(({ tiptapExtension, serializer }) => { - const { name, type } = tiptapExtension; - expect(serializerConfig[`${type}s`][name]).toBe(serializer); - }); - }); - }); - - describe('given an extension without serializer', () => { - it('does not include the extension in the serializer config', () => { - const serializerConfig = buildSerializerConfig([Dropcursor]); - - expect(serializerConfig.marks[Dropcursor.tiptapExtension.name]).toBe(undefined); - expect(serializerConfig.nodes[Dropcursor.tiptapExtension.name]).toBe(undefined); - }); - }); - - describe('given no extensions', () => { - it('creates an empty serializer config', () => { - expect(buildSerializerConfig()).toStrictEqual({ - marks: {}, - nodes: {}, - }); - }); - }); -}); diff --git a/spec/frontend/content_editor/services/create_content_editor_spec.js b/spec/frontend/content_editor/services/create_content_editor_spec.js index b614efd954a..a6d52ddabef 100644 --- a/spec/frontend/content_editor/services/create_content_editor_spec.js +++ b/spec/frontend/content_editor/services/create_content_editor_spec.js @@ -32,13 +32,15 @@ describe('content_editor/services/create_editor', () => { it('allows providing external content editor extensions', async () => { const labelReference = 'this is a ~group::editor'; + const { tiptapExtension, serializer } = createTestContentEditorExtension(); renderMarkdown.mockReturnValueOnce( '<p>this is a <span data-reference="label" data-label-name="group::editor">group::editor</span></p>', ); editor = createContentEditor({ renderMarkdown, - extensions: [createTestContentEditorExtension()], + extensions: [tiptapExtension], + serializerConfig: { nodes: { [tiptapExtension.name]: serializer } }, }); await editor.setSerializedContent(labelReference); diff --git a/spec/frontend/content_editor/services/track_input_rules_and_shortcuts_spec.js b/spec/frontend/content_editor/services/track_input_rules_and_shortcuts_spec.js index 64f3d8df6e0..afe09a75f16 100644 --- a/spec/frontend/content_editor/services/track_input_rules_and_shortcuts_spec.js +++ b/spec/frontend/content_editor/services/track_input_rules_and_shortcuts_spec.js @@ -4,10 +4,10 @@ import { INPUT_RULE_TRACKING_ACTION, CONTENT_EDITOR_TRACKING_LABEL, } from '~/content_editor/constants'; -import { tiptapExtension as BulletList } from '~/content_editor/extensions/bullet_list'; -import { tiptapExtension as CodeBlockLowlight } from '~/content_editor/extensions/code_block_highlight'; -import { tiptapExtension as Heading } from '~/content_editor/extensions/heading'; -import { tiptapExtension as ListItem } from '~/content_editor/extensions/list_item'; +import BulletList from '~/content_editor/extensions/bullet_list'; +import CodeBlockLowlight from '~/content_editor/extensions/code_block_highlight'; +import Heading from '~/content_editor/extensions/heading'; +import ListItem from '~/content_editor/extensions/list_item'; import trackInputRulesAndShortcuts from '~/content_editor/services/track_input_rules_and_shortcuts'; import { ENTER_KEY, BACKSPACE_KEY } from '~/lib/utils/keys'; import { createTestEditor } from '../test_utils'; diff --git a/spec/frontend/vue_shared/components/papa_parse_alert_spec.js b/spec/frontend/vue_shared/components/papa_parse_alert_spec.js new file mode 100644 index 00000000000..9be2de17d01 --- /dev/null +++ b/spec/frontend/vue_shared/components/papa_parse_alert_spec.js @@ -0,0 +1,44 @@ +import { GlAlert } from '@gitlab/ui'; +import { shallowMount } from '@vue/test-utils'; +import { nextTick } from 'vue'; +import PapaParseAlert from '~/vue_shared/components/papa_parse_alert.vue'; + +describe('app/assets/javascripts/vue_shared/components/papa_parse_alert.vue', () => { + let wrapper; + + const createComponent = ({ errorMessages } = {}) => { + wrapper = shallowMount(PapaParseAlert, { + propsData: { + papaParseErrors: errorMessages, + }, + }); + }; + + const findAlert = () => wrapper.findComponent(GlAlert); + + afterEach(() => { + wrapper.destroy(); + }); + + it('should render alert with correct props', async () => { + createComponent({ errorMessages: [{ code: 'MissingQuotes' }] }); + await nextTick; + + expect(findAlert().props()).toMatchObject({ + variant: 'danger', + }); + expect(findAlert().text()).toContain( + 'Failed to render the CSV file for the following reasons:', + ); + expect(findAlert().text()).toContain('Quoted field unterminated'); + }); + + it('should render original message if no translation available', async () => { + createComponent({ + errorMessages: [{ code: 'NotDefined', message: 'Error code is undefined' }], + }); + await nextTick; + + expect(findAlert().text()).toContain('Error code is undefined'); + }); +}); diff --git a/spec/policies/release_policy_spec.rb b/spec/policies/release_policy_spec.rb index 25468ae2ea2..5a34b1f4236 100644 --- a/spec/policies/release_policy_spec.rb +++ b/spec/policies/release_policy_spec.rb @@ -17,29 +17,6 @@ RSpec.describe ReleasePolicy, :request_store do subject { described_class.new(user, release) } - context 'when the evalute_protected_tag_for_release_permissions feature flag is disabled' do - before do - stub_feature_flags(evalute_protected_tag_for_release_permissions: false) - end - - it 'allows the user to create and update a release' do - is_expected.to be_allowed(:create_release) - is_expected.to be_allowed(:update_release) - end - - it 'prevents the user from destroying a release' do - is_expected.to be_disallowed(:destroy_release) - end - - context 'when the user is maintainer' do - let(:user) { maintainer } - - it 'allows the user to destroy a release' do - is_expected.to be_allowed(:destroy_release) - end - end - end - context 'when the user has access to the protected tag' do let_it_be(:protected_tag) { create(:protected_tag, :developers_can_create, name: release.tag, project: project) } diff --git a/spec/services/releases/create_service_spec.rb b/spec/services/releases/create_service_spec.rb index bf28fde3d90..7287825a0be 100644 --- a/spec/services/releases/create_service_spec.rb +++ b/spec/services/releases/create_service_spec.rb @@ -44,21 +44,6 @@ RSpec.describe Releases::CreateService do it_behaves_like 'a successful release creation' - context 'when tag is protected and user does not have access to it' do - let!(:protected_tag) { create(:protected_tag, :no_one_can_create, name: '*', project: project) } - - it 'track the error event' do - stub_feature_flags(evalute_protected_tag_for_release_permissions: false) - - expect(Gitlab::ErrorTracking).to receive(:log_exception).with( - kind_of(described_class::ReleaseProtectedTagAccessError), - project_id: project.id, - user_id: user.id) - - service.execute - end - end - context 'when the tag does not exist' do let(:tag_name) { 'non-exist-tag' } diff --git a/spec/services/releases/destroy_service_spec.rb b/spec/services/releases/destroy_service_spec.rb index 38cdcef3825..bc5bff0b31d 100644 --- a/spec/services/releases/destroy_service_spec.rb +++ b/spec/services/releases/destroy_service_spec.rb @@ -28,21 +28,6 @@ RSpec.describe Releases::DestroyService do it 'returns the destroyed object' do is_expected.to include(status: :success, release: release) end - - context 'when tag is protected and user does not have access to it' do - let!(:protected_tag) { create(:protected_tag, :no_one_can_create, name: '*', project: project) } - - it 'track the error event' do - stub_feature_flags(evalute_protected_tag_for_release_permissions: false) - - expect(Gitlab::ErrorTracking).to receive(:log_exception).with( - kind_of(described_class::ReleaseProtectedTagAccessError), - project_id: project.id, - user_id: user.id) - - service.execute - end - end end context 'when tag does not exist in the repository' do diff --git a/spec/services/releases/update_service_spec.rb b/spec/services/releases/update_service_spec.rb index 96b562a8071..932a7fab5ec 100644 --- a/spec/services/releases/update_service_spec.rb +++ b/spec/services/releases/update_service_spec.rb @@ -38,21 +38,6 @@ RSpec.describe Releases::UpdateService do service.execute end - context 'when tag is protected and user does not have access to it' do - let!(:protected_tag) { create(:protected_tag, :no_one_can_create, name: '*', project: project) } - - it 'track the error event' do - stub_feature_flags(evalute_protected_tag_for_release_permissions: false) - - expect(Gitlab::ErrorTracking).to receive(:log_exception).with( - kind_of(described_class::ReleaseProtectedTagAccessError), - project_id: project.id, - user_id: user.id) - - service.execute - end - end - context 'when the tag does not exists' do let(:tag_name) { 'foobar' } diff --git a/spec/tooling/danger/project_helper_spec.rb b/spec/tooling/danger/project_helper_spec.rb index 8bcfac5a699..1d95fd1fd6b 100644 --- a/spec/tooling/danger/project_helper_spec.rb +++ b/spec/tooling/danger/project_helper_spec.rb @@ -77,7 +77,7 @@ RSpec.describe Tooling::Danger::ProjectHelper do 'ee/spec/frontend/bar' | [:frontend] 'ee/spec/frontend_integration/bar' | [:frontend] - '.gitlab/ci/frontend.gitlab-ci.yml' | %i[frontend engineering_productivity] + '.gitlab/ci/frontend.gitlab-ci.yml' | %i[frontend tooling] 'app/models/foo' | [:backend] 'bin/foo' | [:backend] @@ -113,22 +113,22 @@ RSpec.describe Tooling::Danger::ProjectHelper do 'Rakefile' | [:backend] 'FOO_VERSION' | [:backend] - 'Dangerfile' | [:engineering_productivity] - 'danger/bundle_size/Dangerfile' | [:engineering_productivity] - 'ee/danger/bundle_size/Dangerfile' | [:engineering_productivity] - 'danger/bundle_size/' | [:engineering_productivity] - 'ee/danger/bundle_size/' | [:engineering_productivity] - '.gitlab-ci.yml' | [:engineering_productivity] - '.gitlab/ci/cng.gitlab-ci.yml' | [:engineering_productivity] - '.gitlab/ci/ee-specific-checks.gitlab-ci.yml' | [:engineering_productivity] - 'scripts/foo' | [:engineering_productivity] - 'tooling/danger/foo' | [:engineering_productivity] - 'ee/tooling/danger/foo' | [:engineering_productivity] - 'lefthook.yml' | [:engineering_productivity] - '.editorconfig' | [:engineering_productivity] - 'tooling/bin/find_foss_tests' | [:engineering_productivity] - '.codeclimate.yml' | [:engineering_productivity] - '.gitlab/CODEOWNERS' | [:engineering_productivity] + 'Dangerfile' | [:tooling] + 'danger/bundle_size/Dangerfile' | [:tooling] + 'ee/danger/bundle_size/Dangerfile' | [:tooling] + 'danger/bundle_size/' | [:tooling] + 'ee/danger/bundle_size/' | [:tooling] + '.gitlab-ci.yml' | [:tooling] + '.gitlab/ci/cng.gitlab-ci.yml' | [:tooling] + '.gitlab/ci/ee-specific-checks.gitlab-ci.yml' | [:tooling] + 'scripts/foo' | [:tooling] + 'tooling/danger/foo' | [:tooling] + 'ee/tooling/danger/foo' | [:tooling] + 'lefthook.yml' | [:tooling] + '.editorconfig' | [:tooling] + 'tooling/bin/find_foss_tests' | [:tooling] + '.codeclimate.yml' | [:tooling] + '.gitlab/CODEOWNERS' | [:tooling] 'lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml' | [:ci_template] 'lib/gitlab/ci/templates/dotNET-Core.yml' | [:ci_template] diff --git a/tooling/danger/project_helper.rb b/tooling/danger/project_helper.rb index 8151e074096..4bcc398fa52 100644 --- a/tooling/danger/project_helper.rb +++ b/tooling/danger/project_helper.rb @@ -74,7 +74,7 @@ module Tooling %r{(\A|/)( \.gitlab/ci/frontend\.gitlab-ci\.yml - )\z}x => %i[frontend engineering_productivity], + )\z}x => %i[frontend tooling], %r{\A(ee/)?db/(geo/)?(migrate|post_migrate)/} => [:database, :migration], %r{\A(ee/)?db/(?!fixtures)[^/]+} => [:database], @@ -84,16 +84,16 @@ module Tooling %r{\A(ee/)?app/finders/} => [:database, :backend], %r{\Arubocop/cop/migration(/|\.rb)} => :database, - %r{\A(\.gitlab-ci\.yml\z|\.gitlab\/ci)} => :engineering_productivity, - %r{\A\.codeclimate\.yml\z} => :engineering_productivity, - %r{\Alefthook.yml\z} => :engineering_productivity, - %r{\A\.editorconfig\z} => :engineering_productivity, - %r{Dangerfile\z} => :engineering_productivity, - %r{\A(ee/)?(danger/|tooling/danger/)} => :engineering_productivity, - %r{\A(ee/)?scripts/} => :engineering_productivity, - %r{\Atooling/} => :engineering_productivity, - %r{(CODEOWNERS)} => :engineering_productivity, - %r{(tests.yml)} => :engineering_productivity, + %r{\A(\.gitlab-ci\.yml\z|\.gitlab\/ci)} => :tooling, + %r{\A\.codeclimate\.yml\z} => :tooling, + %r{\Alefthook.yml\z} => :tooling, + %r{\A\.editorconfig\z} => :tooling, + %r{Dangerfile\z} => :tooling, + %r{\A(ee/)?(danger/|tooling/danger/)} => :tooling, + %r{\A(ee/)?scripts/} => :tooling, + %r{\Atooling/} => :tooling, + %r{(CODEOWNERS)} => :tooling, + %r{(tests.yml)} => :tooling, %r{\Alib/gitlab/ci/templates} => :ci_template, |