Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-07-28 00:09:42 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-07-28 00:09:42 +0300
commit6456305e5810391463cdf58d9b4952903047c05a (patch)
tree3a770fdf551d1fbba8bd9950a9961029c92f9c59
parentc241fef1814b6f2fc5931f3d1e26de0378c02ccf (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--.gitlab/ci/frontend.gitlab-ci.yml7
-rw-r--r--.gitlab/ci/rails.gitlab-ci.yml3
-rw-r--r--Gemfile2
-rw-r--r--Gemfile.lock4
-rw-r--r--app/assets/javascripts/blob/csv/csv_viewer.vue13
-rw-r--r--app/assets/javascripts/content_editor/components/toolbar_link_button.vue13
-rw-r--r--app/assets/javascripts/content_editor/extensions/blockquote.js6
-rw-r--r--app/assets/javascripts/content_editor/extensions/bold.js6
-rw-r--r--app/assets/javascripts/content_editor/extensions/bullet_list.js6
-rw-r--r--app/assets/javascripts/content_editor/extensions/code.js6
-rw-r--r--app/assets/javascripts/content_editor/extensions/code_block_highlight.js6
-rw-r--r--app/assets/javascripts/content_editor/extensions/document.js4
-rw-r--r--app/assets/javascripts/content_editor/extensions/dropcursor.js4
-rw-r--r--app/assets/javascripts/content_editor/extensions/gapcursor.js4
-rw-r--r--app/assets/javascripts/content_editor/extensions/hard_break.js6
-rw-r--r--app/assets/javascripts/content_editor/extensions/heading.js6
-rw-r--r--app/assets/javascripts/content_editor/extensions/history.js4
-rw-r--r--app/assets/javascripts/content_editor/extensions/horizontal_rule.js4
-rw-r--r--app/assets/javascripts/content_editor/extensions/image.js17
-rw-r--r--app/assets/javascripts/content_editor/extensions/italic.js5
-rw-r--r--app/assets/javascripts/content_editor/extensions/link.js12
-rw-r--r--app/assets/javascripts/content_editor/extensions/list_item.js6
-rw-r--r--app/assets/javascripts/content_editor/extensions/ordered_list.js6
-rw-r--r--app/assets/javascripts/content_editor/extensions/paragraph.js6
-rw-r--r--app/assets/javascripts/content_editor/extensions/strike.js10
-rw-r--r--app/assets/javascripts/content_editor/extensions/table.js8
-rw-r--r--app/assets/javascripts/content_editor/extensions/table_cell.js6
-rw-r--r--app/assets/javascripts/content_editor/extensions/table_header.js6
-rw-r--r--app/assets/javascripts/content_editor/extensions/table_row.js48
-rw-r--r--app/assets/javascripts/content_editor/extensions/text.js6
-rw-r--r--app/assets/javascripts/content_editor/services/build_serializer_config.js22
-rw-r--r--app/assets/javascripts/content_editor/services/create_content_editor.js58
-rw-r--r--app/assets/javascripts/content_editor/services/markdown_serializer.js134
-rw-r--r--app/assets/javascripts/vue_shared/components/papa_parse_alert.vue44
-rw-r--r--app/policies/project_policy.rb9
-rw-r--r--app/policies/release_policy.rb6
-rw-r--r--app/services/releases/base_service.rb9
-rw-r--r--app/services/releases/create_service.rb4
-rw-r--r--app/services/releases/destroy_service.rb2
-rw-r--r--app/services/releases/update_service.rb2
-rw-r--r--config/feature_flags/development/evalute_protected_tag_for_release_permissions.yml8
-rw-r--r--danger/specialization_labels/Dangerfile2
-rw-r--r--doc/administration/get_started.md2
-rw-r--r--doc/api/experiments.md50
-rw-r--r--doc/api/users.md1
-rw-r--r--doc/development/documentation/styleguide/index.md4
-rw-r--r--doc/user/application_security/dast/index.md4
-rw-r--r--doc/user/group/settings/img/export_panel_v13_0.pngbin47857 -> 0 bytes
-rw-r--r--doc/user/group/settings/import_export.md31
-rw-r--r--doc/user/project/releases/index.md19
-rw-r--r--doc/user/project/wiki/index.md8
-rw-r--r--locale/gitlab.pot18
-rw-r--r--spec/frontend/blob/csv/csv_viewer_spec.js13
-rw-r--r--spec/frontend/content_editor/components/toolbar_image_button_spec.js14
-rw-r--r--spec/frontend/content_editor/components/toolbar_link_button_spec.js6
-rw-r--r--spec/frontend/content_editor/components/toolbar_table_button_spec.js8
-rw-r--r--spec/frontend/content_editor/components/toolbar_text_style_dropdown_spec.js2
-rw-r--r--spec/frontend/content_editor/extensions/code_block_highlight_spec.js2
-rw-r--r--spec/frontend/content_editor/extensions/hard_break_spec.js2
-rw-r--r--spec/frontend/content_editor/extensions/image_spec.js10
-rw-r--r--spec/frontend/content_editor/services/build_serializer_config_spec.js38
-rw-r--r--spec/frontend/content_editor/services/create_content_editor_spec.js4
-rw-r--r--spec/frontend/content_editor/services/track_input_rules_and_shortcuts_spec.js8
-rw-r--r--spec/frontend/vue_shared/components/papa_parse_alert_spec.js44
-rw-r--r--spec/policies/release_policy_spec.rb23
-rw-r--r--spec/services/releases/create_service_spec.rb15
-rw-r--r--spec/services/releases/destroy_service_spec.rb15
-rw-r--r--spec/services/releases/update_service_spec.rb15
-rw-r--r--spec/tooling/danger/project_helper_spec.rb34
-rw-r--r--tooling/danger/project_helper.rb22
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:
diff --git a/Gemfile b/Gemfile
index c14418ba7e3..2e2227d9875 100644
--- a/Gemfile
+++ b/Gemfile
@@ -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
deleted file mode 100644
index 36549e1f3f5..00000000000
--- a/doc/user/group/settings/img/export_panel_v13_0.png
+++ /dev/null
Binary files differ
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,