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>2023-09-13 03:11:34 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-09-13 03:11:34 +0300
commitec808a3c7020a1f487499314fc4d9942ea188ec4 (patch)
treebed36c31e8dccc4c0b1ac1c0927ec188a84e9d59
parenta60e53c7671c299432f0c255ffaf0e0c9fa9eeab (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--.gitlab/ci/qa-common/rules.gitlab-ci.yml2
-rw-r--r--app/assets/javascripts/boards/components/board_card_inner.vue2
-rw-r--r--app/assets/javascripts/boards/components/issue_board_filtered_search.vue5
-rw-r--r--app/assets/javascripts/boards/issue_board_filters.js21
-rw-r--r--app/assets/javascripts/issues/list/components/issues_list_app.vue12
-rw-r--r--app/assets/javascripts/issues/list/queries/search_milestones.query.graphql11
-rw-r--r--app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/milestone_token.vue21
-rw-r--r--app/assets/javascripts/vue_shared/issuable/list/components/issuable_item.vue1
-rw-r--r--app/assets/javascripts/vue_shared/issuable/show/components/issuable_header.vue3
-rw-r--r--app/assets/javascripts/work_items/components/work_item_created_updated.vue2
-rw-r--r--app/assets/javascripts/work_items/components/work_item_type_icon.vue2
-rw-r--r--config/feature_flags/development/merge_trains_create_ref_service.yml2
-rw-r--r--doc/administration/settings/instance_template_repository.md3
-rw-r--r--doc/api/api_resources.md1
-rw-r--r--doc/api/dependency_list_export.md149
-rw-r--r--doc/development/code_suggestions/index.md18
-rw-r--r--doc/development/database/multiple_databases.md92
-rw-r--r--doc/tutorials/export_sbom.md95
-rw-r--r--doc/tutorials/secure_application.md1
-rw-r--r--doc/user/application_security/dependency_list/index.md6
-rw-r--r--doc/user/clusters/agent/ci_cd_workflow.md10
-rw-r--r--doc/user/clusters/agent/install/index.md2
-rw-r--r--doc/user/group/custom_project_templates.md29
-rw-r--r--locale/gitlab.pot17
-rw-r--r--spec/frontend/boards/components/issue_board_filtered_search_spec.js7
-rw-r--r--spec/frontend/boards/mock_data.js5
-rw-r--r--spec/frontend/vue_shared/components/filtered_search_bar/mock_data.js16
-rw-r--r--spec/frontend/vue_shared/components/filtered_search_bar/tokens/milestone_token_spec.js45
-rw-r--r--spec/frontend/vue_shared/issuable/show/components/issuable_header_spec.js2
29 files changed, 509 insertions, 73 deletions
diff --git a/.gitlab/ci/qa-common/rules.gitlab-ci.yml b/.gitlab/ci/qa-common/rules.gitlab-ci.yml
index c0a4e8d206f..c593ec4ccfb 100644
--- a/.gitlab/ci/qa-common/rules.gitlab-ci.yml
+++ b/.gitlab/ci/qa-common/rules.gitlab-ci.yml
@@ -45,7 +45,7 @@
# If Schedule pipeline
.if-schedule-pipeline: &if-schedule-pipeline
- if: '$CI_PIPELINE_SOURCE == "schedule"'
+ if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $SCHEDULE_TYPE == "maintenance"'
# Selective test execution against omnibus instance have following execution scenarios:
# * only e2e spec files changed - runs only changed specs
diff --git a/app/assets/javascripts/boards/components/board_card_inner.vue b/app/assets/javascripts/boards/components/board_card_inner.vue
index 692ca6bf59b..2b38f5735d4 100644
--- a/app/assets/javascripts/boards/components/board_card_inner.vue
+++ b/app/assets/javascripts/boards/components/board_card_inner.vue
@@ -288,7 +288,7 @@ export default {
<gl-loading-icon v-if="isLoading" size="lg" class="gl-mt-5" />
<span
v-if="item.referencePath && !isLoading"
- class="board-card-number gl-overflow-hidden gl-display-flex gl-mr-3 gl-mt-3 gl-font-sm gl-text-secondary"
+ class="board-card-number gl-overflow-hidden gl-display-flex gl-gap-2 gl-mr-3 gl-mt-3 gl-font-sm gl-text-secondary"
:class="{ 'gl-font-base': isEpicBoard }"
>
<work-item-type-icon
diff --git a/app/assets/javascripts/boards/components/issue_board_filtered_search.vue b/app/assets/javascripts/boards/components/issue_board_filtered_search.vue
index f60f00be368..a7b3f5536a4 100644
--- a/app/assets/javascripts/boards/components/issue_board_filtered_search.vue
+++ b/app/assets/javascripts/boards/components/issue_board_filtered_search.vue
@@ -62,7 +62,7 @@ export default {
tokensCE() {
const { issue, incident } = this.$options.i18n;
const { types } = this.$options;
- const { fetchUsers, fetchLabels, fetchMilestones } = issueBoardFilters(
+ const { fetchUsers, fetchLabels } = issueBoardFilters(
this.$apollo,
this.fullPath,
this.isGroupBoard,
@@ -148,7 +148,8 @@ export default {
token: MilestoneToken,
unique: true,
shouldSkipSort: true,
- fetchMilestones,
+ isProject: !this.isGroupBoard,
+ fullPath: this.fullPath,
},
{
icon: 'issues',
diff --git a/app/assets/javascripts/boards/issue_board_filters.js b/app/assets/javascripts/boards/issue_board_filters.js
index 8a487822198..ba5da70c6ec 100644
--- a/app/assets/javascripts/boards/issue_board_filters.js
+++ b/app/assets/javascripts/boards/issue_board_filters.js
@@ -1,7 +1,5 @@
import { BoardType } from 'ee_else_ce/boards/constants';
import usersAutocompleteQuery from '~/graphql_shared/queries/users_autocomplete.query.graphql';
-import groupBoardMilestonesQuery from './graphql/group_board_milestones.query.graphql';
-import projectBoardMilestonesQuery from './graphql/project_board_milestones.query.graphql';
import boardLabels from './graphql/board_labels.query.graphql';
export default function issueBoardFilters(apollo, fullPath, isGroupBoard) {
@@ -34,27 +32,8 @@ export default function issueBoardFilters(apollo, fullPath, isGroupBoard) {
.then(transformLabels);
};
- const fetchMilestones = (searchTerm) => {
- const variables = {
- fullPath,
- searchTerm,
- };
-
- const query = isGroupBoard ? groupBoardMilestonesQuery : projectBoardMilestonesQuery;
-
- return apollo
- .query({
- query,
- variables,
- })
- .then(({ data }) => {
- return data.workspace?.milestones.nodes;
- });
- };
-
return {
fetchLabels,
fetchUsers,
- fetchMilestones,
};
}
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 8a8895e55a9..3d8ed3af816 100644
--- a/app/assets/javascripts/issues/list/components/issues_list_app.vue
+++ b/app/assets/javascripts/issues/list/components/issues_list_app.vue
@@ -99,7 +99,6 @@ import {
import eventHub from '../eventhub';
import reorderIssuesMutation from '../queries/reorder_issues.mutation.graphql';
import searchLabelsQuery from '../queries/search_labels.query.graphql';
-import searchMilestonesQuery from '../queries/search_milestones.query.graphql';
import setSortPreferenceMutation from '../queries/set_sort_preference.mutation.graphql';
import {
convertToApiParams,
@@ -405,9 +404,10 @@ export default {
title: TOKEN_TITLE_MILESTONE,
icon: 'clock',
token: MilestoneToken,
- fetchMilestones: this.fetchMilestones,
recentSuggestionsStorageKey: `${this.fullPath}-issues-recent-tokens-milestone`,
shouldSkipSort: true,
+ fullPath: this.fullPath,
+ isProject: this.isProject,
},
{
type: TOKEN_TYPE_LABEL,
@@ -634,14 +634,6 @@ export default {
fetchLatestLabels(search) {
return this.fetchLabelsWithFetchPolicy(search, fetchPolicies.NETWORK_ONLY);
},
- fetchMilestones(search) {
- return this.$apollo
- .query({
- query: searchMilestonesQuery,
- variables: { fullPath: this.fullPath, search, isProject: this.isProject },
- })
- .then(({ data }) => data[this.namespace]?.milestones.nodes);
- },
fetchUsers(search) {
return this.$apollo
.query({
diff --git a/app/assets/javascripts/issues/list/queries/search_milestones.query.graphql b/app/assets/javascripts/issues/list/queries/search_milestones.query.graphql
index 040240cde99..941e71b7ca7 100644
--- a/app/assets/javascripts/issues/list/queries/search_milestones.query.graphql
+++ b/app/assets/javascripts/issues/list/queries/search_milestones.query.graphql
@@ -1,6 +1,11 @@
#import "./milestone.fragment.graphql"
-query searchMilestones($fullPath: ID!, $search: String, $isProject: Boolean = false) {
+query searchMilestones(
+ $fullPath: ID!
+ $search: String
+ $isProject: Boolean = false
+ $state: MilestoneStateEnum
+) {
group(fullPath: $fullPath) @skip(if: $isProject) {
id
milestones(
@@ -8,7 +13,7 @@ query searchMilestones($fullPath: ID!, $search: String, $isProject: Boolean = fa
includeAncestors: true
includeDescendants: true
sort: EXPIRED_LAST_DUE_DATE_ASC
- state: active
+ state: $state
) {
nodes {
...Milestone
@@ -21,7 +26,7 @@ query searchMilestones($fullPath: ID!, $search: String, $isProject: Boolean = fa
searchTitle: $search
includeAncestors: true
sort: EXPIRED_LAST_DUE_DATE_ASC
- state: active
+ state: $state
) {
nodes {
...Milestone
diff --git a/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/milestone_token.vue b/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/milestone_token.vue
index 8322fe92de4..77108ad3628 100644
--- a/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/milestone_token.vue
+++ b/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/milestone_token.vue
@@ -2,6 +2,8 @@
import { GlFilteredSearchSuggestion } from '@gitlab/ui';
import { createAlert } from '~/alert';
import { __ } from '~/locale';
+import { WORKSPACE_GROUP, WORKSPACE_PROJECT } from '~/issues/constants';
+import searchMilestonesQuery from '~/issues/list/queries/search_milestones.query.graphql';
import { sortMilestonesByDueDate } from '~/milestones/utils';
import BaseToken from '~/vue_shared/components/filtered_search_bar/tokens/base_token.vue';
import { stripQuotes } from '~/lib/utils/text_utility';
@@ -36,6 +38,14 @@ export default {
defaultMilestones() {
return this.config.defaultMilestones || DEFAULT_MILESTONES;
},
+ namespace() {
+ return this.config.isProject ? WORKSPACE_PROJECT : WORKSPACE_GROUP;
+ },
+ fetchMilestonesQuery() {
+ return this.config.fetchMilestones
+ ? this.config.fetchMilestones
+ : this.fetchMilestonesBySearchTerm;
+ },
},
methods: {
getActiveMilestone(milestones, data) {
@@ -51,10 +61,17 @@ export default {
) || this.defaultMilestones.find(({ value }) => value === data)
);
},
+ fetchMilestonesBySearchTerm(search) {
+ return this.$apollo
+ .query({
+ query: searchMilestonesQuery,
+ variables: { fullPath: this.config.fullPath, search, isProject: this.config.isProject },
+ })
+ .then(({ data }) => data[this.namespace]?.milestones.nodes);
+ },
fetchMilestones(searchTerm) {
this.loading = true;
- this.config
- .fetchMilestones(searchTerm)
+ this.fetchMilestonesQuery(searchTerm)
.then((response) => {
const data = Array.isArray(response) ? response : response.data;
diff --git a/app/assets/javascripts/vue_shared/issuable/list/components/issuable_item.vue b/app/assets/javascripts/vue_shared/issuable/list/components/issuable_item.vue
index 324228111d4..947a42d4184 100644
--- a/app/assets/javascripts/vue_shared/issuable/list/components/issuable_item.vue
+++ b/app/assets/javascripts/vue_shared/issuable/list/components/issuable_item.vue
@@ -251,6 +251,7 @@ export default {
<div data-testid="issuable-title" class="issue-title title">
<work-item-type-icon
v-if="showWorkItemTypeIcon"
+ class="gl-mr-2"
:work-item-type="type"
show-tooltip-on-hover
/>
diff --git a/app/assets/javascripts/vue_shared/issuable/show/components/issuable_header.vue b/app/assets/javascripts/vue_shared/issuable/show/components/issuable_header.vue
index fadd56fc697..c4b92454ac0 100644
--- a/app/assets/javascripts/vue_shared/issuable/show/components/issuable_header.vue
+++ b/app/assets/javascripts/vue_shared/issuable/show/components/issuable_header.vue
@@ -192,9 +192,8 @@ export default {
</span>
<work-item-type-icon
v-if="shouldShowWorkItemTypeIcon"
- class="gl-m-0!"
show-text
- :work-item-type="issuableType.toUpperCase()"
+ :work-item-type="issuableType"
/>
<gl-sprintf :message="createdMessage">
<template #timeAgo>
diff --git a/app/assets/javascripts/work_items/components/work_item_created_updated.vue b/app/assets/javascripts/work_items/components/work_item_created_updated.vue
index 60a74b9cdeb..14e55134048 100644
--- a/app/assets/javascripts/work_items/components/work_item_created_updated.vue
+++ b/app/assets/javascripts/work_items/components/work_item_created_updated.vue
@@ -90,7 +90,7 @@ export default {
hide-text-in-small-screens
/>
<work-item-type-icon
- class="gl-vertical-align-middle gl-mr-0!"
+ class="gl-vertical-align-middle"
:work-item-icon-name="workItemIconName"
:work-item-type="workItemType"
show-text
diff --git a/app/assets/javascripts/work_items/components/work_item_type_icon.vue b/app/assets/javascripts/work_items/components/work_item_type_icon.vue
index f27ae5f4e6d..5426f3965b3 100644
--- a/app/assets/javascripts/work_items/components/work_item_type_icon.vue
+++ b/app/assets/javascripts/work_items/components/work_item_type_icon.vue
@@ -53,7 +53,7 @@ export default {
</script>
<template>
- <span class="gl-mr-2">
+ <span>
<gl-icon
v-gl-tooltip.hover="showTooltipOnHover"
:name="iconName"
diff --git a/config/feature_flags/development/merge_trains_create_ref_service.yml b/config/feature_flags/development/merge_trains_create_ref_service.yml
index cd649589a93..cdbe6813210 100644
--- a/config/feature_flags/development/merge_trains_create_ref_service.yml
+++ b/config/feature_flags/development/merge_trains_create_ref_service.yml
@@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/420161
milestone: '16.3'
type: development
group: group::pipeline execution
-default_enabled: false
+default_enabled: true
diff --git a/doc/administration/settings/instance_template_repository.md b/doc/administration/settings/instance_template_repository.md
index bb48a7411f5..510c88e7738 100644
--- a/doc/administration/settings/instance_template_repository.md
+++ b/doc/administration/settings/instance_template_repository.md
@@ -32,6 +32,9 @@ After you add templates, you can use them for the entire instance.
They are available in the [Web Editor](../../user/project/repository/web_editor.md)
and through the [API settings](../../api/settings.md).
+These templates cannot be used as a value of the
+[`include:template`](../../ci/yaml/index.md#includetemplate) key in `.gitlab-ci.yml`.
+
## Supported file types and locations
Templates must be added to a specific subdirectory in the repository,
diff --git a/doc/api/api_resources.md b/doc/api/api_resources.md
index a764a59e869..8706e605c51 100644
--- a/doc/api/api_resources.md
+++ b/doc/api/api_resources.md
@@ -158,6 +158,7 @@ The following API resources are available outside of project and group contexts
| [Code snippets](snippets.md) | `/snippets` |
| [Code Suggestions](code_suggestions.md) | `/code_suggestions` |
| [Custom attributes](custom_attributes.md) | `/users/:id/custom_attributes` (also available for groups and projects) |
+| [Dependency list exports](dependency_list_export.md) **(ULTIMATE ALL)** | `/pipelines/:id/dependency_list_exports`, `/projects/:id/dependency_list_exports`, `/groups/:id/dependency_list_exports`, `/security/dependency_list_exports/:id`, `/security/dependency_list_exports/:id/download` |
| [Deploy keys](deploy_keys.md) | `/deploy_keys` (also available for projects) |
| [Deploy tokens](deploy_tokens.md) | `/deploy_tokens` (also available for projects and groups) |
| [Events](events.md) | `/events`, `/users/:id/events` (also available for projects) |
diff --git a/doc/api/dependency_list_export.md b/doc/api/dependency_list_export.md
new file mode 100644
index 00000000000..79bf5f1a68f
--- /dev/null
+++ b/doc/api/dependency_list_export.md
@@ -0,0 +1,149 @@
+---
+stage: Govern
+group: Threat Insights
+info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
+---
+
+# Dependency list export API **(ULTIMATE ALL)**
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/333463) in GitLab 16.4.
+
+Every call to this endpoint requires authentication.
+
+## Create a pipeline-level dependency list export
+
+Create a new CycloneDX JSON export for all the project dependencies detected in a pipeline.
+
+If an authenticated user doesn't have permission to
+[read_dependency](../user/permissions.md#custom-role-requirements),
+this request returns a `403 Forbidden` status code.
+
+SBOM exports can be only accessed by the export's author.
+
+```plaintext
+POST /pipelines/:id/dependency_list_exports
+```
+
+| Attribute | Type | Required | Description |
+| ------------------- | ----------------- | ---------- | -----------------------------------------------------------------------------------------------------------------------------|
+| `id` | integer | yes | The ID of the pipeline which the authenticated user has access to. |
+| `export_type` | string | yes | This must be set to `sbom`. |
+
+```shell
+curl --request POST --header "PRIVATE-TOKEN: <private_token>" "https://gitlab.example.com/api/v4/pipelines/1/dependency_list_exports" --data "export_type=sbom"
+```
+
+The created dependency list export is automatically deleted after 1 hour.
+
+Example response:
+
+```json
+{
+ "id": 2,
+ "has_finished": false,
+ "self": "http://gitlab.example.com/api/v4/dependency_list_exports/2",
+ "download": "http://gitlab.example.com/api/v4/dependency_list_exports/2/download"
+}
+```
+
+## Get single dependency list export
+
+Get a single dependency list export.
+
+```plaintext
+GET /security/dependency_list_exports/:id
+```
+
+| Attribute | Type | Required | Description |
+| --------- | ---- | -------- | ----------- |
+| `id` | integer | yes | The ID of the dependency list export. |
+
+```shell
+curl --header "PRIVATE-TOKEN: <private_token>" "https://gitlab.example.com/api/v4/security/dependency_list_exports/2"
+```
+
+The status code is `202 Accepted` when the dependency list export is being generated, and `200 OK` when it's ready.
+
+Example response:
+
+```json
+{
+ "id": 4,
+ "has_finished": true,
+ "self": "http://gitlab.example.com/api/v4/dependency_list_exports/4",
+ "download": "http://gitlab.example.com/api/v4/dependency_list_exports/4/download"
+}
+```
+
+## Download dependency list export
+
+Download a single dependency list export.
+
+```plaintext
+GET /security/dependency_list_exports/:id/download
+```
+
+| Attribute | Type | Required | Description |
+| --------- | ---- | -------- | ----------- |
+| `id` | integer | yes | The ID of the dependency list export. |
+
+```shell
+curl --header "PRIVATE-TOKEN: <private_token>" "https://gitlab.example.com/api/v4/security/dependency_list_exports/2/download"
+```
+
+The response is `404 Not Found` if the dependency list export is not finished yet or was not found.
+
+Example response:
+
+```json
+{
+ "bomFormat": "CycloneDX",
+ "specVersion": "1.4",
+ "serialNumber": "urn:uuid:aec33827-20ae-40d0-ae83-18ee846364d2",
+ "version": 1,
+ "metadata": {
+ "tools": [
+ {
+ "vendor": "Gitlab",
+ "name": "Gemnasium",
+ "version": "2.34.0"
+ }
+ ],
+ "authors": [
+ {
+ "name": "Gitlab",
+ "email": "support@gitlab.com"
+ }
+ ],
+ "properties": [
+ {
+ "name": "gitlab:dependency_scanning:input_file",
+ "value": "package-lock.json"
+ }
+ ]
+ },
+ "components": [
+ {
+ "name": "com.fasterxml.jackson.core/jackson-core",
+ "purl": "pkg:maven/com.fasterxml.jackson.core/jackson-core@2.9.2",
+ "version": "2.9.2",
+ "type": "library",
+ "licenses": [
+ {
+ "license": {
+ "id": "MIT",
+ "url": "https://spdx.org/licenses/MIT.html"
+ }
+ },
+ {
+ "license": {
+ "id": "BSD-3-Clause",
+ "url": "https://spdx.org/licenses/BSD-3-Clause.html"
+ }
+ }
+ ]
+ }
+ ]
+}
+
+```
diff --git a/doc/development/code_suggestions/index.md b/doc/development/code_suggestions/index.md
index 9b94e9020ba..38fd6200ace 100644
--- a/doc/development/code_suggestions/index.md
+++ b/doc/development/code_suggestions/index.md
@@ -36,3 +36,21 @@ This should enable everyone to see locally any change in an IDE being sent to th
1. LOG_FORMAT_JSON=false
1. LOG_TO_FILE=true
1. Watch the new log file ```modelgateway_debug.log``` , e.g. ```tail -f modelgateway_debug.log | fblog -a prefix -a suffix -a current_file_name -a suggestion -a language -a input -a parameters -a score -a exception```
+
+### Setup instructions to use staging Model Gateway
+
+When testing interactions with the Model Gateway, you might want to integrate your local GDK
+with the deployed staging Model Gateway. To do this:
+
+1. You need a [cloud staging license](../../user/project/repository/code_suggestions/self_managed.md#update-gitlab) that has the Code Suggestions add-on, because add-ons are enabled on staging. Drop a note in the `#s_fulfillment` internal Slack channel to request an add-on to your license. See this [handbook page](https://about.gitlab.com/handbook/developer-onboarding/#working-on-gitlab-ee-developer-licenses) for how to request a license for local development.
+1. Set env variables to point customers-dot to staging, and the Model Gateway to staging:
+
+ ```shell
+ export GITLAB_LICENSE_MODE=test
+ export CUSTOMER_PORTAL_URL=https://customers.staging.gitlab.com
+ export CODE_SUGGESTIONS_BASE_URL=https://codesuggestions.staging.gitlab.com
+ ```
+
+1. Restart the GDK.
+1. Ensure you followed the necessary [steps to enable the Code Suggestions feature](../../user/project/repository/code_suggestions/self_managed.md#gitlab-163-and-later).
+1. Test out the Code Suggestions feature by opening the Web IDE for a project.
diff --git a/doc/development/database/multiple_databases.md b/doc/development/database/multiple_databases.md
index f4cb1d7412d..41db9e296f6 100644
--- a/doc/development/database/multiple_databases.md
+++ b/doc/development/database/multiple_databases.md
@@ -11,6 +11,9 @@ To allow GitLab to scale further we
The two databases are `main` and `ci`. GitLab supports being run with either one database or two databases.
On GitLab.com we are using two separate databases.
+For the purpose of building the [Cells](../../architecture/blueprints/cells/index.md) architecture, we are decomposing
+the databases further, to introduce another database `gitlab_main_clusterwide`.
+
## GitLab Schema
For properly discovering allowed patterns between different databases
@@ -23,17 +26,22 @@ that we cannot use PostgreSQL schema due to complex migration procedures. Instea
the concept of application-level classification.
Each table of GitLab needs to have a `gitlab_schema` assigned:
-- `gitlab_main`: describes all tables that are being stored in the `main:` database (for example, like `projects`, `users`).
-- `gitlab_ci`: describes all CI tables that are being stored in the `ci:` database (for example, `ci_pipelines`, `ci_builds`).
-- `gitlab_geo`: describes all Geo tables that are being stored in the `geo:` database (for example, like `project_registry`, `secondary_usage_data`).
-- `gitlab_shared`: describes all application tables that contain data across all decomposed databases (for example, `loose_foreign_keys_deleted_records`) for models that inherit from `Gitlab::Database::SharedModel`.
-- `gitlab_internal`: describes all internal tables of Rails and PostgreSQL (for example, `ar_internal_metadata`, `schema_migrations`, `pg_*`).
-- `gitlab_pm`: describes all tables that store `package_metadata` (it is an alias for `gitlab_main`).
-- `...`: more schemas to be introduced with additional decomposed databases
+| Database | Description | Notes |
+| -------- | ----------- | ------- |
+| `gitlab_main`| All tables that are being stored in the `main:` database (for example, `projects` and `users`) | Currently, this is being replaced with `gitlab_main_cell`, for the purpose of building the [Cells](../../architecture/blueprints/cells/index.md) architecture. `gitlab_main_cell` schema describes all tables that are local to a cell in a GitLab installation. |
+| `gitlab_main_clusterwide` | All tables that are being stored cluster-wide in a GitLab installation, in the [Cells](../../architecture/blueprints/cells/index.md) architecture. | |
+| `gitlab_ci` | All CI tables that are being stored in the `ci:` database (for example, `ci_pipelines`, `ci_builds`) | |
+| `gitlab_geo` | All Geo tables that are being stored in the `geo:` database (for example, like `project_registry`, `secondary_usage_data`) | |
+| `gitlab_shared` | All application tables that contain data across all decomposed databases (for example, `loose_foreign_keys_deleted_records`) for models that inherit from `Gitlab::Database::SharedModel`. | |
+| `gitlab_internal` | All internal tables of Rails and PostgreSQL (for example, `ar_internal_metadata`, `schema_migrations`, `pg_*`) | |
+| `gitlab_pm` | All tables that store `package_metadata`| It is an alias for `gitlab_main`|
+
+More schemas to be introduced with additional decomposed databases
The usage of schema enforces the base class to be used:
-- `ApplicationRecord` for `gitlab_main`
+- `ApplicationRecord` for `gitlab_main`/`gitlab_main_cell.`
+- `MainClusterwide::ApplicationRecord` for `gitlab_main_clusterwide`.
- `Ci::ApplicationRecord` for `gitlab_ci`
- `Geo::TrackingBase` for `gitlab_geo`
- `Gitlab::Database::SharedModel` for `gitlab_shared`
@@ -465,6 +473,20 @@ You can see a real example of using this method for fixing a cross-join in
#### Allowlist for existing cross-joins
+The easiest way of identifying a cross-join is via failing pipelines.
+
+As an example, in [!130038](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/130038/diffs) we moved the `notification_settings` table to the `gitlab_main_cell` schema, by marking it as such in the `db/docs/notification_settings.yml` file.
+
+The pipeline failed with the following [error](https://gitlab.com/gitlab-org/gitlab/-/jobs/4929130983):
+
+```ruby
+Database::PreventCrossJoins::CrossJoinAcrossUnsupportedTablesError:
+
+Unsupported cross-join across 'users, notification_settings' querying 'gitlab_main_clusterwide, gitlab_main_cell' discovered when executing query 'SELECT "users".* FROM "users" WHERE "users"."id" IN (SELECT "notification_settings"."user_id" FROM ((SELECT "notification_settings"."user_id" FROM "notification_settings" WHERE "notification_settings"."source_id" = 119 AND "notification_settings"."source_type" = 'Project' AND (("notification_settings"."level" = 3 AND EXISTS (SELECT true FROM "notification_settings" "notification_settings_2" WHERE "notification_settings_2"."user_id" = "notification_settings"."user_id" AND "notification_settings_2"."source_id" IS NULL AND "notification_settings_2"."source_type" IS NULL AND "notification_settings_2"."level" = 2)) OR "notification_settings"."level" = 2))) notification_settings)'
+```
+
+To make the pipeline green, this cross-join query must be allow-listed.
+
A cross-join across databases can be explicitly allowed by wrapping the code in the
`::Gitlab::Database.allow_cross_joins_across_databases` helper method. Alternative
way is to mark a given relation as `relation.allow_cross_joins_across_databases`.
@@ -554,7 +576,42 @@ more information, look at the
[transaction guidelines](transaction_guidelines.md#dangerous-example-third-party-api-calls)
page.
-#### Fixing cross-database errors
+#### Fixing cross-database transactions
+
+A transaction across databases can be explicitly allowed by wrapping the code in the
+`Gitlab::Database::QueryAnalyzers::PreventCrossDatabaseModification.temporary_ignore_tables_in_transaction` helper method.
+
+For cross-database transactions in Rails callbacks, the `cross_database_ignore_tables` method can be used.
+
+These methods should only be used for existing code.
+
+The `temporary_ignore_tables_in_transaction` helper method can be used as follows:
+
+```ruby
+class GroupMember < Member
+ def update_two_factor_requirement
+ return unless user
+
+ # To mark and ignore cross-database transactions involving members and users/user_details/user_preferences
+ Gitlab::Database::QueryAnalyzers::PreventCrossDatabaseModification.temporary_ignore_tables_in_transaction(
+ %w[users user_details user_preferences], url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/424288'
+ ) do
+ user.update_two_factor_requirement
+ end
+ end
+end
+```
+
+The `cross_database_ignore_tables` method can be used as follows:
+
+```ruby
+class Namespace < ApplicationRecord
+ include CrossDatabaseIgnoredTables
+
+ # To mark and ignore cross-database transactions involving namespaces and routes/redirect_routes happening within Rails callbacks.
+ cross_database_ignore_tables %w[routes redirect_routes], url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/424277'
+end
+```
##### Removing the transaction block
@@ -640,6 +697,23 @@ or records that point to nowhere, which might lead to bugs. As such we created
["loose foreign keys"](loose_foreign_keys.md) which is an asynchronous
process of cleaning up orphaned records.
+### Allowlist for existing cross-database foreign keys
+
+The easiest way of identifying a cross-database foreign key is via failing pipelines.
+
+As an example, in [!130038](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/130038/diffs) we moved the `notification_settings` table to the `gitlab_main_cell` schema, by marking it in the `db/docs/notification_settings.yml` file.
+
+`notification_settings.user_id` is a column that points to `users`, but the `users` table belongs to a different database, thus this is now treated as a cross-database foreign key.
+
+We have a spec to capture such cases of cross-database foreign keys in [`no_cross_db_foreign_keys_spec.rb`](https://gitlab.com/gitlab-org/gitlab/-/blob/01d3a1e41513200368a22bbab5d4312174762ee0/spec/lib/gitlab/database/no_cross_db_foreign_keys_spec.rb), which would fail if such a cross-database foreign key is encountered.
+
+To make the pipeline green, this cross-database foreign key must be allow-listed.
+
+To do this, explicitly allow the existing cross-database foreign key to exist by adding it as an exception in the same spec (as in [this example](https://gitlab.com/gitlab-org/gitlab/-/blob/7d99387f399c548af24d93d564b35f2f9510662d/spec/lib/gitlab/database/no_cross_db_foreign_keys_spec.rb#L26)).
+This way, the spec will not fail.
+
+Later, this foreign key can be converted to a loose foreign key, like we did in [!130080](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/130080/diffs).
+
## Testing for multiple databases
In our testing CI pipelines, we test GitLab by default with multiple databases set up, using
diff --git a/doc/tutorials/export_sbom.md b/doc/tutorials/export_sbom.md
new file mode 100644
index 00000000000..cbbb1421283
--- /dev/null
+++ b/doc/tutorials/export_sbom.md
@@ -0,0 +1,95 @@
+---
+stage: Secure
+group: Composition Analysis
+info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
+---
+
+# Tutorial: Export dependency list in SBOM format **(ULTIMATE ALL)**
+
+Dependency Scanning output can be exported to the CycloneDX JSON format.
+
+This tutorial shows you how to generate a CycloneDX JSON SBOM for a pipeline, and then to upload it as a CI job artifact.
+
+## Prerequisites
+
+Set up Dependency Scanning. For detailed instructions, follow [the Dependency Scanning tutorial](dependency_scanning.md).
+
+## Create configuration files
+
+1. Create a [snippet](../api/snippets.md) with the following code.
+
+ Filename: `export.sh`
+
+ ```shell
+ #! /bin/sh
+
+ function create_export {
+ curl --silent \
+ --header "PRIVATE-TOKEN: $PRIVATE_TOKEN" \
+ -X 'POST' --data "export_type=sbom" \
+ "http://gitlab.localdev:3000/api/v4/pipelines/$CI_PIPELINE_ID/dependency_list_exports" \
+ | jq '.id'
+ }
+
+ function check_status {
+ curl --silent \
+ --header "PRIVATE-TOKEN: $PRIVATE_TOKEN" \
+ --write-out "%{http_code}" --output /dev/null \
+ http://gitlab.localdev:3000/api/v4/dependency_list_exports/$1
+ }
+
+ function download {
+ curl --header "PRIVATE-TOKEN: $PRIVATE_TOKEN" \
+ --output "gl-sbom-merged-$CI_PIPELINE_ID.cdx.json" \
+ "http://gitlab.localdev:3000/api/v4/dependency_list_exports/$1/download"
+ }
+
+ function export_sbom {
+ local ID=$(create_export)
+
+ for run in $(seq 0 3); do
+ local STATUS=$(check_status $ID)
+ # Status is 200 when JSON is generated.
+ # Status is 202 when generate JSON job is running.
+ if [ $STATUS -eq "200" ]; then
+ download $ID
+
+ exit 0
+ elif [ $STATUS -ne "202" ]; then
+ exit 1
+ fi
+
+ echo "Waiting for JSON to be generated"
+ sleep 5
+ done
+
+ exit 1
+ }
+
+ export_sbom
+ ```
+
+ The above script works in the following steps:
+
+ 1. Create a CycloneDX SBOM export for the current pipeline.
+ 1. Check the status of that export, and stop when it's ready.
+ 1. Download the CycloneDX SBOM file.
+
+1. Update `.gitlab-ci.yml` with the following code.
+
+ ```yaml
+ export-merged-sbom:
+ before_script:
+ - apk add --update jq curl
+ stage: .post
+ script:
+ - curl --output export.sh --url "https://gitlab.example.com/api/v4/snippets/<SNIPPET_ID>/raw"
+ - /bin/sh export.sh
+ artifacts:
+ paths:
+ - "gl-sbom-merged-*.cdx.json"
+ ```
+
+1. Go to **Build > Pipelines** and confirm that the latest pipeline completed successfully.
+
+In the job artifacts, `gl-sbom-merged-<pipeline_id>.cdx.json` file should be present.
diff --git a/doc/tutorials/secure_application.md b/doc/tutorials/secure_application.md
index 54235d0a6dc..96a4107e36c 100644
--- a/doc/tutorials/secure_application.md
+++ b/doc/tutorials/secure_application.md
@@ -11,6 +11,7 @@ GitLab can check your application for security vulnerabilities and that it meets
| Topic | Description | Good for beginners |
|-------|-------------|--------------------|
| [Set up dependency scanning](dependency_scanning.md) | Learn how to detect vulnerabilities in an application's dependencies. | **{star}** |
+| [Export Dependency List in SBOM format](export_sbom.md) | Learn how to export an application's dependencies to the CycloneDX SBOM format. | **{star}** |
| [Create a compliance pipeline](compliance_pipeline/index.md) | Learn how to create compliance pipelines for your groups. | **{star}** |
| [Set up a scan result policy](scan_result_policy/index.md) | Learn how to configure a scan result policy that takes action based on scan results. | **{star}** |
| [Scan a Docker container for vulnerabilities](container_scanning/index.md) | Learn how to use container scanning templates to add container scanning to your projects. | **{star}** |
diff --git a/doc/user/application_security/dependency_list/index.md b/doc/user/application_security/dependency_list/index.md
index 481fc774885..dbad5ff9c11 100644
--- a/doc/user/application_security/dependency_list/index.md
+++ b/doc/user/application_security/dependency_list/index.md
@@ -117,4 +117,10 @@ You can download your group's or project's list of dependencies and their detail
### Using the API
+#### List project Dependencies
+
You can download your project's list of dependencies [using the API](../../../api/dependencies.md#list-project-dependencies). Note this only provides the dependencies identified by the [Gemnasium family of analyzers](../dependency_scanning/index.md#dependency-analyzers) and not any other of the GitLab dependency analyzers.
+
+#### Export pipeline dependency list
+
+You can download your project's list of dependencies identified in a pipeline [using the API](../../../api/dependency_list_export.md).
diff --git a/doc/user/clusters/agent/ci_cd_workflow.md b/doc/user/clusters/agent/ci_cd_workflow.md
index 6c7f43e2991..a1281d3d75c 100644
--- a/doc/user/clusters/agent/ci_cd_workflow.md
+++ b/doc/user/clusters/agent/ci_cd_workflow.md
@@ -15,9 +15,9 @@ info: To determine the technical writer assigned to the Stage/Group associated w
> - The ability to switch between certificate-based clusters and agents was [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/335089) in GitLab 14.9. The certificate-based cluster context is always called `gitlab-deploy`.
> - [Renamed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/80508) from _CI/CD tunnel_ to _CI/CD workflow_ in GitLab 14.9.
-You can use a GitLab CI/CD workflow to safely deploy to and update your Kubernetes clusters.
+You can use GitLab CI/CD to safely connect, deploy, and update your Kubernetes clusters.
-To do so, you must first [install an agent in your cluster](install/index.md). When done, you have a Kubernetes context and can
+To do so, [install an agent in your cluster](install/index.md). When done, you have a Kubernetes context and can
run Kubernetes API commands in your GitLab CI/CD pipeline.
To ensure access to your cluster is safe:
@@ -25,11 +25,11 @@ To ensure access to your cluster is safe:
- Each agent has a separate context (`kubecontext`).
- Only the project where the agent is configured, and any additional projects you authorize, can access the agent in your cluster.
-The CI/CD workflow requires runners to be registered with GitLab, but these runners do not have to be in the cluster where the agent is.
+To use GitLab CI/CD to interact with your cluster, runners must be registered with GitLab. However, these runners do not have to be in the cluster where the agent is.
-## GitLab CI/CD workflow steps
+## Use GitLab CI/CD with your cluster
-To update a Kubernetes cluster by using GitLab CI/CD, complete the following steps.
+To update a Kubernetes cluster with GitLab CI/CD:
1. Ensure you have a working Kubernetes cluster and the manifests are in a GitLab project.
1. In the same GitLab project, [register and install the GitLab agent](install/index.md).
diff --git a/doc/user/clusters/agent/install/index.md b/doc/user/clusters/agent/install/index.md
index fb6d9c10f4c..d620a9f658c 100644
--- a/doc/user/clusters/agent/install/index.md
+++ b/doc/user/clusters/agent/install/index.md
@@ -43,7 +43,7 @@ To install the agent in your cluster:
For configuration settings, the agent uses a YAML file in the GitLab project. You must create this file if:
- You use [a GitOps workflow](../gitops/agent.md#gitops-workflow-steps).
-- You use [a GitLab CI/CD workflow](../ci_cd_workflow.md#gitlab-cicd-workflow-steps) and want to authorize a different project to use the agent.
+- You use [a GitLab CI/CD workflow](../ci_cd_workflow.md#use-gitlab-cicd-with-your-cluster) and want to authorize a different project to use the agent.
- You [allow specific project or group members to access Kubernetes](../user_access.md).
To create an agent configuration file:
diff --git a/doc/user/group/custom_project_templates.md b/doc/user/group/custom_project_templates.md
index 491ae1ec528..87c1c548abd 100644
--- a/doc/user/group/custom_project_templates.md
+++ b/doc/user/group/custom_project_templates.md
@@ -69,6 +69,35 @@ gitlab.com/myorganization/
...
```
+## What is copied from the templates
+
+The entire custom instance-level project templates repository is copied, including:
+
+- Branches
+- Commits
+- Tags
+
+If the user:
+
+- Has the Owner role on the custom instance-level project templates project or is a GitLab administrator,
+ all project settings are copied over to the new project.
+- Doesn't have the Owner role or is not a GitLab administrator,
+ project deploy keys and project webhooks aren't copied over because they contain sensitive data.
+
+To learn more about what is migrated, see
+[Items that are exported](../project/settings/import_export.md#items-that-are-exported).
+
+## User assignments in templates
+
+When you use a template created by another user, any items that were assigned
+to a user in the template are reassigned to you. It's important to understand
+this reassignment when you configure security features like protected branches
+and tags. For example, if the template contains a protected branch:
+
+- In the template, the branch allows the _template owner_ to merge into the default branch.
+- In the project created from the template, the branch allows _you_ to merge into
+ the default branch.
+
<!-- ## Troubleshooting
Include any troubleshooting steps that you can foresee. If you know beforehand what issues
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 9ac4b89e6af..879f03519b0 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -41427,6 +41427,9 @@ msgstr ""
msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
msgstr ""
+msgid "ScanResultPolicy|Block users from modifying protected branches"
+msgstr ""
+
msgid "ScanResultPolicy|Choose criteria type"
msgstr ""
@@ -41493,12 +41496,21 @@ msgstr ""
msgid "ScanResultPolicy|Pre-existing"
msgstr ""
-msgid "ScanResultPolicy|Prevent branch protection modification"
+msgid "ScanResultPolicy|Prevent approval by anyone who added a commit"
+msgstr ""
+
+msgid "ScanResultPolicy|Prevent approval by merge request's author"
msgstr ""
msgid "ScanResultPolicy|Protected branch settings"
msgstr ""
+msgid "ScanResultPolicy|Remove all approvals when commit is added"
+msgstr ""
+
+msgid "ScanResultPolicy|Require the user's password to approve"
+msgstr ""
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr ""
@@ -41532,6 +41544,9 @@ msgstr ""
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr ""
+msgid "ScanResultPolicy|When enabled, two person approval will be required on all MRs as merge request authors cannot approve their own MRs and merge them unilaterally"
+msgstr ""
+
msgid "ScanResultPolicy|any commits"
msgstr ""
diff --git a/spec/frontend/boards/components/issue_board_filtered_search_spec.js b/spec/frontend/boards/components/issue_board_filtered_search_spec.js
index 5b5b68d5dbe..16ad54f0854 100644
--- a/spec/frontend/boards/components/issue_board_filtered_search_spec.js
+++ b/spec/frontend/boards/components/issue_board_filtered_search_spec.js
@@ -61,12 +61,7 @@ describe('IssueBoardFilter', () => {
({ isSignedIn }) => {
createComponent({ isSignedIn });
- const tokens = mockTokens(
- fetchLabelsSpy,
- fetchUsersSpy,
- wrapper.vm.fetchMilestones,
- isSignedIn,
- );
+ const tokens = mockTokens(fetchLabelsSpy, fetchUsersSpy, isSignedIn);
expect(findBoardsFilteredSearch().props('tokens')).toEqual(orderBy(tokens, ['title']));
},
diff --git a/spec/frontend/boards/mock_data.js b/spec/frontend/boards/mock_data.js
index 8f57a6eb7da..dfcdb4c05d0 100644
--- a/spec/frontend/boards/mock_data.js
+++ b/spec/frontend/boards/mock_data.js
@@ -827,7 +827,7 @@ export const mockConfidentialToken = {
],
};
-export const mockTokens = (fetchLabels, fetchUsers, fetchMilestones, isSignedIn) => [
+export const mockTokens = (fetchLabels, fetchUsers, isSignedIn) => [
{
icon: 'user',
title: TOKEN_TITLE_ASSIGNEE,
@@ -870,7 +870,8 @@ export const mockTokens = (fetchLabels, fetchUsers, fetchMilestones, isSignedIn)
shouldSkipSort: true,
token: MilestoneToken,
unique: true,
- fetchMilestones,
+ fullPath: 'gitlab-org',
+ isProject: false,
},
{
icon: 'issues',
diff --git a/spec/frontend/vue_shared/components/filtered_search_bar/mock_data.js b/spec/frontend/vue_shared/components/filtered_search_bar/mock_data.js
index b2f4c780f51..a22ad4c450e 100644
--- a/spec/frontend/vue_shared/components/filtered_search_bar/mock_data.js
+++ b/spec/frontend/vue_shared/components/filtered_search_bar/mock_data.js
@@ -84,6 +84,19 @@ export const mockMilestones = [
mockEscapedMilestone,
];
+export const projectMilestonesResponse = {
+ data: {
+ project: {
+ id: 'gid://gitlab/Project/1',
+ attributes: {
+ nodes: mockMilestones,
+ __typename: 'MilestoneConnection',
+ },
+ __typename: 'Project',
+ },
+ },
+};
+
export const mockCrmContacts = [
{
__typename: 'CustomerRelationsContact',
@@ -257,7 +270,8 @@ export const mockMilestoneToken = {
symbol: '%',
token: MilestoneToken,
operators: OPERATORS_IS,
- fetchMilestones: () => Promise.resolve({ data: mockMilestones }),
+ fullPath: 'gitlab-org',
+ isProject: true,
};
export const mockReleaseToken = {
diff --git a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/milestone_token_spec.js b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/milestone_token_spec.js
index db51b4a05b1..36e82b39df4 100644
--- a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/milestone_token_spec.js
+++ b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/milestone_token_spec.js
@@ -6,17 +6,27 @@ import {
} from '@gitlab/ui';
import { mount } from '@vue/test-utils';
import MockAdapter from 'axios-mock-adapter';
-import { nextTick } from 'vue';
+import Vue, { nextTick } from 'vue';
+import VueApollo from 'vue-apollo';
+import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { sortMilestonesByDueDate } from '~/milestones/utils';
+import searchMilestonesQuery from '~/issues/list/queries/search_milestones.query.graphql';
import { DEFAULT_MILESTONES } from '~/vue_shared/components/filtered_search_bar/constants';
import MilestoneToken from '~/vue_shared/components/filtered_search_bar/tokens/milestone_token.vue';
import BaseToken from '~/vue_shared/components/filtered_search_bar/tokens/base_token.vue';
-import { mockMilestoneToken, mockMilestones, mockRegularMilestone } from '../mock_data';
+import {
+ mockMilestoneToken,
+ mockMilestones,
+ mockRegularMilestone,
+ projectMilestonesResponse,
+} from '../mock_data';
+
+Vue.use(VueApollo);
jest.mock('~/alert');
jest.mock('~/milestones/utils');
@@ -31,6 +41,9 @@ const defaultStubs = {
},
};
+const milestonesQueryHandler = jest.fn().mockResolvedValue(projectMilestonesResponse);
+const mockApollo = createMockApollo([[searchMilestonesQuery, milestonesQueryHandler]]);
+
function createComponent(options = {}) {
const {
config = { ...mockMilestoneToken, shouldSkipSort: true },
@@ -39,6 +52,7 @@ function createComponent(options = {}) {
stubs = defaultStubs,
} = options;
return mount(MilestoneToken, {
+ apolloProvider: mockApollo,
propsData: {
config,
value,
@@ -102,6 +116,33 @@ describe('MilestoneToken', () => {
});
});
+ describe('default - when fetchMilestones function is not provided in config', () => {
+ beforeEach(() => {
+ wrapper = createComponent({});
+ return triggerFetchMilestones();
+ });
+
+ it('calls searchMilestonesQuery to fetch milestones', () => {
+ expect(milestonesQueryHandler).toHaveBeenCalledWith({
+ fullPath: mockMilestoneToken.fullPath,
+ isProject: mockMilestoneToken.isProject,
+ search: null,
+ });
+ });
+
+ it('calls searchMilestonesQuery with search parameter when provided', async () => {
+ const searchTerm = 'foo';
+
+ await triggerFetchMilestones(searchTerm);
+
+ expect(milestonesQueryHandler).toHaveBeenCalledWith({
+ fullPath: mockMilestoneToken.fullPath,
+ isProject: mockMilestoneToken.isProject,
+ search: searchTerm,
+ });
+ });
+ });
+
describe('when request is successful', () => {
const searchTerm = 'foo';
diff --git a/spec/frontend/vue_shared/issuable/show/components/issuable_header_spec.js b/spec/frontend/vue_shared/issuable/show/components/issuable_header_spec.js
index a3d7b244685..7662aa535e3 100644
--- a/spec/frontend/vue_shared/issuable/show/components/issuable_header_spec.js
+++ b/spec/frontend/vue_shared/issuable/show/components/issuable_header_spec.js
@@ -170,7 +170,7 @@ describe('IssuableHeader component', () => {
expect(findWorkItemTypeIcon().props()).toMatchObject({
showText: true,
- workItemType: 'ISSUE',
+ workItemType: 'issue',
});
});