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:
-rw-r--r--.gitlab/ci/rules.gitlab-ci.yml5
-rw-r--r--.gitlab/issue_templates/Deprecations.md2
-rw-r--r--app/assets/javascripts/ci_variable_list/components/ci_variable_modal.vue3
-rw-r--r--app/assets/javascripts/content_editor/services/hast_to_prosemirror_converter.js141
-rw-r--r--app/assets/javascripts/content_editor/services/remark_markdown_deserializer.js15
-rw-r--r--app/assets/javascripts/feature_flags/components/form.vue6
-rw-r--r--app/assets/javascripts/feature_flags/components/new_environments_dropdown.vue2
-rw-r--r--app/assets/javascripts/feature_flags/components/strategy.vue2
-rw-r--r--app/assets/javascripts/groups/components/item_caret.vue2
-rw-r--r--app/assets/javascripts/ide/components/jobs/detail/description.vue2
-rw-r--r--app/assets/javascripts/issues/list/components/issues_list_app.vue15
-rw-r--r--app/assets/javascripts/pipelines/components/pipelines_list/pipeline_stage.vue3
-rw-r--r--app/assets/javascripts/terraform/components/states_table_actions.vue10
-rw-r--r--app/assets/javascripts/terraform/components/terraform_list.vue5
-rw-r--r--app/assets/javascripts/terraform/index.js2
-rw-r--r--app/assets/javascripts/vue_shared/components/ci_icon.vue11
-rw-r--r--app/assets/javascripts/vue_shared/issuable/list/constants.js7
-rw-r--r--app/assets/stylesheets/framework/icons.scss22
-rw-r--r--app/models/ci/runner.rb12
-rw-r--r--app/services/web_hook_service.rb25
-rw-r--r--app/views/devise/registrations/new.html.haml1
-rw-r--r--config/feature_flags/development/delayed_repository_update_mirror_worker.yml8
-rw-r--r--data/deprecations/15-1-jira-github-enterprise-dvcs.yml16
-rw-r--r--doc/development/integrations/secure.md3
-rw-r--r--doc/development/integrations/secure_partner_integration.md1
-rw-r--r--doc/integration/elasticsearch.md18
-rw-r--r--doc/update/deprecations.md15
-rw-r--r--doc/user/application_security/cluster_image_scanning/index.md324
-rw-r--r--doc/user/application_security/configuration/index.md4
-rw-r--r--doc/user/application_security/policies/scan-execution-policies.md2
-rw-r--r--doc/user/clusters/agent/vulnerabilities.md2
-rw-r--r--doc/user/packages/terraform_module_registry/index.md10
-rw-r--r--lib/gitlab/github_import/importer/issue_importer.rb8
-rw-r--r--locale/gitlab.pot3
-rw-r--r--spec/frontend/ci_variable_list/components/ci_variable_modal_spec.js5
-rw-r--r--spec/frontend/content_editor/remark_markdown_processing_spec.js117
-rw-r--r--spec/frontend/groups/components/item_caret_spec.js4
-rw-r--r--spec/frontend/ide/components/jobs/detail/description_spec.js6
-rw-r--r--spec/frontend/issues/list/components/issues_list_app_spec.js23
-rw-r--r--spec/frontend/pipelines/components/pipelines_list/pipeline_stage_spec.js11
-rw-r--r--spec/frontend/terraform/components/states_table_actions_spec.js1
-rw-r--r--spec/frontend/terraform/components/states_table_spec.js1
-rw-r--r--spec/frontend/terraform/components/terraform_list_spec.js4
-rw-r--r--spec/lib/gitlab/github_import/importer/issue_importer_spec.rb56
-rw-r--r--spec/models/ci/runner_spec.rb62
45 files changed, 528 insertions, 469 deletions
diff --git a/.gitlab/ci/rules.gitlab-ci.yml b/.gitlab/ci/rules.gitlab-ci.yml
index bc7a5663ac9..d93164b35b9 100644
--- a/.gitlab/ci/rules.gitlab-ci.yml
+++ b/.gitlab/ci/rules.gitlab-ci.yml
@@ -73,6 +73,9 @@
.if-merge-request-labels-skip-undercoverage: &if-merge-request-labels-skip-undercoverage
if: '$CI_MERGE_REQUEST_LABELS =~ /pipeline:skip-undercoverage/'
+.if-merge-request-labels-community-contribution: &if-merge-request-labels-community-contribution
+ if: '$CI_MERGE_REQUEST_LABELS =~ /Community contribution/'
+
.if-merge-request-labels-jh-contribution: &if-merge-request-labels-jh-contribution
if: '$CI_MERGE_REQUEST_LABELS =~ /JiHu contribution/'
@@ -1664,6 +1667,8 @@
rules:
- <<: *if-not-canonical-namespace
when: never
+ - <<: *if-merge-request-labels-community-contribution
+ when: never
- <<: *if-merge-request
###############
diff --git a/.gitlab/issue_templates/Deprecations.md b/.gitlab/issue_templates/Deprecations.md
index 2e48c272316..3dfed1a1fc1 100644
--- a/.gitlab/issue_templates/Deprecations.md
+++ b/.gitlab/issue_templates/Deprecations.md
@@ -47,7 +47,7 @@ Please add links to the relevant merge requests.
- As soon as possible, but no later than the third milestone preceding the major release (for example, given the following release schedule: `14.8, 14.9, 14.10, 15.0` – `14.8` is the third milestone preceding the major release):
- [ ] A [deprecation entry](https://about.gitlab.com/handbook/marketing/blog/release-posts/#creating-a-deprecation-entry) has been created so the deprecation will appear in release posts and on the [general deprecation page](https://docs.gitlab.com/ee/update/deprecations).
- - [ ] Documentation has been updated to add a note about the [end-of-life](https://docs.gitlab.com/ee/development/documentation/styleguide/#end-of-life-for-features-or-products) and to mark the feature as [deprecated](https://docs.gitlab.com/ee/development/documentation/styleguide/#deprecated-features).
+ - [ ] Documentation has been updated to mark the feature as [deprecated](https://docs.gitlab.com/ee/development/documentation/versions.html#deprecations-and-removals).
- [ ] On or before the major milestone: A [removal entry](https://about.gitlab.com/handbook/marketing/blog/release-posts/#removals) has been created so the removal will appear on the [removals by milestones](https://docs.gitlab.com/ee/update/removals) page and be announced in the release post.
- On the major milestone:
- [ ] The deprecated item has been removed.
diff --git a/app/assets/javascripts/ci_variable_list/components/ci_variable_modal.vue b/app/assets/javascripts/ci_variable_list/components/ci_variable_modal.vue
index 3af89dc4a2c..557a8d6b5ba 100644
--- a/app/assets/javascripts/ci_variable_list/components/ci_variable_modal.vue
+++ b/app/assets/javascripts/ci_variable_list/components/ci_variable_modal.vue
@@ -369,7 +369,7 @@ export default {
:href="awsTipLearnLink"
target="_blank"
category="secondary"
- variant="info"
+ variant="confirm"
class="gl-overflow-wrap-break"
>{{ __('Learn more about deploying to AWS') }}</gl-button
>
@@ -416,6 +416,7 @@ export default {
:disabled="!canSubmit"
variant="confirm"
category="primary"
+ data-testid="ciUpdateOrAddVariableBtn"
data-qa-selector="ci_variable_save_button"
@click="updateOrAddVariable"
>{{ modalActionText }}
diff --git a/app/assets/javascripts/content_editor/services/hast_to_prosemirror_converter.js b/app/assets/javascripts/content_editor/services/hast_to_prosemirror_converter.js
index dce33889c48..f38e4514393 100644
--- a/app/assets/javascripts/content_editor/services/hast_to_prosemirror_converter.js
+++ b/app/assets/javascripts/content_editor/services/hast_to_prosemirror_converter.js
@@ -20,7 +20,7 @@
*/
import { Mark } from 'prosemirror-model';
-import { visitParents } from 'unist-util-visit-parents';
+import { visitParents, SKIP } from 'unist-util-visit-parents';
import { toString } from 'hast-util-to-string';
import { isFunction, isString, noop } from 'lodash';
@@ -143,6 +143,20 @@ class HastToProseMirrorConverterState {
return this.stack.length === 0;
}
+ findInStack(fn) {
+ const last = this.stack.length - 1;
+
+ for (let i = last; i >= 0; i -= 1) {
+ const item = this.stack[i];
+
+ if (fn(item) === true) {
+ return item;
+ }
+ }
+
+ return null;
+ }
+
/**
* Creates a text node and adds it to
* the top node in the stack.
@@ -254,34 +268,20 @@ const createProseMirrorNodeFactories = (schema, proseMirrorFactorySpecs, source)
const factories = {
root: {
selector: 'root',
- handle: (state, hastNode) =>
- state.openNode(
- schema.topNodeType,
- hastNode,
- {},
- {
- wrapTextInParagraph: true,
- },
- ),
+ wrapInParagraph: true,
+ handle: (state, hastNode) => state.openNode(schema.topNodeType, hastNode, {}, {}),
},
text: {
selector: 'text',
- handle: (state, hastNode, parent) => {
- const { factorySpec } = state.top;
- const { processText, wrapTextInParagraph } = factorySpec;
+ handle: (state, hastNode) => {
+ const found = state.findInStack((node) => isFunction(node.factorySpec.processText));
const { value: text } = hastNode;
if (/^\s+$/.test(text)) {
return;
}
- if (wrapTextInParagraph === true) {
- state.openNode(schema.nodeType('paragraph'), hastNode, getAttrs({}, parent, [], source));
- state.addText(schema, isFunction(processText) ? processText(text) : text);
- state.closeNode();
- } else {
- state.addText(schema, text);
- }
+ state.addText(schema, found ? found.factorySpec.processText(text) : text);
},
},
};
@@ -291,6 +291,7 @@ const createProseMirrorNodeFactories = (schema, proseMirrorFactorySpecs, source)
skipChildren: factorySpec.skipChildren,
processText: factorySpec.processText,
parent: factorySpec.parent,
+ wrapInParagraph: factorySpec.wrapInParagraph,
};
if (factorySpec.type === 'block') {
@@ -370,6 +371,75 @@ const findParent = (ancestors, parent) => {
return ancestors[ancestors.length - 1];
};
+const calcTextNodePosition = (textNode) => {
+ const { position, value, type } = textNode;
+
+ if (type !== 'text' || (!position.start && !position.end) || (position.start && position.end)) {
+ return textNode.position;
+ }
+
+ const span = value.length - 1;
+
+ if (position.start && !position.end) {
+ const { start } = position;
+
+ return {
+ start,
+ end: {
+ row: start.row,
+ column: start.column + span,
+ offset: start.offset + span,
+ },
+ };
+ }
+
+ const { end } = position;
+
+ return {
+ start: {
+ row: end.row,
+ column: end.column - span,
+ offset: end.offset - span,
+ },
+ end,
+ };
+};
+
+const removeEmptyTextNodes = (nodes) =>
+ nodes.filter(
+ (node) => node.type !== 'text' || (node.type === 'text' && !/^\s+$/.test(node.value)),
+ );
+
+const wrapInlineElements = (nodes, wrappableTags) =>
+ nodes.reduce((children, child) => {
+ const previous = children[children.length - 1];
+
+ if (child.type !== 'text' && !wrappableTags.includes(child.tagName)) {
+ return [...children, child];
+ }
+
+ const wrapperExists = previous?.properties.wrapper;
+
+ if (wrapperExists) {
+ const wrapper = previous;
+
+ wrapper.position.end = child.position.end;
+ wrapper.children.push(child);
+
+ return children;
+ }
+
+ const wrapper = {
+ type: 'element',
+ tagName: 'p',
+ position: calcTextNodePosition(child),
+ children: [child],
+ properties: { wrapper: true },
+ };
+
+ return [...children, wrapper];
+ }, []);
+
/**
* Converts a Hast AST to a ProseMirror document based on a series
* of specifications that describe how to map all the nodes of the former
@@ -445,10 +515,11 @@ const findParent = (ancestors, parent) => {
* 2. hasParents: All the hast node’s ancestors up to the root node
* 3. source: Markdown source file’s content
*
- * **wrapTextInParagraph**
+ * **wrapInParagraph**
*
- * This property only applies to block nodes. If a block node contains text,
- * it will wrap that text in a paragraph. This is useful for ProseMirror block
+ * This property only applies to block nodes. If a block node contains inline
+ * elements like text, images, links, etc, the converter will wrap those inline
+ * elements in a paragraph. This is useful for ProseMirror block
* nodes that don’t allow text directly such as list items and tables.
*
* **processText**
@@ -485,7 +556,13 @@ const findParent = (ancestors, parent) => {
*
* @returns A ProseMirror document
*/
-export const createProseMirrorDocFromMdastTree = ({ schema, factorySpecs, tree, source }) => {
+export const createProseMirrorDocFromMdastTree = ({
+ schema,
+ factorySpecs,
+ wrappableTags,
+ tree,
+ source,
+}) => {
const proseMirrorNodeFactories = createProseMirrorNodeFactories(schema, factorySpecs, source);
const state = new HastToProseMirrorConverterState();
@@ -502,9 +579,23 @@ export const createProseMirrorDocFromMdastTree = ({ schema, factorySpecs, tree,
const parent = findParent(ancestors, factory.parent);
+ if (factory.wrapInParagraph) {
+ /**
+ * Modifying parameters is a bad practice. For performance reasons,
+ * the author of the unist-util-visit-parents function recommends
+ * modifying nodes in place to avoid traversing the Abstract Syntax
+ * Tree more than once
+ */
+ // eslint-disable-next-line no-param-reassign
+ hastNode.children = wrapInlineElements(
+ removeEmptyTextNodes(hastNode.children),
+ wrappableTags,
+ );
+ }
+
factory.handle(state, hastNode, parent);
- return factory.skipChildren === true ? 'skip' : true;
+ return factory.skipChildren === true ? SKIP : true;
});
let doc;
diff --git a/app/assets/javascripts/content_editor/services/remark_markdown_deserializer.js b/app/assets/javascripts/content_editor/services/remark_markdown_deserializer.js
index 9fb0d520848..12b3f288e22 100644
--- a/app/assets/javascripts/content_editor/services/remark_markdown_deserializer.js
+++ b/app/assets/javascripts/content_editor/services/remark_markdown_deserializer.js
@@ -2,6 +2,8 @@ import { isString } from 'lodash';
import { render } from '~/lib/gfm';
import { createProseMirrorDocFromMdastTree } from './hast_to_prosemirror_converter';
+const wrappableTags = ['img', 'br', 'code', 'i', 'em', 'b', 'strong', 'a', 'strike', 's', 'del'];
+
const isTaskItem = (hastNode) => {
const { className } = hastNode.properties;
@@ -20,9 +22,9 @@ const factorySpecs = {
paragraph: { type: 'block', selector: 'p' },
listItem: {
type: 'block',
- wrapTextInParagraph: true,
- processText: (text) => text.trim(),
+ wrapInParagraph: true,
selector: (hastNode) => hastNode.tagName === 'li' && !hastNode.properties.className,
+ processText: (text) => text.trimRight(),
},
orderedList: {
type: 'block',
@@ -74,12 +76,12 @@ const factorySpecs = {
},
taskItem: {
type: 'block',
- wrapTextInParagraph: true,
- processText: (text) => text.trim(),
+ wrapInParagraph: true,
selector: isTaskItem,
getAttrs: (hastNode) => ({
checked: hastNode.children[0].properties.checked,
}),
+ processText: (text) => text.trimLeft(),
},
taskItemCheckbox: {
type: 'ignore',
@@ -99,13 +101,13 @@ const factorySpecs = {
type: 'block',
selector: 'th',
getAttrs: getTableCellAttrs,
- wrapTextInParagraph: true,
+ wrapInParagraph: true,
},
tableCell: {
type: 'block',
selector: 'td',
getAttrs: getTableCellAttrs,
- wrapTextInParagraph: true,
+ wrapInParagraph: true,
},
ignoredTableNodes: {
type: 'ignore',
@@ -160,6 +162,7 @@ export default () => {
schema,
factorySpecs,
tree,
+ wrappableTags,
source: markdown,
}),
});
diff --git a/app/assets/javascripts/feature_flags/components/form.vue b/app/assets/javascripts/feature_flags/components/form.vue
index 26da0d56f9a..ec5a241bb16 100644
--- a/app/assets/javascripts/feature_flags/components/form.vue
+++ b/app/assets/javascripts/feature_flags/components/form.vue
@@ -211,16 +211,16 @@ export default {
</div>
</fieldset>
- <div class="form-actions">
+ <div class="gl-mr-6">
<gl-button
ref="submitButton"
type="button"
variant="confirm"
- class="js-ff-submit col-xs-12"
+ class="js-ff-submit gl-mr-2"
@click="handleSubmit"
>{{ submitText }}</gl-button
>
- <gl-button :href="cancelPath" class="js-ff-cancel col-xs-12 float-right">
+ <gl-button :href="cancelPath" class="js-ff-cancel">
{{ __('Cancel') }}
</gl-button>
</div>
diff --git a/app/assets/javascripts/feature_flags/components/new_environments_dropdown.vue b/app/assets/javascripts/feature_flags/components/new_environments_dropdown.vue
index 5575c6567b5..98982920121 100644
--- a/app/assets/javascripts/feature_flags/components/new_environments_dropdown.vue
+++ b/app/assets/javascripts/feature_flags/components/new_environments_dropdown.vue
@@ -72,7 +72,7 @@ export default {
<span class="d-md-none mr-1">
{{ $options.translations.addEnvironmentsLabel }}
</span>
- <gl-icon class="d-none d-md-inline-flex" name="plus" />
+ <gl-icon class="d-none d-md-inline-flex gl-mr-1" name="plus" />
</template>
<gl-search-box-by-type
ref="searchBox"
diff --git a/app/assets/javascripts/feature_flags/components/strategy.vue b/app/assets/javascripts/feature_flags/components/strategy.vue
index 3f515dcdf18..1d7a79f926a 100644
--- a/app/assets/javascripts/feature_flags/components/strategy.vue
+++ b/app/assets/javascripts/feature_flags/components/strategy.vue
@@ -176,7 +176,7 @@ export default {
}}</label>
<div class="gl-display-flex gl-flex-direction-column">
<div
- class="gl-display-flex gl-flex-direction-column gl-md-flex-direction-row align-items-start gl-md-align-items-center"
+ class="gl-display-flex gl-flex-direction-column gl-md-flex-direction-row gl-md-align-items-center"
>
<new-environments-dropdown
:id="environmentsDropdownId"
diff --git a/app/assets/javascripts/groups/components/item_caret.vue b/app/assets/javascripts/groups/components/item_caret.vue
index a51edd385dd..94d39a9c572 100644
--- a/app/assets/javascripts/groups/components/item_caret.vue
+++ b/app/assets/javascripts/groups/components/item_caret.vue
@@ -14,7 +14,7 @@ export default {
},
computed: {
iconClass() {
- return this.isGroupOpen ? 'angle-down' : 'angle-right';
+ return this.isGroupOpen ? 'chevron-down' : 'chevron-right';
},
},
};
diff --git a/app/assets/javascripts/ide/components/jobs/detail/description.vue b/app/assets/javascripts/ide/components/jobs/detail/description.vue
index 8fd1973267c..c184e25f67f 100644
--- a/app/assets/javascripts/ide/components/jobs/detail/description.vue
+++ b/app/assets/javascripts/ide/components/jobs/detail/description.vue
@@ -23,7 +23,7 @@ export default {
<template>
<div class="d-flex align-items-center">
- <ci-icon :status="job.status" :borderless="true" :size="24" class="d-flex" />
+ <ci-icon is-borderless :status="job.status" :size="24" class="d-flex" />
<span class="gl-ml-3">
{{ job.name }}
<a
diff --git a/app/assets/javascripts/issues/list/components/issues_list_app.vue b/app/assets/javascripts/issues/list/components/issues_list_app.vue
index bd4b8ca0455..1a6874728ea 100644
--- a/app/assets/javascripts/issues/list/components/issues_list_app.vue
+++ b/app/assets/javascripts/issues/list/components/issues_list_app.vue
@@ -39,7 +39,11 @@ import {
TOKEN_TITLE_TYPE,
} from '~/vue_shared/components/filtered_search_bar/constants';
import IssuableList from '~/vue_shared/issuable/list/components/issuable_list_root.vue';
-import { IssuableListTabs, IssuableStates } from '~/vue_shared/issuable/list/constants';
+import {
+ IssuableListTabs,
+ IssuableStates,
+ IssuableTypes,
+} from '~/vue_shared/issuable/list/constants';
import {
CREATED_DESC,
i18n,
@@ -98,6 +102,7 @@ const ReleaseToken = () =>
export default {
i18n,
IssuableListTabs,
+ IssuableTypes: [IssuableTypes.Issue, IssuableTypes.Incident, IssuableTypes.TestCase],
components: {
CsvImportExportButtons,
GlButton,
@@ -168,7 +173,9 @@ export default {
issues: {
query: getIssuesQuery,
variables() {
- return this.queryVariables;
+ const { types } = this.queryVariables;
+
+ return { ...this.queryVariables, types: types ? [types] : this.$options.IssuableTypes };
},
update(data) {
return data[this.namespace]?.issues.nodes ?? [];
@@ -192,7 +199,9 @@ export default {
issuesCounts: {
query: getIssuesCountsQuery,
variables() {
- return this.queryVariables;
+ const { types } = this.queryVariables;
+
+ return { ...this.queryVariables, types: types ? [types] : this.$options.IssuableTypes };
},
update(data) {
return data[this.namespace] ?? {};
diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_stage.vue b/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_stage.vue
index 7544382aa4d..43e31037c36 100644
--- a/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_stage.vue
+++ b/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_stage.vue
@@ -127,12 +127,13 @@ export default {
>
<template #button-content>
<ci-icon
+ is-borderless
is-interactive
css-classes="gl-rounded-full"
:is-active="isDropdownOpen"
:size="24"
:status="stage.status"
- class="gl-align-items-center gl-display-inline-flex gl-z-index-1"
+ class="gl-align-items-center gl-border gl-display-inline-flex gl-z-index-1"
/>
</template>
<div
diff --git a/app/assets/javascripts/terraform/components/states_table_actions.vue b/app/assets/javascripts/terraform/components/states_table_actions.vue
index 1970d6d7949..773ecf1d5d5 100644
--- a/app/assets/javascripts/terraform/components/states_table_actions.vue
+++ b/app/assets/javascripts/terraform/components/states_table_actions.vue
@@ -33,6 +33,7 @@ export default {
directives: {
GlModalDirective,
},
+ inject: ['projectPath'],
props: {
state: {
required: true,
@@ -149,7 +150,14 @@ export default {
variables: {
stateID: this.state.id,
},
- refetchQueries: () => [{ query: getStatesQuery }],
+ refetchQueries: () => [
+ {
+ query: getStatesQuery,
+ variables: {
+ projectPath: this.projectPath,
+ },
+ },
+ ],
awaitRefetchQueries: true,
notifyOnNetworkStatusChange: true,
})
diff --git a/app/assets/javascripts/terraform/components/terraform_list.vue b/app/assets/javascripts/terraform/components/terraform_list.vue
index cc8538ec2e8..f098b447d10 100644
--- a/app/assets/javascripts/terraform/components/terraform_list.vue
+++ b/app/assets/javascripts/terraform/components/terraform_list.vue
@@ -31,15 +31,12 @@ export default {
GlTabs,
StatesTable,
},
+ inject: ['projectPath'],
props: {
emptyStateImage: {
required: true,
type: String,
},
- projectPath: {
- required: true,
- type: String,
- },
terraformAdmin: {
required: false,
type: Boolean,
diff --git a/app/assets/javascripts/terraform/index.js b/app/assets/javascripts/terraform/index.js
index 34261f3c4db..571177986d2 100644
--- a/app/assets/javascripts/terraform/index.js
+++ b/app/assets/javascripts/terraform/index.js
@@ -30,6 +30,7 @@ export default () => {
el,
apolloProvider: new VueApollo({ defaultClient }),
provide: {
+ projectPath,
accessTokensPath,
terraformApiUrl,
username,
@@ -38,7 +39,6 @@ export default () => {
return createElement(TerraformList, {
props: {
emptyStateImage,
- projectPath,
terraformAdmin: el.hasAttribute('data-terraform-admin'),
},
});
diff --git a/app/assets/javascripts/vue_shared/components/ci_icon.vue b/app/assets/javascripts/vue_shared/components/ci_icon.vue
index c70f028a876..8bffc2479a1 100644
--- a/app/assets/javascripts/vue_shared/components/ci_icon.vue
+++ b/app/assets/javascripts/vue_shared/components/ci_icon.vue
@@ -45,12 +45,12 @@ export default {
return validSizes.includes(value);
},
},
- borderless: {
+ isActive: {
type: Boolean,
required: false,
default: false,
},
- isActive: {
+ isBorderless: {
type: Boolean,
required: false,
default: false,
@@ -72,14 +72,17 @@ export default {
return `ci-status-icon ci-status-icon-${status} js-ci-status-icon-${status} gl-rounded-full gl-justify-content-center`;
},
icon() {
- return this.borderless ? `${this.status.icon}_borderless` : this.status.icon;
+ return this.isBorderless ? `${this.status.icon}_borderless` : this.status.icon;
},
},
};
</script>
<template>
<span
- :class="[wrapperStyleClasses, { interactive: isInteractive, active: isActive }]"
+ :class="[
+ wrapperStyleClasses,
+ { interactive: isInteractive, active: isActive, borderless: isBorderless },
+ ]"
:style="{ height: `${size}px`, width: `${size}px` }"
data-testid="ci-icon-wrapper"
>
diff --git a/app/assets/javascripts/vue_shared/issuable/list/constants.js b/app/assets/javascripts/vue_shared/issuable/list/constants.js
index c6dce6a51c2..be9afc0610d 100644
--- a/app/assets/javascripts/vue_shared/issuable/list/constants.js
+++ b/app/assets/javascripts/vue_shared/issuable/list/constants.js
@@ -46,6 +46,13 @@ export const AvailableSortOptions = [
},
];
+export const IssuableTypes = {
+ Issue: 'ISSUE',
+ Incident: 'INCIDENT',
+ TestCase: 'TEST_CASE',
+ Requirement: 'REQUIREMENT',
+};
+
export const DEFAULT_PAGE_SIZE = 20;
export const DEFAULT_SKELETON_COUNT = 5;
diff --git a/app/assets/stylesheets/framework/icons.scss b/app/assets/stylesheets/framework/icons.scss
index 1a6a461dad8..a8e740525e2 100644
--- a/app/assets/stylesheets/framework/icons.scss
+++ b/app/assets/stylesheets/framework/icons.scss
@@ -4,22 +4,22 @@
fill: $primary-color;
}
+ // For the pipeline mini graph, we pass a custom 'gl-border' so that we can enforce
+ // a border of 1px instead of the thicker svg borders to adhere to design standards.
+ // If we implement the component with 'isBorderless' and also pass that border,
+ // this css is to dynamically apply the correct border color for those specific icons.
+ &.borderless {
+ border-color: $primary-color;
+ }
+
&.interactive {
&:hover {
- background: $primary-color;
-
- .gl-icon {
- --svg-status-bg: #{$svg-color};
- box-shadow: 0 0 0 1px $primary-color;
- }
+ background: $svg-color;
}
+ &:hover,
&.active {
- background: $primary-color;
-
- .gl-icon {
- box-shadow: 0 0 0 1px $primary-color;
- }
+ box-shadow: 0 0 0 1px $primary-color;
}
}
}
diff --git a/app/models/ci/runner.rb b/app/models/ci/runner.rb
index 7a1d52f5aea..61194c9b7d1 100644
--- a/app/models/ci/runner.rb
+++ b/app/models/ci/runner.rb
@@ -77,6 +77,7 @@ module Ci
has_one :last_build, -> { order('id DESC') }, class_name: 'Ci::Build'
before_save :ensure_token
+ before_save :update_semver, if: -> { version_changed? }
scope :active, -> (value = true) { where(active: value) }
scope :paused, -> { active(false) }
@@ -429,6 +430,7 @@ module Ci
values = values&.slice(:version, :revision, :platform, :architecture, :ip_address, :config, :executor) || {}
values[:contacted_at] = Time.current
values[:executor_type] = EXECUTOR_NAME_TO_TYPES.fetch(values.delete(:executor), :unknown)
+ values[:semver] = semver_from_version(values[:version])
cache_attributes(values)
@@ -449,6 +451,16 @@ module Ci
read_attribute(:contacted_at)
end
+ def semver_from_version(version)
+ parsed_runner_version = ::Gitlab::VersionInfo.parse(version)
+
+ parsed_runner_version.valid? ? parsed_runner_version.to_s : nil
+ end
+
+ def update_semver
+ self.semver = semver_from_version(self.version)
+ end
+
def namespace_ids
strong_memoize(:namespace_ids) do
runner_namespaces.pluck(:namespace_id).compact
diff --git a/app/services/web_hook_service.rb b/app/services/web_hook_service.rb
index 6526e6a4c5e..7caccd13a99 100644
--- a/app/services/web_hook_service.rb
+++ b/app/services/web_hook_service.rb
@@ -234,23 +234,22 @@ class WebHookService
end
def log_rate_limited
- Gitlab::AuthLogger.error(
- message: 'Webhook rate limit exceeded',
- hook_id: hook.id,
- hook_type: hook.type,
- hook_name: hook_name,
- **Gitlab::ApplicationContext.current
- )
+ log_auth_error('Webhook rate limit exceeded')
end
def log_recursion_blocked
+ log_auth_error(
+ 'Recursive webhook blocked from executing',
+ recursion_detection: ::Gitlab::WebHooks::RecursionDetection.to_log(hook)
+ )
+ end
+
+ def log_auth_error(message, params = {})
Gitlab::AuthLogger.error(
- message: 'Recursive webhook blocked from executing',
- hook_id: hook.id,
- hook_type: hook.type,
- hook_name: hook_name,
- recursion_detection: ::Gitlab::WebHooks::RecursionDetection.to_log(hook),
- **Gitlab::ApplicationContext.current
+ params.merge(
+ { message: message, hook_id: hook.id, hook_type: hook.type, hook_name: hook_name },
+ Gitlab::ApplicationContext.current
+ )
)
end
diff --git a/app/views/devise/registrations/new.html.haml b/app/views/devise/registrations/new.html.haml
index 60c3df718a1..b6acb244384 100644
--- a/app/views/devise/registrations/new.html.haml
+++ b/app/views/devise/registrations/new.html.haml
@@ -1,4 +1,5 @@
- page_title _("Sign up")
+- page_description _("Join GitLab today! You and your team can plan, build, and ship secure code all in one application. Get started here for free!")
- add_page_specific_style 'page_bundles/signup'
- content_for :page_specific_javascripts do
= render "layouts/google_tag_manager_head"
diff --git a/config/feature_flags/development/delayed_repository_update_mirror_worker.yml b/config/feature_flags/development/delayed_repository_update_mirror_worker.yml
new file mode 100644
index 00000000000..acf5902716e
--- /dev/null
+++ b/config/feature_flags/development/delayed_repository_update_mirror_worker.yml
@@ -0,0 +1,8 @@
+---
+name: delayed_repository_update_mirror_worker
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/89501
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/362894
+milestone: '15.1'
+type: development
+group: group::source code
+default_enabled: false
diff --git a/data/deprecations/15-1-jira-github-enterprise-dvcs.yml b/data/deprecations/15-1-jira-github-enterprise-dvcs.yml
new file mode 100644
index 00000000000..ac8b630c1ff
--- /dev/null
+++ b/data/deprecations/15-1-jira-github-enterprise-dvcs.yml
@@ -0,0 +1,16 @@
+- name: "Jira GitHub Enterprise DVCS integration" # The name of the feature to be deprecated
+ announcement_milestone: "15.1" # The milestone when this feature was first announced as deprecated.
+ announcement_date: "2022-06-22" # The date of the milestone release when this feature was first announced as deprecated. This should almost always be the 22nd of a month (YYYY-MM-22), unless you did an out of band blog post.
+ removal_milestone: "16.0" # The milestone when this feature is planned to be removed
+ removal_date: "2023-05-22" # The date of the milestone release when this feature was first announced as deprecated. This should almost always be the 22nd of a month (YYYY-MM-22), unless you did an out of band blog post.
+ breaking_change: true # If this deprecation is a breaking change, set this value to true
+ body: | # Do not modify this line, instead modify the lines below.
+ The [Jira DVCS Connector](https://docs.gitlab.com/ee/integration/jira/dvcs.html) (which enables the [Jira Development Panel](https://support.atlassian.com/jira-software-cloud/docs/view-development-information-for-an-issue/)), will no longer support Jira Cloud users starting with GitLab 16.0. The [GitLab for Jira App](https://docs.gitlab.com/ee/integration/jira/connect-app.html) has always been recommended for Jira Cloud users, and it will be required instead of the DVCS connector. If you are a Jira Cloud user, we recommended you begin migrating to the GitLab for Jira App.
+ Any Jira Server and Jira Data Center users will need to confirm they are not using the GitHub Enterprise Connector to enable the GitLab DVCS integration, but they may continue to use the [native GitLab DVCS integration](https://docs.gitlab.com/ee/integration/jira/dvcs.html) (supported in Jira 8.14 and later).
+# The following items are not published on the docs page, but may be used in the future.
+ stage: Ecosystem # (optional - may be required in the future) String value of the stage that the feature was created in. e.g., Growth
+ tiers: # (optional - may be required in the future) An array of tiers that the feature is available in currently. e.g., [Free, Silver, Gold, Core, Premium, Ultimate]
+ issue_url: https://gitlab.com/groups/gitlab-org/-/epics/7508 # (optional) This is a link to the deprecation issue in GitLab
+ documentation_url: https://docs.gitlab.com/ee/integration/jira/dvcs.html # (optional) This is a link to the current documentation page
+ image_url: # (optional) This is a link to a thumbnail image depicting the feature
+ video_url: # (optional) Use the youtube thumbnail URL with the structure of https://img.youtube.com/vi/UNIQUEID/hqdefault.jpg
diff --git a/doc/development/integrations/secure.md b/doc/development/integrations/secure.md
index 74020fe38a9..83bf64bb9f1 100644
--- a/doc/development/integrations/secure.md
+++ b/doc/development/integrations/secure.md
@@ -312,8 +312,7 @@ The format is extensively described in the documentation of
[SAST](../../user/application_security/sast/index.md#reports-json-format),
[DAST](../../user/application_security/dast/#reports),
[Dependency Scanning](../../user/application_security/dependency_scanning/index.md#reports-json-format),
-[Container Scanning](../../user/application_security/container_scanning/index.md#reports-json-format),
-and [Cluster Image Scanning](../../user/application_security/cluster_image_scanning/index.md#reports-json-format).
+and [Container Scanning](../../user/application_security/container_scanning/index.md#reports-json-format)
You can find the schemas for these scanners here:
diff --git a/doc/development/integrations/secure_partner_integration.md b/doc/development/integrations/secure_partner_integration.md
index e55b2d34613..63f86a3f95d 100644
--- a/doc/development/integrations/secure_partner_integration.md
+++ b/doc/development/integrations/secure_partner_integration.md
@@ -90,7 +90,6 @@ and complete an integration with the Secure stage.
- Documentation for [SAST reports](../../user/application_security/sast/index.md#reports-json-format).
- Documentation for [Dependency Scanning reports](../../user/application_security/dependency_scanning/index.md#reports-json-format).
- Documentation for [Container Scanning reports](../../user/application_security/container_scanning/index.md#reports-json-format).
- - Documentation for [`cluster_image_scanning` reports](../../user/application_security/cluster_image_scanning/index.md#reports-json-format).
- See this [example secure job definition that also defines the artifact created](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Security/Container-Scanning.gitlab-ci.yml).
- If you need a new kind of scan or report, [create an issue](https://gitlab.com/gitlab-org/gitlab/-/issues/new#)
and add the label `devops::secure`.
diff --git a/doc/integration/elasticsearch.md b/doc/integration/elasticsearch.md
index 7b21aa74e81..47afe7016d9 100644
--- a/doc/integration/elasticsearch.md
+++ b/doc/integration/elasticsearch.md
@@ -208,7 +208,7 @@ The following Elasticsearch settings are available:
| `URL` | The URL of your Elasticsearch instance. Use a comma-separated list to support clustering (for example, `http://host1, https://host2:9200`). If your Elasticsearch instance is password-protected, use the `Username` and `Password` fields described below. Alternatively, use inline credentials such as `http://<username>:<password>@<elastic_host>:9200/`. |
| `Username` | The `username` of your Elasticsearch instance. |
| `Password` | The password of your Elasticsearch instance. |
-| `Number of Elasticsearch shards` | Elasticsearch indexes are split into multiple shards for performance reasons. In general, you should use at least 5 shards, and indexes with tens of millions of documents need to have more shards ([see below](#guidance-on-choosing-optimal-cluster-configuration)). Changes to this value do not take effect until the index is recreated. You can read more about tradeoffs in the [Elasticsearch documentation](https://www.elastic.co/guide/en/elasticsearch/reference/current/scalability.html). |
+| `Number of Elasticsearch shards` | Elasticsearch indices are split into multiple shards for performance reasons. In general, you should use at least 5 shards, and indices with tens of millions of documents need to have more shards ([see below](#guidance-on-choosing-optimal-cluster-configuration)). Changes to this value do not take effect until the index is recreated. You can read more about tradeoffs in the [Elasticsearch documentation](https://www.elastic.co/guide/en/elasticsearch/reference/current/scalability.html). |
| `Number of Elasticsearch replicas` | Each Elasticsearch shard can have a number of replicas. These are a complete copy of the shard, and can provide increased query performance or resilience against hardware failure. Increasing this value increases total disk space required by the index. |
| `Limit the number of namespaces and projects that can be indexed` | Enabling this allows you to select namespaces and projects to index. All other namespaces and projects use database search instead. If you enable this option but do not select any namespaces or projects, none are indexed. [Read more below](#limit-the-number-of-namespaces-and-projects-that-can-be-indexed).
| `Using AWS hosted Elasticsearch with IAM credentials` | Sign your Elasticsearch requests using [AWS IAM authorization](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_access-keys.html), [AWS EC2 Instance Profile Credentials](https://docs.aws.amazon.com/codedeploy/latest/userguide/getting-started-create-iam-instance-profile.html#getting-started-create-iam-instance-profile-cli), or [AWS ECS Tasks Credentials](https://docs.aws.amazon.com/AmazonECS/latest/userguide/task-iam-roles.html). Please refer to [Identity and Access Management in Amazon OpenSearch Service](https://docs.aws.amazon.com/opensearch-service/latest/developerguide/ac.html) for details of AWS hosted OpenSearch domain access policy configuration. |
@@ -284,7 +284,7 @@ To disable the Elasticsearch integration:
1. On the left sidebar, select **Settings > Advanced Search**.
1. Uncheck **Elasticsearch indexing** and **Search with Elasticsearch enabled**.
1. Select **Save changes**.
-1. Optional. Delete the existing indexes:
+1. Optional. Delete the existing indices:
```shell
# Omnibus installations
@@ -467,7 +467,7 @@ version](../update/index.md#upgrading-to-a-new-major-version).
Rake tasks are available to:
- [Build and install](#build-and-install) the indexer.
-- Delete indexes when [disabling Elasticsearch](#disable-advanced-search).
+- Delete indices when [disabling Elasticsearch](#disable-advanced-search).
- Add GitLab data to an index.
The following are some available Rake tasks:
@@ -480,8 +480,8 @@ The following are some available Rake tasks:
| [`sudo gitlab-rake gitlab:elastic:index_projects`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/lib/tasks/gitlab/elastic.rake) | Iterates over all projects, and queues Sidekiq jobs to index them in the background. It can only be used after the index is created. |
| [`sudo gitlab-rake gitlab:elastic:index_projects_status`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/lib/tasks/gitlab/elastic.rake) | Determines the overall status of the indexing. It is done by counting the total number of indexed projects, dividing by a count of the total number of projects, then multiplying by 100. |
| [`sudo gitlab-rake gitlab:elastic:clear_index_status`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/lib/tasks/gitlab/elastic.rake) | Deletes all instances of IndexStatus for all projects. Note that this command results in a complete wipe of the index, and it should be used with caution. |
-| [`sudo gitlab-rake gitlab:elastic:create_empty_index`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/lib/tasks/gitlab/elastic.rake) | Generates empty indexes (the default index and a separate issues index) and assigns an alias for each on the Elasticsearch side only if it doesn't already exist. |
-| [`sudo gitlab-rake gitlab:elastic:delete_index`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/lib/tasks/gitlab/elastic.rake) | Removes the GitLab indexes and aliases (if they exist) on the Elasticsearch instance. |
+| [`sudo gitlab-rake gitlab:elastic:create_empty_index`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/lib/tasks/gitlab/elastic.rake) | Generates empty indices (the default index and a separate issues index) and assigns an alias for each on the Elasticsearch side only if it doesn't already exist. |
+| [`sudo gitlab-rake gitlab:elastic:delete_index`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/lib/tasks/gitlab/elastic.rake) | Removes the GitLab indices and aliases (if they exist) on the Elasticsearch instance. |
| [`sudo gitlab-rake gitlab:elastic:recreate_index`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/lib/tasks/gitlab/elastic.rake) | Wrapper task for `gitlab:elastic:delete_index` and `gitlab:elastic:create_empty_index`. |
| [`sudo gitlab-rake gitlab:elastic:index_snippets`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/lib/tasks/gitlab/elastic.rake) | Performs an Elasticsearch import that indexes the snippets data. |
| [`sudo gitlab-rake gitlab:elastic:projects_not_indexed`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/lib/tasks/gitlab/elastic.rake) | Displays which projects are not indexed. |
@@ -567,7 +567,7 @@ Setup](../administration/reference_architectures/index.md) or creating [extra
Sidekiq processes](../administration/operations/extra_sidekiq_processes.md).
1. [Configure your Elasticsearch host and port](#enable-advanced-search).
-1. Create empty indexes:
+1. Create empty indices:
```shell
# Omnibus installations
@@ -950,7 +950,7 @@ sudo gitlab-rake gitlab:elastic:clear_locked_projects
### `Can't specify parent if no parent field has been configured` error
-If you enabled Elasticsearch before GitLab 8.12 and have not rebuilt indexes, you get
+If you enabled Elasticsearch before GitLab 8.12 and have not rebuilt indices, you get
exceptions in lots of different cases:
```plaintext
@@ -967,7 +967,7 @@ Elasticsearch::Transport::Transport::Errors::BadRequest([400] {
}):
```
-This is because we changed the index mapping in GitLab 8.12 and the old indexes should be removed and built from scratch again,
+This is because we changed the index mapping in GitLab 8.12 and the old indices should be removed and built from scratch again,
see details in the [update guide](../update/upgrading_from_source.md).
### `Elasticsearch::Transport::Transport::Errors::BadRequest`
@@ -1069,7 +1069,7 @@ sudo -u git -H bundle exec rake gitlab:elastic:index
### How does Advanced Search handle private projects?
-Advanced Search stores all the projects in the same Elasticsearch indexes,
+Advanced Search stores all the projects in the same Elasticsearch indices,
however, searches only surface results that can be viewed by the user.
Advanced Search honors all permission checks in the application by
filtering out projects that a user does not have access to at search time.
diff --git a/doc/update/deprecations.md b/doc/update/deprecations.md
index 3f90f540c7a..4ef801feb7a 100644
--- a/doc/update/deprecations.md
+++ b/doc/update/deprecations.md
@@ -49,6 +49,21 @@ sole discretion of GitLab Inc.
<div class="deprecation removal-160 breaking-change">
+### Jira GitHub Enterprise DVCS integration
+
+Planned removal: GitLab <span class="removal-milestone">16.0</span> (2023-05-22)
+
+WARNING:
+This is a [breaking change](https://docs.gitlab.com/ee/development/contributing/#breaking-changes).
+Review the details carefully before upgrading.
+
+The [Jira DVCS Connector](https://docs.gitlab.com/ee/integration/jira/dvcs.html) (which enables the [Jira Development Panel](https://support.atlassian.com/jira-software-cloud/docs/view-development-information-for-an-issue/)), will no longer support Jira Cloud users starting with GitLab 16.0. The [GitLab for Jira App](https://docs.gitlab.com/ee/integration/jira/connect-app.html) has always been recommended for Jira Cloud users, and it will be required instead of the DVCS connector. If you are a Jira Cloud user, we recommended you begin migrating to the GitLab for Jira App.
+Any Jira Server and Jira Data Center users will need to confirm they are not using the GitHub Enterprise Connector to enable the GitLab DVCS integration, but they may continue to use the [native GitLab DVCS integration](https://docs.gitlab.com/ee/integration/jira/dvcs.html) (supported in Jira 8.14 and later).
+
+</div>
+
+<div class="deprecation removal-160 breaking-change">
+
### REST API Runner maintainer_note
Planned removal: GitLab <span class="removal-milestone">16.0</span> (2023-05-22)
diff --git a/doc/user/application_security/cluster_image_scanning/index.md b/doc/user/application_security/cluster_image_scanning/index.md
index aba28a5ca89..e7a59d70b25 100644
--- a/doc/user/application_security/cluster_image_scanning/index.md
+++ b/doc/user/application_security/cluster_image_scanning/index.md
@@ -1,321 +1,11 @@
---
-type: reference, howto
-stage: Protect
-group: Container Security
-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
+redirect_to: '../../clusters/agent/vulnerabilities.md'
+remove_date: '2022-08-19'
---
-# Cluster Image Scanning **(ULTIMATE)**
+This document was moved to [another location](../../clusters/agent/vulnerabilities.md).
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/) in GitLab 14.1.
-
-WARNING:
-This analyzer is in [Alpha](../../../policy/alpha-beta-support.md#alpha-features)
-and is unstable. The JSON report and CI/CD configuration may be subject to change or breakage
-across GitLab releases.
-
-Your Kubernetes cluster may run workloads based on images that the Container Security analyzer
-didn't scan. These images may therefore contain known vulnerabilities. By including an extra job in
-your pipeline that scans for those security risks and displays them in the vulnerability report, you
-can use GitLab to audit your Kubernetes workloads and environments.
-
-GitLab provides integration with open-source tools for vulnerability analysis in Kubernetes clusters:
-
-- [Starboard](https://github.com/aquasecurity/starboard)
-
-To integrate GitLab with security scanners other than those listed here, see
-[Security scanner integration](../../../development/integrations/secure.md).
-
-You can use cluster image scanning through the following methods:
-
-<!--- start_remove The following content will be removed on remove_date: '2022-08-22' -->
-- [The cluster image scanning analyzer](#use-the-cluster-image-scanning-analyzer-removed) ([Removed](https://gitlab.com/gitlab-org/gitlab/-/issues/356465) in GitLab 15.0. Use [the GitLab agent](#cluster-image-scanning-with-the-gitlab-agent) instead.)
-<!--- end_remove -->
-- [The GitLab agent](#cluster-image-scanning-with-the-gitlab-agent)
-
-<!--- start_remove The following content will be removed on remove_date: '2022-08-22' -->
-
-## Use the cluster image scanning analyzer (removed)
-
-This feature was [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/356465) in GitLab 15.0.
-Use [the GitLab agent](#cluster-image-scanning-with-the-gitlab-agent) instead.
-
-You can use the cluster image scanning analyzer to run cluster image scanning with [GitLab CI/CD](../../../ci/index.md).
-To enable the cluster image scanning analyzer, [include the CI job](#configuration)
-in your existing `.gitlab-ci.yml` file.
-
-### Prerequisites
-
-To enable cluster image scanning in your pipeline, you need the following:
-
-- Cluster Image Scanning runs in the `test` stage, which is available by default. If you redefine the stages
- in the `.gitlab-ci.yml` file, the `test` stage is required.
-- [GitLab Runner](https://docs.gitlab.com/runner/)
- with the [`docker`](https://docs.gitlab.com/runner/executors/docker.html)
- or [`kubernetes`](https://docs.gitlab.com/runner/install/kubernetes.html)
- executor on Linux/amd64.
-- Docker `18.09.03` or later installed on the same computer as the runner. If you're using the
- shared runners on GitLab.com, then this is already the case.
-- [Starboard Operator](https://aquasecurity.github.io/starboard/v0.10.3/operator/installation/kubectl/)
- installed and configured in your cluster.
-- The configuration for accessing your Kubernetes cluster stored in the `CIS_KUBECONFIG`
- [configuration variable](#cicd-variables-for-cluster-image-scanning)
- with the type set to `File` (see [Configuring the cluster](#configuring-the-cluster)).
-
-### Configuring the cluster
-
-1. Create a new service account.
-
- To properly fetch vulnerabilities from the cluster and to limit analyzer access to the workload,
- you must create a new service account with the cluster role limited to `get`, `list`, and `watch`
- `vulnerabilityreports` in the Kubernetes cluster:
-
- ```shell
- kubectl apply -f https://gitlab.com/gitlab-org/security-products/analyzers/cluster-image-scanning/-/raw/main/gitlab-vulnerability-viewer-service-account.yaml
- ```
-
-1. Obtain the Kubernetes API URL.
-
- Get the API URL by running this command:
-
- ```shell
- API_URL=$(kubectl cluster-info | grep -E 'Kubernetes master|Kubernetes control plane' | awk '/http/ {print $NF}')
- ```
-
-1. Obtain the CA certificate:
-
- 1. List the secrets with `kubectl get secrets`. One should have a name similar to
- `default-token-xxxxx`. Copy that token name for use below.
-
- 1. Run this command to get the certificate:
-
- ```shell
- CA_CERTIFICATE=$(kubectl get secret <secret name> -o jsonpath="{['data']['ca\.crt']}")
- ```
-
-1. Obtain the service account token:
-
- ```shell
- TOKEN=$(kubectl -n kube-system get secret $(kubectl -n kube-system get secret | grep gitlab-vulnerability-viewer | awk '{print $1}') -o jsonpath="{.data.token}" | base64 --decode)
- ```
-
-1. Generate the value for the `CIS_KUBECONFIG` variable. Copy the printed value from the output:
-
- ```shell
- echo "
- ---
- apiVersion: v1
- kind: Config
- clusters:
- - name: gitlab-vulnerabilities-viewer
- cluster:
- server: $API_URL
- certificate-authority-data: $CA_CERTIFICATE
- contexts:
- - name: gitlab-vulnerabilities-viewer
- context:
- cluster: gitlab-vulnerabilities-viewer
- namespace: default
- user: gitlab-vulnerabilities-viewer
- current-context: gitlab-vulnerabilities-viewer
- users:
- - name: gitlab-vulnerabilities-viewer
- user:
- token: $TOKEN
- "
- ```
-
-1. Set the CI/CD variable:
-
- 1. Navigate to your project's **Settings > CI/CD**.
-
- 1. Expand the **Variables** section.
-
- 1. Select **Add variable** and fill in the details:
-
- - **Key**: `CIS_KUBECONFIG`.
- - **Value**: `generated value`
- - **Type**: `File`
-
-WARNING:
-The `CIS_KUBECONFIG` variable is accessible by all jobs executed for your project. Mark the
-`Protect variable` flag to export this variable to pipelines running on protected branches and tags
-only. You can apply additional protection to your cluster by
-[restricting service account access to a single namespace](https://kubernetes.io/docs/reference/access-authn-authz/rbac/),
-and [configuring Starboard Operator](https://aquasecurity.github.io/starboard/v0.10.3/operator/configuration/#install-modes)
-to install in restricted mode.
-
-### Configuration
-
-To include the `Cluster-Image-Scanning.gitlab-ci.yml` template (GitLab 14.1 and later), add the
-following to your `.gitlab-ci.yml` file:
-
-```yaml
-include:
- - template: Security/Cluster-Image-Scanning.gitlab-ci.yml
-```
-
-The included template:
-
-- Creates a `cluster_image_scanning` job in your CI/CD pipeline.
-- Connects to your Kubernetes cluster with credentials provided in the `CIS_KUBECONFIG` variable and
- fetches vulnerabilities found by [Starboard Operator](https://aquasecurity.github.io/starboard/v0.10.3/operator/).
-
-GitLab saves the results as a
-[Cluster Image Scanning report artifact](../../../ci/yaml/artifacts_reports.md#artifactsreportscluster_image_scanning)
-that you can download and analyze later. When downloading, you always receive the most recent
-artifact.
-
-#### Customize the cluster image scanning settings
-
-You can customize how GitLab scans your cluster. For example, to restrict the analyzer to get
-results for only a certain workload, use the [`variables`](../../../ci/yaml/index.md#variables)
-parameter in your `.gitlab-ci.yml` to set [CI/CD variables](#cicd-variables-for-cluster-image-scanning).
-The variables you set in your `.gitlab-ci.yml` overwrite those in
-`Cluster-Image-Scanning.gitlab-ci.yml`.
-
-##### CI/CD variables for cluster image scanning
-
-You can [configure](#customize-the-cluster-image-scanning-settings) analyzers by using the following CI/CD variables:
-
-| CI/CD Variable | Default | Description |
-| ------------------------------ | ------------- | ----------- |
-| `CIS_KUBECONFIG` | `""` | File used to configure access to the Kubernetes cluster. See the [Kubernetes documentation](https://kubernetes.io/docs/tasks/access-application-cluster/configure-access-multiple-clusters/) for more details. |
-| `CIS_CONTAINER_NAMES` | `""` | A comma-separated list of container names used in the Kubernetes resources you want to filter vulnerabilities for. For example, `alpine,postgres`. |
-| `CIS_RESOURCE_NAMES` | `""` | A comma-separated list of Kubernetes resources you want to filter vulnerabilities for. For example, `nginx,redis`. |
-| `CIS_RESOURCE_NAMESPACES` | `""` | A comma-separated list of namespaces of the Kubernetes resources you want to filter vulnerabilities for. For example, `production,staging`. |
-| `CIS_RESOURCE_KINDS` | `""` | A comma-separated list of the kinds of Kubernetes resources to filter vulnerabilities for. For example, `deployment,pod`. |
-| `CIS_CLUSTER_IDENTIFIER` | `""` | ID of the Kubernetes cluster integrated with GitLab. This is used to map vulnerabilities to the cluster so they can be filtered in the Vulnerability Report page. |
-| `CIS_CLUSTER_AGENT_IDENTIFIER` | `""` | ID of the Kubernetes cluster agent integrated with GitLab. This maps vulnerabilities to the agent so they can be filtered in the Vulnerability Report page. |
-
-#### Override the cluster image scanning template
-
-If you want to override the job definition (for example, to change properties like `variables`), you
-must declare and override a job after the template inclusion, and then
-specify any additional keys.
-
-This example sets `CIS_RESOURCE_NAME` to `nginx`:
-
-```yaml
-include:
- - template: Security/Cluster-Image-Scanning.gitlab-ci.yml
-
-cluster_image_scanning:
- variables:
- CIS_RESOURCE_NAME: nginx
-```
-
-#### Connect with Kubernetes cluster associated to the project
-
-If you want to connect to the Kubernetes cluster associated with the project and run Cluster Image Scanning jobs without
-configuring the `CIS_KUBECONFIG` variable, you must extend `cluster_image_scanning` and specify the environment you want to scan.
-
-This example configures the `cluster_image_scanning` job to scan the Kubernetes cluster connected with the `staging` environment:
-
-```yaml
-cluster_image_scanning:
- environment:
- name: staging
- action: prepare
-```
-
-### Reports JSON format
-
-The cluster image scanning tool emits a JSON report file. For more information, see the
-[schema for this report](https://gitlab.com/gitlab-org/security-products/security-report-schemas/-/blob/master/dist/container-scanning-report-format.json).
-
-Here's an example cluster image scanning report:
-
-```json-doc
-{
- "version": "14.0.2",
- "scan": {
- "scanner": {
- "id": "starboard_trivy",
- "name": "Trivy (using Starboard Operator)",
- "url": "https://github.com/aquasecurity/starboard",
- "vendor": {
- "name": "GitLab"
- },
- "version": "0.16.0"
- },
- "start_time": "2021-04-28T12:47:00Z",
- "end_time": "2021-04-28T12:47:00Z",
- "type": "cluster_image_scanning",
- "status": "success"
- },
- "vulnerabilities": [
- {
- "id": "c15f22205ee842184c2d55f1a207b3708283353f85083d66c34379c709b0ac9d",
- "category": "cluster_image_scanning",
- "message": "CVE-2011-3374 in apt",
- "description": "",
- "cve": "library/nginx:1.18:apt:CVE-2011-3374",
- "severity": "Low",
- "confidence": "Unknown",
- "solution": "Upgrade apt from 1.8.2.2",
- "scanner": {
- "id": "starboard_trivy",
- "name": "Trivy (using Starboard Operator)"
- },
- "location": {
- "dependency": {
- "package": {
- "name": "apt"
- },
- "version": "1.8.2.2"
- },
- "operating_system": "library/nginx:1.18",
- "image": "index.docker.io/library/nginx:1.18"
- },
- "identifiers": [
- {
- "type": "cve",
- "name": "CVE-2011-3374",
- "value": "CVE-2011-3374",
- "url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2011-3374"
- }
- ],
- "links": [
- "https://avd.aquasec.com/nvd/cve-2011-3374"
- ]
- }
- ]
-}
-```
-
-<!--- end_remove -->
-## Cluster image scanning with the GitLab agent
-
-You can use the [GitLab agent](../../clusters/agent/index.md) to
-scan images from within your Kubernetes cluster and record the vulnerabilities in GitLab.
-
-### Prerequisites
-
-- [GitLab agent](../../clusters/agent/install/index.md)
- set up in GitLab, installed in your cluster, and configured using a configuration repository.
-
-### Configuration
-
-The agent runs the cluster image scanning once the `starboard`
-directive is added to your [agent's configuration repository](../../clusters/agent/vulnerabilities.md).
-
-## Security Dashboard
-
-The [Security Dashboard](../security_dashboard/index.md) shows you an overview of all
-the security vulnerabilities in your groups, projects, and pipelines.
-
-## Interacting with the vulnerabilities
-
-After you find a vulnerability, you can address it in the [vulnerability report](../vulnerabilities/index.md)
-or the [GitLab agent's](../../clusters/agent/vulnerabilities.md)
-details section.
-<!--- start_remove The following content will be removed on remove_date: '2022-08-22' -->
-
-## Troubleshooting
-
-### Getting warning message `gl-cluster-image-scanning-report.json: no matching files`
-
-For information on this error, see the [general Application Security troubleshooting section](../../../ci/pipelines/job_artifacts.md#error-message-no-files-to-upload).
-
-<!--- end_remove -->
+<!-- This redirect file can be deleted after <2022-08-19>. -->
+<!-- Redirects that point to other docs in the same project expire in three months. -->
+<!-- Redirects that point to docs in a different project or site (link is not relative and starts with `https:`) expire in one year. -->
+<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->
diff --git a/doc/user/application_security/configuration/index.md b/doc/user/application_security/configuration/index.md
index 61a2121b9c6..09292dcb92b 100644
--- a/doc/user/application_security/configuration/index.md
+++ b/doc/user/application_security/configuration/index.md
@@ -52,8 +52,8 @@ You can configure the following security controls:
- Select **Configure with a merge request** to create a merge request with the changes required to
enable Container Scanning. For more details, see
[Enable Container Scanning through an automatic merge request](../container_scanning/index.md#enable-container-scanning-through-an-automatic-merge-request).
-- [Cluster Image Scanning](../cluster_image_scanning/index.md)
- - Can be configured with `.gitlab-ci.yml`. For more details, read [Cluster Image Scanning](../../../user/application_security/cluster_image_scanning/#configuration).
+- [Operational Container Scanning](../../clusters/agent/vulnerabilities.md)
+ - Can be configured by adding a configuration block to your agent configuration. For more details, read [Operational Container Scanning](../../clusters/agent/vulnerabilities.md#enable-cluster-vulnerability-scanning).
- [Secret Detection](../secret_detection/index.md)
- Select **Configure with a merge request** to create a merge request with the changes required to
enable Secret Detection. For more details, read [Enable Secret Detection via an automatic merge request](../secret_detection/index.md#enable-secret-detection-via-an-automatic-merge-request).
diff --git a/doc/user/application_security/policies/scan-execution-policies.md b/doc/user/application_security/policies/scan-execution-policies.md
index 884b9ad7f0d..5beb6912877 100644
--- a/doc/user/application_security/policies/scan-execution-policies.md
+++ b/doc/user/application_security/policies/scan-execution-policies.md
@@ -152,7 +152,7 @@ Note the following:
mode when executed as part of a scheduled scan.
- A container scanning and cluster image scanning scans configured for the `pipeline` rule type ignores the cluster defined in the `clusters` object.
They use predefined CI/CD variables defined for your project. Cluster selection with the `clusters` object is supported for the `schedule` rule type.
- Cluster with name provided in `clusters` object must be created and configured for the project. To be able to successfully perform the `container_scanning`/`cluster_image_scanning` scans for the cluster you must follow instructions for the [Cluster Image Scanning feature](../cluster_image_scanning/index.md#prerequisites).
+ A cluster with a name provided in the `clusters` object must be created and configured for the project.
- The SAST scan uses the default template and runs in a [child pipeline](../../../ci/pipelines/parent_child_pipelines.md).
## Example security policies project
diff --git a/doc/user/clusters/agent/vulnerabilities.md b/doc/user/clusters/agent/vulnerabilities.md
index 9fc256aa877..a3fe80ecd4b 100644
--- a/doc/user/clusters/agent/vulnerabilities.md
+++ b/doc/user/clusters/agent/vulnerabilities.md
@@ -4,7 +4,7 @@ group: Configure
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
---
-# Container vulnerability scanning **(ULTIMATE)**
+# Operational Container Scanning **(ULTIMATE)**
> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/6346) in GitLab 14.8.
diff --git a/doc/user/packages/terraform_module_registry/index.md b/doc/user/packages/terraform_module_registry/index.md
index a107d06a63c..661b894bda0 100644
--- a/doc/user/packages/terraform_module_registry/index.md
+++ b/doc/user/packages/terraform_module_registry/index.md
@@ -22,11 +22,11 @@ To authenticate to the Terraform module registry, you need either:
When you publish a Terraform Module, if it does not exist, it is created.
-If a package with the same name and version already exists, it will not be created. It does not overwrite the existing package.
-
Prerequisites:
-- You need to [authenticate with the API](../../../api/index.md#authentication). If authenticating with a deploy token, it must be configured with the `write_package_registry` scope.
+- A package with the same name and version must not already exist.
+- Your project and group names must not include a dot (`.`). For example, `source = "gitlab.example.com/my.group/project.name"`.
+- You must [authenticate with the API](../../../api/index.md#authentication). If authenticating with a deploy token, it must be configured with the `write_package_registry` scope.
```plaintext
PUT /projects/:id/packages/terraform/modules/:module-name/:module-system/:module-version/file
@@ -35,8 +35,8 @@ PUT /projects/:id/packages/terraform/modules/:module-name/:module-system/:module
| Attribute | Type | Required | Description |
| -------------------| --------------- | ---------| -------------------------------------------------------------------------------------------------------------------------------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](../../../api/index.md#namespaced-path-encoding). |
-| `module-name` | string | yes | The package name. It can contain only lowercase letters (`a-z`), uppercase letter (`A-Z`), numbers (`0-9`), or hyphens (`-`) and cannot exceed 64 characters.
-| `module-system` | string | yes | The package system. It can contain only lowercase letters (`a-z`) and numbers (`0-9`), and cannot exceed 64 characters. More information can be found in the [Terraform Module Registry Protocol documentation](https://www.terraform.io/internals/module-registry-protocol).
+| `module-name` | string | yes | The package name. **Supported syntax**: One to 64 ASCII characters, including lowercase letters (a-z), digits (0-9), and hyphens (`-`).
+| `module-system` | string | yes | The package system. **Supported syntax**: One to 64 ASCII characters, including lowercase letters (a-z), digits (0-9), and hyphens (`-`). More information can be found in the [Terraform Module Registry Protocol documentation](https://www.terraform.io/internals/module-registry-protocol).
| `module-version` | string | yes | The package version. It must be valid according to the [Semantic Versioning Specification](https://semver.org/).
Provide the file content in the request body.
diff --git a/lib/gitlab/github_import/importer/issue_importer.rb b/lib/gitlab/github_import/importer/issue_importer.rb
index 7f46615f17e..35fd4bd88a0 100644
--- a/lib/gitlab/github_import/importer/issue_importer.rb
+++ b/lib/gitlab/github_import/importer/issue_importer.rb
@@ -31,6 +31,7 @@ module Gitlab
if (issue_id = create_issue)
create_assignees(issue_id)
issuable_finder.cache_database_id(issue_id)
+ update_search_data(issue_id) if Feature.enabled?(:issues_full_text_search)
end
end
end
@@ -77,6 +78,13 @@ module Gitlab
ApplicationRecord.legacy_bulk_insert(IssueAssignee.table_name, assignees) # rubocop:disable Gitlab/BulkInsert
end
+
+ # Adds search data to database (if full_text_search feature is enabled)
+ #
+ # issue_id - The ID of the created issue.
+ def update_search_data(issue_id)
+ project.issues.find(issue_id)&.update_search_data!
+ end
end
end
end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 18ecc8c6c80..ebec4a84cda 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -22096,6 +22096,9 @@ msgstr ""
msgid "Job|triggered"
msgstr ""
+msgid "Join GitLab today! You and your team can plan, build, and ship secure code all in one application. Get started here for free!"
+msgstr ""
+
msgid "Join Zoom meeting"
msgstr ""
diff --git a/spec/frontend/ci_variable_list/components/ci_variable_modal_spec.js b/spec/frontend/ci_variable_list/components/ci_variable_modal_spec.js
index d26378d9382..7ce294ad11b 100644
--- a/spec/frontend/ci_variable_list/components/ci_variable_modal_spec.js
+++ b/spec/frontend/ci_variable_list/components/ci_variable_modal_spec.js
@@ -42,10 +42,7 @@ describe('Ci variable modal', () => {
const findCiEnvironmentsDropdown = () => wrapper.find(CiEnvironmentsDropdown);
const findModal = () => wrapper.find(ModalStub);
- const findAddorUpdateButton = () =>
- findModal()
- .findAll(GlButton)
- .wrappers.find((button) => button.props('variant') === 'confirm');
+ const findAddorUpdateButton = () => findModal().find('[data-testid="ciUpdateOrAddVariableBtn"]');
const deleteVariableButton = () =>
findModal()
.findAll(GlButton)
diff --git a/spec/frontend/content_editor/remark_markdown_processing_spec.js b/spec/frontend/content_editor/remark_markdown_processing_spec.js
index f5cee1b41b9..fce08097f58 100644
--- a/spec/frontend/content_editor/remark_markdown_processing_spec.js
+++ b/spec/frontend/content_editor/remark_markdown_processing_spec.js
@@ -124,7 +124,7 @@ describe('Client side Markdown processing', () => {
sourceMarkdown,
});
- it.each([
+ const examples = [
{
markdown: '__bold text__',
expectedDoc: doc(
@@ -244,6 +244,40 @@ describe('Client side Markdown processing', () => {
),
},
{
+ markdown: `
+
+<img src="bar" alt="foo" />
+
+ `,
+ expectedDoc: doc(
+ paragraph(
+ sourceAttrs('0:27', '<img src="bar" alt="foo" />'),
+ image({ ...sourceAttrs('0:27', '<img src="bar" alt="foo" />'), alt: 'foo', src: 'bar' }),
+ ),
+ ),
+ },
+ {
+ markdown: `
+- List item 1
+
+<img src="bar" alt="foo" />
+
+ `,
+ expectedDoc: doc(
+ bulletList(
+ sourceAttrs('0:13', '- List item 1'),
+ listItem(
+ sourceAttrs('0:13', '- List item 1'),
+ paragraph(sourceAttrs('2:13', 'List item 1'), 'List item 1'),
+ ),
+ ),
+ paragraph(
+ sourceAttrs('15:42', '<img src="bar" alt="foo" />'),
+ image({ ...sourceAttrs('15:42', '<img src="bar" alt="foo" />'), alt: 'foo', src: 'bar' }),
+ ),
+ ),
+ },
+ {
markdown: '[GitLab](https://gitlab.com "Go to GitLab")',
expectedDoc: doc(
paragraph(
@@ -381,11 +415,11 @@ two
sourceAttrs('0:27', '- List item 1\n- List item 2'),
listItem(
sourceAttrs('0:13', '- List item 1'),
- paragraph(sourceAttrs('0:13', '- List item 1'), 'List item 1'),
+ paragraph(sourceAttrs('2:13', 'List item 1'), 'List item 1'),
),
listItem(
sourceAttrs('14:27', '- List item 2'),
- paragraph(sourceAttrs('14:27', '- List item 2'), 'List item 2'),
+ paragraph(sourceAttrs('16:27', 'List item 2'), 'List item 2'),
),
),
),
@@ -400,11 +434,11 @@ two
sourceAttrs('0:27', '* List item 1\n* List item 2'),
listItem(
sourceAttrs('0:13', '* List item 1'),
- paragraph(sourceAttrs('0:13', '* List item 1'), 'List item 1'),
+ paragraph(sourceAttrs('2:13', 'List item 1'), 'List item 1'),
),
listItem(
sourceAttrs('14:27', '* List item 2'),
- paragraph(sourceAttrs('14:27', '* List item 2'), 'List item 2'),
+ paragraph(sourceAttrs('16:27', 'List item 2'), 'List item 2'),
),
),
),
@@ -419,11 +453,11 @@ two
sourceAttrs('0:27', '+ List item 1\n+ List item 2'),
listItem(
sourceAttrs('0:13', '+ List item 1'),
- paragraph(sourceAttrs('0:13', '+ List item 1'), 'List item 1'),
+ paragraph(sourceAttrs('2:13', 'List item 1'), 'List item 1'),
),
listItem(
sourceAttrs('14:27', '+ List item 2'),
- paragraph(sourceAttrs('14:27', '+ List item 2'), 'List item 2'),
+ paragraph(sourceAttrs('16:27', 'List item 2'), 'List item 2'),
),
),
),
@@ -438,11 +472,11 @@ two
sourceAttrs('0:29', '1. List item 1\n1. List item 2'),
listItem(
sourceAttrs('0:14', '1. List item 1'),
- paragraph(sourceAttrs('0:14', '1. List item 1'), 'List item 1'),
+ paragraph(sourceAttrs('3:14', 'List item 1'), 'List item 1'),
),
listItem(
sourceAttrs('15:29', '1. List item 2'),
- paragraph(sourceAttrs('15:29', '1. List item 2'), 'List item 2'),
+ paragraph(sourceAttrs('18:29', 'List item 2'), 'List item 2'),
),
),
),
@@ -457,11 +491,11 @@ two
sourceAttrs('0:29', '1. List item 1\n2. List item 2'),
listItem(
sourceAttrs('0:14', '1. List item 1'),
- paragraph(sourceAttrs('0:14', '1. List item 1'), 'List item 1'),
+ paragraph(sourceAttrs('3:14', 'List item 1'), 'List item 1'),
),
listItem(
sourceAttrs('15:29', '2. List item 2'),
- paragraph(sourceAttrs('15:29', '2. List item 2'), 'List item 2'),
+ paragraph(sourceAttrs('18:29', 'List item 2'), 'List item 2'),
),
),
),
@@ -476,11 +510,11 @@ two
sourceAttrs('0:29', '1) List item 1\n2) List item 2'),
listItem(
sourceAttrs('0:14', '1) List item 1'),
- paragraph(sourceAttrs('0:14', '1) List item 1'), 'List item 1'),
+ paragraph(sourceAttrs('3:14', 'List item 1'), 'List item 1'),
),
listItem(
sourceAttrs('15:29', '2) List item 2'),
- paragraph(sourceAttrs('15:29', '2) List item 2'), 'List item 2'),
+ paragraph(sourceAttrs('18:29', 'List item 2'), 'List item 2'),
),
),
),
@@ -495,12 +529,12 @@ two
sourceAttrs('0:33', '- List item 1\n - Sub list item 1'),
listItem(
sourceAttrs('0:33', '- List item 1\n - Sub list item 1'),
- paragraph(sourceAttrs('0:33', '- List item 1\n - Sub list item 1'), 'List item 1'),
+ paragraph(sourceAttrs('2:13', 'List item 1'), 'List item 1'),
bulletList(
sourceAttrs('16:33', '- Sub list item 1'),
listItem(
sourceAttrs('16:33', '- Sub list item 1'),
- paragraph(sourceAttrs('16:33', '- Sub list item 1'), 'Sub list item 1'),
+ paragraph(sourceAttrs('18:33', 'Sub list item 1'), 'Sub list item 1'),
),
),
),
@@ -534,6 +568,24 @@ two
},
{
markdown: `
+- List item with an image ![bar](foo.png)
+`,
+ expectedDoc: doc(
+ bulletList(
+ sourceAttrs('0:41', '- List item with an image ![bar](foo.png)'),
+ listItem(
+ sourceAttrs('0:41', '- List item with an image ![bar](foo.png)'),
+ paragraph(
+ sourceAttrs('2:41', 'List item with an image ![bar](foo.png)'),
+ 'List item with an image',
+ image({ ...sourceAttrs('26:41', '![bar](foo.png)'), alt: 'bar', src: 'foo.png' }),
+ ),
+ ),
+ ),
+ ),
+ },
+ {
+ markdown: `
> This is a blockquote
`,
expectedDoc: doc(
@@ -555,11 +607,11 @@ two
sourceAttrs('2:31', '- List item 1\n> - List item 2'),
listItem(
sourceAttrs('2:15', '- List item 1'),
- paragraph(sourceAttrs('2:15', '- List item 1'), 'List item 1'),
+ paragraph(sourceAttrs('4:15', 'List item 1'), 'List item 1'),
),
listItem(
sourceAttrs('18:31', '- List item 2'),
- paragraph(sourceAttrs('18:31', '- List item 2'), 'List item 2'),
+ paragraph(sourceAttrs('20:31', 'List item 2'), 'List item 2'),
),
),
),
@@ -707,14 +759,14 @@ const fn = () => 'GitLab';
checked: false,
...sourceAttrs('0:22', '- [ ] task list item 1'),
},
- paragraph(sourceAttrs('0:22', '- [ ] task list item 1'), 'task list item 1'),
+ paragraph(sourceAttrs('6:22', 'task list item 1'), 'task list item 1'),
),
taskItem(
{
checked: false,
...sourceAttrs('23:45', '- [ ] task list item 2'),
},
- paragraph(sourceAttrs('23:45', '- [ ] task list item 2'), 'task list item 2'),
+ paragraph(sourceAttrs('29:45', 'task list item 2'), 'task list item 2'),
),
),
),
@@ -735,14 +787,14 @@ const fn = () => 'GitLab';
checked: true,
...sourceAttrs('0:22', '- [x] task list item 1'),
},
- paragraph(sourceAttrs('0:22', '- [x] task list item 1'), 'task list item 1'),
+ paragraph(sourceAttrs('6:22', 'task list item 1'), 'task list item 1'),
),
taskItem(
{
checked: true,
...sourceAttrs('23:45', '- [x] task list item 2'),
},
- paragraph(sourceAttrs('23:45', '- [x] task list item 2'), 'task list item 2'),
+ paragraph(sourceAttrs('29:45', 'task list item 2'), 'task list item 2'),
),
),
),
@@ -763,14 +815,14 @@ const fn = () => 'GitLab';
checked: false,
...sourceAttrs('0:23', '1. [ ] task list item 1'),
},
- paragraph(sourceAttrs('0:23', '1. [ ] task list item 1'), 'task list item 1'),
+ paragraph(sourceAttrs('7:23', 'task list item 1'), 'task list item 1'),
),
taskItem(
{
checked: false,
...sourceAttrs('24:47', '2. [ ] task list item 2'),
},
- paragraph(sourceAttrs('24:47', '2. [ ] task list item 2'), 'task list item 2'),
+ paragraph(sourceAttrs('31:47', 'task list item 2'), 'task list item 2'),
),
),
),
@@ -786,13 +838,13 @@ const fn = () => 'GitLab';
sourceAttrs('0:29', '| a | b |\n|---|---|\n| c | d |'),
tableRow(
sourceAttrs('0:9', '| a | b |'),
- tableHeader(sourceAttrs('0:5', '| a |'), paragraph(sourceAttrs('0:5', '| a |'), 'a')),
- tableHeader(sourceAttrs('5:9', ' b |'), paragraph(sourceAttrs('5:9', ' b |'), 'b')),
+ tableHeader(sourceAttrs('0:5', '| a |'), paragraph(sourceAttrs('2:3', 'a'), 'a')),
+ tableHeader(sourceAttrs('5:9', ' b |'), paragraph(sourceAttrs('6:7', 'b'), 'b')),
),
tableRow(
sourceAttrs('20:29', '| c | d |'),
- tableCell(sourceAttrs('20:25', '| c |'), paragraph(sourceAttrs('20:25', '| c |'), 'c')),
- tableCell(sourceAttrs('25:29', ' d |'), paragraph(sourceAttrs('25:29', ' d |'), 'd')),
+ tableCell(sourceAttrs('20:25', '| c |'), paragraph(sourceAttrs('22:23', 'c'), 'c')),
+ tableCell(sourceAttrs('25:29', ' d |'), paragraph(sourceAttrs('26:27', 'd'), 'd')),
),
),
),
@@ -822,7 +874,7 @@ const fn = () => 'GitLab';
colspan: 2,
rowspan: 5,
},
- paragraph(sourceAttrs('19:58', '<th colspan="2" rowspan="5">Header</th>'), 'Header'),
+ paragraph(sourceAttrs('47:53', 'Header'), 'Header'),
),
),
tableRow(
@@ -833,13 +885,18 @@ const fn = () => 'GitLab';
colspan: 2,
rowspan: 5,
},
- paragraph(sourceAttrs('78:115', '<td colspan="2" rowspan="5">Body</td>'), 'Body'),
+ paragraph(sourceAttrs('106:110', 'Body'), 'Body'),
),
),
),
),
},
- ])('processes %s correctly', async ({ markdown, expectedDoc }) => {
+ ];
+
+ const runOnly = examples.find((example) => example.only === true);
+ const runExamples = runOnly ? [runOnly] : examples;
+
+ it.each(runExamples)('processes %s correctly', async ({ markdown, expectedDoc }) => {
const trimmed = markdown.trim();
const document = await deserialize(trimmed);
diff --git a/spec/frontend/groups/components/item_caret_spec.js b/spec/frontend/groups/components/item_caret_spec.js
index cbe1f21d6e2..4bf92bb5642 100644
--- a/spec/frontend/groups/components/item_caret_spec.js
+++ b/spec/frontend/groups/components/item_caret_spec.js
@@ -35,8 +35,8 @@ describe('ItemCaret', () => {
it.each`
isGroupOpen | icon
- ${true} | ${'angle-down'}
- ${false} | ${'angle-right'}
+ ${true} | ${'chevron-down'}
+ ${false} | ${'chevron-right'}
`('renders "$icon" icon when `isGroupOpen` is $isGroupOpen', ({ isGroupOpen, icon }) => {
createComponent({
isGroupOpen,
diff --git a/spec/frontend/ide/components/jobs/detail/description_spec.js b/spec/frontend/ide/components/jobs/detail/description_spec.js
index 786a7661d97..128ccff6568 100644
--- a/spec/frontend/ide/components/jobs/detail/description_spec.js
+++ b/spec/frontend/ide/components/jobs/detail/description_spec.js
@@ -28,6 +28,12 @@ describe('IDE job description', () => {
).not.toBe(null);
});
+ it('renders a borderless CI icon', () => {
+ expect(
+ vm.$el.querySelector('.borderless [data-testid="status_success_borderless-icon"]'),
+ ).not.toBe(null);
+ });
+
it('renders bridge job details without the job link', () => {
vm = mountComponent(Component, {
job: { ...jobs[0], path: undefined },
diff --git a/spec/frontend/issues/list/components/issues_list_app_spec.js b/spec/frontend/issues/list/components/issues_list_app_spec.js
index 934178cda0e..359a62c7de7 100644
--- a/spec/frontend/issues/list/components/issues_list_app_spec.js
+++ b/spec/frontend/issues/list/components/issues_list_app_spec.js
@@ -104,6 +104,9 @@ describe('CE IssuesListApp component', () => {
defaultQueryResponse.data.project.issues.nodes[0].weight = 5;
}
+ const mockIssuesQueryResponse = jest.fn().mockResolvedValue(defaultQueryResponse);
+ const mockIssuesCountsQueryResponse = jest.fn().mockResolvedValue(getIssuesCountsQueryResponse);
+
const findCsvImportExportButtons = () => wrapper.findComponent(CsvImportExportButtons);
const findIssuableByEmail = () => wrapper.findComponent(IssuableByEmail);
const findGlButton = () => wrapper.findComponent(GlButton);
@@ -117,8 +120,8 @@ describe('CE IssuesListApp component', () => {
const mountComponent = ({
provide = {},
data = {},
- issuesQueryResponse = jest.fn().mockResolvedValue(defaultQueryResponse),
- issuesCountsQueryResponse = jest.fn().mockResolvedValue(getIssuesCountsQueryResponse),
+ issuesQueryResponse = mockIssuesQueryResponse,
+ issuesCountsQueryResponse = mockIssuesCountsQueryResponse,
sortPreferenceMutationResponse = jest.fn().mockResolvedValue(setSortPreferenceMutationResponse),
stubs = {},
mountFn = shallowMount,
@@ -160,6 +163,22 @@ describe('CE IssuesListApp component', () => {
return waitForPromises();
});
+ it('queries list with types `ISSUE` and `INCIDENT', () => {
+ const expectedTypes = ['ISSUE', 'INCIDENT', 'TEST_CASE'];
+
+ expect(mockIssuesQueryResponse).toHaveBeenCalledWith(
+ expect.objectContaining({
+ types: expectedTypes,
+ }),
+ );
+
+ expect(mockIssuesCountsQueryResponse).toHaveBeenCalledWith(
+ expect.objectContaining({
+ types: expectedTypes,
+ }),
+ );
+ });
+
it('renders', () => {
expect(findIssuableList().props()).toMatchObject({
namespace: defaultProvide.fullPath,
diff --git a/spec/frontend/pipelines/components/pipelines_list/pipeline_stage_spec.js b/spec/frontend/pipelines/components/pipelines_list/pipeline_stage_spec.js
index fe9b40e91c9..e57dd3508eb 100644
--- a/spec/frontend/pipelines/components/pipelines_list/pipeline_stage_spec.js
+++ b/spec/frontend/pipelines/components/pipelines_list/pipeline_stage_spec.js
@@ -105,6 +105,17 @@ describe('Pipelines stage component', () => {
expect(findDropdownToggle().exists()).toBe(true);
expect(findCiIcon().exists()).toBe(true);
});
+
+ it('should render a borderless ci-icon', () => {
+ expect(findCiIcon().exists()).toBe(true);
+ expect(findCiIcon().props('isBorderless')).toBe(true);
+ expect(findCiIcon().classes('borderless')).toBe(true);
+ });
+
+ it('should render a ci-icon with a custom border class', () => {
+ expect(findCiIcon().exists()).toBe(true);
+ expect(findCiIcon().classes('gl-border')).toBe(true);
+ });
});
describe('when update dropdown is changed', () => {
diff --git a/spec/frontend/terraform/components/states_table_actions_spec.js b/spec/frontend/terraform/components/states_table_actions_spec.js
index d01f6af9023..40b7448d78d 100644
--- a/spec/frontend/terraform/components/states_table_actions_spec.js
+++ b/spec/frontend/terraform/components/states_table_actions_spec.js
@@ -69,6 +69,7 @@ describe('StatesTableActions', () => {
wrapper = shallowMount(StateActions, {
apolloProvider,
propsData,
+ provide: { projectPath: 'path/to/project' },
mocks: { $toast: { show: toast } },
stubs: { GlDropdown, GlModal, GlSprintf },
});
diff --git a/spec/frontend/terraform/components/states_table_spec.js b/spec/frontend/terraform/components/states_table_spec.js
index 3821b7beb5f..16ffd2b7013 100644
--- a/spec/frontend/terraform/components/states_table_spec.js
+++ b/spec/frontend/terraform/components/states_table_spec.js
@@ -125,6 +125,7 @@ describe('StatesTable', () => {
wrapper = extendedWrapper(
mount(StatesTable, {
propsData,
+ provide: { projectPath: 'path/to/project' },
directives: {
GlTooltip: createMockDirective(),
},
diff --git a/spec/frontend/terraform/components/terraform_list_spec.js b/spec/frontend/terraform/components/terraform_list_spec.js
index c8b4cd564d9..cfd82768098 100644
--- a/spec/frontend/terraform/components/terraform_list_spec.js
+++ b/spec/frontend/terraform/components/terraform_list_spec.js
@@ -16,6 +16,9 @@ describe('TerraformList', () => {
const propsData = {
emptyStateImage: '/path/to/image',
+ };
+
+ const provide = {
projectPath: 'path/to/project',
};
@@ -47,6 +50,7 @@ describe('TerraformList', () => {
wrapper = shallowMount(TerraformList, {
apolloProvider,
propsData,
+ provide,
stubs: {
GlTab,
},
diff --git a/spec/lib/gitlab/github_import/importer/issue_importer_spec.rb b/spec/lib/gitlab/github_import/importer/issue_importer_spec.rb
index 4287c32b947..2a06983417d 100644
--- a/spec/lib/gitlab/github_import/importer/issue_importer_spec.rb
+++ b/spec/lib/gitlab/github_import/importer/issue_importer_spec.rb
@@ -55,20 +55,54 @@ RSpec.describe Gitlab::GithubImport::Importer::IssueImporter, :clean_gitlab_redi
describe '#execute' do
let(:importer) { described_class.new(issue, project, client) }
- it 'creates the issue and assignees' do
- expect(importer)
- .to receive(:create_issue)
- .and_return(10)
+ context 'when :issues_full_test_search is disabled' do
+ before do
+ stub_feature_flags(issues_full_text_search: false)
+ end
+
+ it 'creates the issue and assignees but does not update search data' do
+ expect(importer)
+ .to receive(:create_issue)
+ .and_return(10)
+
+ expect(importer)
+ .to receive(:create_assignees)
+ .with(10)
+
+ expect(importer.issuable_finder)
+ .to receive(:cache_database_id)
+ .with(10)
+
+ expect(importer).not_to receive(:update_search_data)
+
+ importer.execute
+ end
+ end
- expect(importer)
- .to receive(:create_assignees)
- .with(10)
+ context 'when :issues_full_text_search feature is enabled' do
+ before do
+ stub_feature_flags(issues_full_text_search: true)
+ end
- expect(importer.issuable_finder)
- .to receive(:cache_database_id)
- .with(10)
+ it 'creates the issue and assignees and updates_search_data' do
+ expect(importer)
+ .to receive(:create_issue)
+ .and_return(10)
+
+ expect(importer)
+ .to receive(:create_assignees)
+ .with(10)
- importer.execute
+ expect(importer.issuable_finder)
+ .to receive(:cache_database_id)
+ .with(10)
+
+ expect(importer)
+ .to receive(:update_search_data)
+ .with(10)
+
+ importer.execute
+ end
end
end
diff --git a/spec/models/ci/runner_spec.rb b/spec/models/ci/runner_spec.rb
index 8a1dcbfbdeb..74d8b012b29 100644
--- a/spec/models/ci/runner_spec.rb
+++ b/spec/models/ci/runner_spec.rb
@@ -1002,8 +1002,11 @@ RSpec.describe Ci::Runner do
describe '#heartbeat' do
let(:runner) { create(:ci_runner, :project) }
let(:executor) { 'shell' }
+ let(:version) { '15.0.1' }
- subject { runner.heartbeat(architecture: '18-bit', config: { gpus: "all" }, executor: executor) }
+ subject(:heartbeat) do
+ runner.heartbeat(architecture: '18-bit', config: { gpus: "all" }, executor: executor, version: version)
+ end
context 'when database was updated recently' do
before do
@@ -1013,7 +1016,7 @@ RSpec.describe Ci::Runner do
it 'updates cache' do
expect_redis_update
- subject
+ heartbeat
end
end
@@ -1047,7 +1050,7 @@ RSpec.describe Ci::Runner do
it 'updates with expected executor type' do
expect_redis_update
- subject
+ heartbeat
expect(runner.reload.read_attribute(:executor_type)).to eq(expected_executor_type)
end
@@ -1059,6 +1062,18 @@ RSpec.describe Ci::Runner do
end
end
end
+
+ context 'with updated version' do
+ before do
+ runner.version = '1.2.3'
+ end
+
+ it 'updates version components with new version' do
+ heartbeat
+
+ expect(runner.reload.read_attribute(:semver)).to eq '15.0.1'
+ end
+ end
end
def expect_redis_update
@@ -1069,10 +1084,11 @@ RSpec.describe Ci::Runner do
end
def does_db_update
- expect { subject }.to change { runner.reload.read_attribute(:contacted_at) }
+ expect { heartbeat }.to change { runner.reload.read_attribute(:contacted_at) }
.and change { runner.reload.read_attribute(:architecture) }
.and change { runner.reload.read_attribute(:config) }
.and change { runner.reload.read_attribute(:executor_type) }
+ .and change { runner.reload.read_attribute(:semver) }
end
end
@@ -1683,4 +1699,42 @@ RSpec.describe Ci::Runner do
end
end
end
+
+ describe '.save' do
+ context 'with initial value' do
+ let(:runner) { create(:ci_runner, version: 'v1.2.3') }
+
+ it 'updates semver column' do
+ expect(runner.semver).to eq '1.2.3'
+ end
+ end
+
+ context 'with no initial version value' do
+ let(:runner) { build(:ci_runner) }
+
+ context 'with version change' do
+ subject(:update_version) { runner.update!(version: new_version) }
+
+ context 'to invalid version' do
+ let(:new_version) { 'invalid version' }
+
+ it 'updates semver column to nil' do
+ update_version
+
+ expect(runner.reload.semver).to be_nil
+ end
+ end
+
+ context 'to v14.10.1' do
+ let(:new_version) { 'v14.10.1' }
+
+ it 'updates semver column' do
+ update_version
+
+ expect(runner.reload.semver).to eq '14.10.1'
+ end
+ end
+ end
+ end
+ end
end