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/review.gitlab-ci.yml5
-rw-r--r--app/assets/javascripts/gitlab_version_check/components/security_patch_upgrade_alert.vue76
-rw-r--r--app/assets/javascripts/gitlab_version_check/constants.js2
-rw-r--r--app/assets/javascripts/gitlab_version_check/index.js31
-rw-r--r--app/assets/javascripts/main.js17
-rw-r--r--app/assets/javascripts/pages/admin/dashboard/index.js3
-rw-r--r--app/assets/javascripts/pages/help/index/index.js2
-rw-r--r--app/helpers/version_check_helper.rb8
-rw-r--r--app/services/bulk_imports/create_service.rb3
-rw-r--r--app/views/layouts/_page.html.haml1
-rw-r--r--app/views/shared/gitlab_version/_security_patch_upgrade_alert.html.haml3
-rw-r--r--config/open_api.yml2
-rw-r--r--danger/product_intelligence/Dangerfile2
-rw-r--r--doc/administration/geo/replication/troubleshooting.md4
-rw-r--r--doc/development/documentation/styleguide/index.md13
-rw-r--r--doc/development/documentation/styleguide/word_list.md5
-rw-r--r--doc/user/packages/conan_repository/index.md5
-rw-r--r--doc/user/packages/container_registry/index.md3
-rw-r--r--doc/user/packages/package_registry/index.md24
-rw-r--r--doc/user/permissions.md2
-rw-r--r--doc/user/project/merge_requests/approvals/settings.md34
-rw-r--r--doc/user/project/merge_requests/methods/index.md130
-rw-r--r--lib/api/api.rb2
-rw-r--r--lib/api/concerns/packages/nuget_endpoints.rb38
-rw-r--r--lib/api/nuget_group_packages.rb2
-rw-r--r--lib/bulk_imports/clients/http.rb33
-rw-r--r--lib/bulk_imports/groups/stage.rb2
-rw-r--r--lib/bulk_imports/projects/stage.rb2
-rw-r--r--lib/bulk_imports/stage.rb2
-rw-r--r--locale/gitlab.pot18
-rw-r--r--package.json1
-rw-r--r--spec/factories/bulk_import.rb1
-rw-r--r--spec/features/projects/settings/repository_settings_spec.rb7
-rw-r--r--spec/frontend/gitlab_version_check/components/security_patch_upgrade_alert_spec.js84
-rw-r--r--spec/frontend/gitlab_version_check/index_spec.js27
-rw-r--r--spec/frontend/gitlab_version_check/mock_data.js10
-rw-r--r--spec/helpers/version_check_helper_spec.rb26
-rw-r--r--spec/lib/bulk_imports/clients/http_spec.rb32
-rw-r--r--spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_namespaces_spec.rb58
-rw-r--r--spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_projects_spec.rb22
-rw-r--r--spec/requests/api/bulk_imports_spec.rb3
-rw-r--r--spec/requests/projects/ml/experiments_controller_spec.rb2
-rw-r--r--spec/services/bulk_imports/create_service_spec.rb2
-rw-r--r--spec/tooling/danger/product_intelligence_spec.rb74
-rw-r--r--spec/tooling/fixtures/metrics/sample_instrumentation_metric.rb15
-rw-r--r--spec/views/shared/gitlab_version/_security_patch_upgrade_alert.html.haml_spec.rb16
-rw-r--r--tooling/danger/product_intelligence.rb67
-rw-r--r--yarn.lock38
48 files changed, 781 insertions, 178 deletions
diff --git a/.gitlab/ci/review.gitlab-ci.yml b/.gitlab/ci/review.gitlab-ci.yml
index 1fb8985aba1..5c1c4cc9001 100644
--- a/.gitlab/ci/review.gitlab-ci.yml
+++ b/.gitlab/ci/review.gitlab-ci.yml
@@ -30,6 +30,7 @@ review-cleanup:
before_script:
- source scripts/review_apps/gcp_cleanup.sh
- setup_gcp_dependencies
+ - !reference [".use-kube-context", before_script]
review-k8s-resources-count-checks:
extends:
@@ -41,8 +42,6 @@ review-k8s-resources-count-checks:
environment:
name: review/k8s-resources-count-checks
action: verify
- before_script:
- - !reference [".use-kube-context", before_script]
script:
- scripts/review_apps/k8s-resources-count-checks.sh || (scripts/slack review-apps-monitoring "☠️ \`${CI_JOB_NAME}\` failed! ☠️ See ${CI_JOB_URL}" warning "GitLab Bot" && exit 1);
@@ -54,8 +53,6 @@ review-gcp-quotas-checks:
environment:
name: review/gcp-quotas-checks
action: verify
- before_script:
- - !reference [".use-kube-context", before_script]
script:
- ruby scripts/review_apps/gcp-quotas-checks.rb || (scripts/slack review-apps-monitoring "☠️ \`${CI_JOB_NAME}\` failed! ☠️ See ${CI_JOB_URL}" warning "GitLab Bot" && exit 1);
diff --git a/app/assets/javascripts/gitlab_version_check/components/security_patch_upgrade_alert.vue b/app/assets/javascripts/gitlab_version_check/components/security_patch_upgrade_alert.vue
new file mode 100644
index 00000000000..89dc68ec73e
--- /dev/null
+++ b/app/assets/javascripts/gitlab_version_check/components/security_patch_upgrade_alert.vue
@@ -0,0 +1,76 @@
+<script>
+import { GlAlert, GlSprintf, GlLink, GlButton } from '@gitlab/ui';
+import { s__ } from '~/locale';
+import Tracking from '~/tracking';
+import { UPGRADE_DOCS_URL, ABOUT_RELEASES_PAGE } from '../constants';
+
+export default {
+ name: 'SecurityPatchUpgradeAlert',
+ i18n: {
+ alertTitle: s__('VersionCheck|Critical security upgrade available'),
+ alertBody: s__(
+ 'VersionCheck|You are currently on version %{currentVersion}. We strongly recommend upgrading your GitLab installation. %{link}',
+ ),
+ learnMore: s__('VersionCheck|Learn more about this critical security release.'),
+ primaryButtonText: s__('VersionCheck|Upgrade now'),
+ },
+ components: {
+ GlAlert,
+ GlSprintf,
+ GlLink,
+ GlButton,
+ },
+ mixins: [Tracking.mixin()],
+ props: {
+ currentVersion: {
+ type: String,
+ required: true,
+ },
+ },
+ mounted() {
+ this.track('render', {
+ label: 'security_patch_upgrade_alert',
+ property: this.currentVersion,
+ });
+ },
+ methods: {
+ trackLearnMoreClick() {
+ this.track('click_link', {
+ label: 'security_patch_upgrade_alert_learn_more',
+ property: this.currentVersion,
+ });
+ },
+ trackUpgradeNowClick() {
+ this.track('click_link', {
+ label: 'security_patch_upgrade_alert_upgrade_now',
+ property: this.currentVersion,
+ });
+ },
+ },
+ UPGRADE_DOCS_URL,
+ ABOUT_RELEASES_PAGE,
+};
+</script>
+
+<template>
+ <gl-alert :title="$options.i18n.alertTitle" variant="danger" :dismissible="false">
+ <gl-sprintf :message="$options.i18n.alertBody">
+ <template #currentVersion>
+ <span class="gl-font-weight-bold">{{ currentVersion }}</span>
+ </template>
+ <template #link>
+ <gl-link :href="$options.ABOUT_RELEASES_PAGE" @click="trackLearnMoreClick">{{
+ $options.i18n.learnMore
+ }}</gl-link>
+ </template>
+ </gl-sprintf>
+ <template #actions>
+ <gl-button
+ :href="$options.UPGRADE_DOCS_URL"
+ variant="confirm"
+ @click="trackUpgradeNowClick"
+ >{{ $options.i18n.primaryButtonText }}</gl-button
+ >
+ </template>
+ </gl-alert>
+</template>
diff --git a/app/assets/javascripts/gitlab_version_check/constants.js b/app/assets/javascripts/gitlab_version_check/constants.js
index 259723a4e22..43759c79b5b 100644
--- a/app/assets/javascripts/gitlab_version_check/constants.js
+++ b/app/assets/javascripts/gitlab_version_check/constants.js
@@ -7,3 +7,5 @@ export const STATUS_TYPES = {
};
export const UPGRADE_DOCS_URL = helpPagePath('update/index');
+
+export const ABOUT_RELEASES_PAGE = 'https://about.gitlab.com/releases/categories/releases/';
diff --git a/app/assets/javascripts/gitlab_version_check/index.js b/app/assets/javascripts/gitlab_version_check/index.js
index 8d778ecc792..b3180c2d1ba 100644
--- a/app/assets/javascripts/gitlab_version_check/index.js
+++ b/app/assets/javascripts/gitlab_version_check/index.js
@@ -1,6 +1,7 @@
import Vue from 'vue';
import { parseBoolean } from '~/lib/utils/common_utils';
import GitlabVersionCheckBadge from './components/gitlab_version_check_badge.vue';
+import SecurityPatchUpgradeAlert from './components/security_patch_upgrade_alert.vue';
const mountGitlabVersionCheckBadge = (el) => {
const { size, version } = el.dataset;
@@ -31,8 +32,36 @@ const mountGitlabVersionCheckBadge = (el) => {
}
};
+const mountSecurityPatchUpgradeAlert = (el) => {
+ const { currentVersion } = el.dataset;
+
+ try {
+ return new Vue({
+ el,
+ render(createElement) {
+ return createElement(SecurityPatchUpgradeAlert, {
+ props: {
+ currentVersion,
+ },
+ });
+ },
+ });
+ } catch {
+ return null;
+ }
+};
+
export default () => {
+ const renderedApps = [];
+
+ const securityPatchUpgradeAlert = document.getElementById('js-security-patch-upgrade-alert');
const versionCheckBadges = [...document.querySelectorAll('.js-gitlab-version-check-badge')];
- return versionCheckBadges.map((el) => mountGitlabVersionCheckBadge(el));
+ if (securityPatchUpgradeAlert) {
+ renderedApps.push(mountSecurityPatchUpgradeAlert(securityPatchUpgradeAlert));
+ }
+
+ renderedApps.push(...versionCheckBadges.map((el) => mountGitlabVersionCheckBadge(el)));
+
+ return renderedApps;
};
diff --git a/app/assets/javascripts/main.js b/app/assets/javascripts/main.js
index 8e4ebd510aa..df3b55ed2ad 100644
--- a/app/assets/javascripts/main.js
+++ b/app/assets/javascripts/main.js
@@ -37,6 +37,7 @@ import initBroadcastNotifications from './broadcast_notification';
import { initTopNav } from './nav';
import { initCopyCodeButton } from './behaviors/copy_code';
import initHeaderSearch from './header_search/init';
+import initGitlabVersionCheck from './gitlab_version_check';
import 'ee_else_ce/main_ee';
import 'jh_else_ce/main_jh';
@@ -100,21 +101,7 @@ function deferredInitialisation() {
initDefaultTrackers();
initFeatureHighlight();
initCopyCodeButton();
-
- const helpToggle = document.querySelector('.header-help-dropdown-toggle');
- if (helpToggle) {
- helpToggle.addEventListener(
- 'click',
- () => {
- import(/* webpackChunkName: 'versionCheck' */ './gitlab_version_check')
- .then(({ default: initGitlabVersionCheck }) => {
- initGitlabVersionCheck();
- })
- .catch(() => {});
- },
- { once: true },
- );
- }
+ initGitlabVersionCheck();
addSelectOnFocusBehaviour('.js-select-on-focus');
diff --git a/app/assets/javascripts/pages/admin/dashboard/index.js b/app/assets/javascripts/pages/admin/dashboard/index.js
deleted file mode 100644
index b63e612be47..00000000000
--- a/app/assets/javascripts/pages/admin/dashboard/index.js
+++ /dev/null
@@ -1,3 +0,0 @@
-import initGitlabVersionCheck from '~/gitlab_version_check';
-
-initGitlabVersionCheck();
diff --git a/app/assets/javascripts/pages/help/index/index.js b/app/assets/javascripts/pages/help/index/index.js
index a8e67c57307..da748223440 100644
--- a/app/assets/javascripts/pages/help/index/index.js
+++ b/app/assets/javascripts/pages/help/index/index.js
@@ -1,5 +1,3 @@
import docs from '~/docs/docs_bundle';
-import initGitlabVersionCheck from '~/gitlab_version_check';
docs();
-initGitlabVersionCheck();
diff --git a/app/helpers/version_check_helper.rb b/app/helpers/version_check_helper.rb
index 7179607ca7c..0bb92dfd118 100644
--- a/app/helpers/version_check_helper.rb
+++ b/app/helpers/version_check_helper.rb
@@ -3,6 +3,8 @@
module VersionCheckHelper
include Gitlab::Utils::StrongMemoize
+ SECURITY_ALERT_SEVERITY = 'danger'
+
def show_version_check?
return false unless Gitlab::CurrentSettings.version_check_enabled
return false if User.single_user&.requires_usage_stats_consent?
@@ -15,6 +17,12 @@ module VersionCheckHelper
end
strong_memoize_attr :gitlab_version_check
+ def show_security_patch_upgrade_alert?
+ return false unless show_version_check? && gitlab_version_check
+
+ gitlab_version_check['severity'] === SECURITY_ALERT_SEVERITY
+ end
+
def link_to_version
if Gitlab.pre_release?
commit_link = link_to(Gitlab.revision, source_host_url + namespace_project_commits_path(source_code_group, source_code_project, Gitlab.revision))
diff --git a/app/services/bulk_imports/create_service.rb b/app/services/bulk_imports/create_service.rb
index 0403069e5d4..124b5964232 100644
--- a/app/services/bulk_imports/create_service.rb
+++ b/app/services/bulk_imports/create_service.rb
@@ -57,7 +57,8 @@ module BulkImports
bulk_import = BulkImport.create!(
user: current_user,
source_type: 'gitlab',
- source_version: client.instance_version
+ source_version: client.instance_version,
+ source_enterprise: client.instance_enterprise
)
bulk_import.create_configuration!(credentials.slice(:url, :access_token))
diff --git a/app/views/layouts/_page.html.haml b/app/views/layouts/_page.html.haml
index d668399b408..bb1d051f71f 100644
--- a/app/views/layouts/_page.html.haml
+++ b/app/views/layouts/_page.html.haml
@@ -14,6 +14,7 @@
= dispensable_render "layouts/header/registration_enabled_callout"
= dispensable_render "layouts/nav/classification_level_banner"
= yield :flash_message
+ = dispensable_render "shared/gitlab_version/security_patch_upgrade_alert"
= dispensable_render "shared/service_ping_consent"
= dispensable_render_if_exists "layouts/header/ee_subscribable_banner"
= dispensable_render_if_exists "layouts/header/seat_count_alert"
diff --git a/app/views/shared/gitlab_version/_security_patch_upgrade_alert.html.haml b/app/views/shared/gitlab_version/_security_patch_upgrade_alert.html.haml
new file mode 100644
index 00000000000..7604445abb2
--- /dev/null
+++ b/app/views/shared/gitlab_version/_security_patch_upgrade_alert.html.haml
@@ -0,0 +1,3 @@
+- return unless show_security_patch_upgrade_alert?
+
+#js-security-patch-upgrade-alert{ data: { "current_version": Gitlab.version_info } }
diff --git a/config/open_api.yml b/config/open_api.yml
index 100bf4df67e..aaf38b32edb 100644
--- a/config/open_api.yml
+++ b/config/open_api.yml
@@ -83,6 +83,8 @@ metadata:
description: Operations related to metadata of the GitLab instance
- name: metrics_user_starred_dashboards
description: Operations related to User-starred metrics dashboards
+ - name: nuget_packages
+ description: Operations related to Nuget packages
- name: package_files
description: Operations about package files
- name: plan_limits
diff --git a/danger/product_intelligence/Dangerfile b/danger/product_intelligence/Dangerfile
index c38d87604cc..1be549f139f 100644
--- a/danger/product_intelligence/Dangerfile
+++ b/danger/product_intelligence/Dangerfile
@@ -1,3 +1,5 @@
# frozen_string_literal: true
product_intelligence.check!
+
+product_intelligence.check_affected_scopes!
diff --git a/doc/administration/geo/replication/troubleshooting.md b/doc/administration/geo/replication/troubleshooting.md
index fa668091c90..f794ea6745f 100644
--- a/doc/administration/geo/replication/troubleshooting.md
+++ b/doc/administration/geo/replication/troubleshooting.md
@@ -204,7 +204,7 @@ Commands that change data can cause damage if not run correctly or under the rig
```
1. This will cause the primary to start checksumming all Uploads.
-1. When a primary successfully checksums a record, then all secondaries rechecksum as well, and they compare the values.
+1. When a primary successfully checksums a record, then all secondaries recalculate the checksum as well, and they compare the values.
A similar thing can be done for all Models handled by the [Geo Self-Service Framework](../../../development/geo/framework.md) which have implemented verification:
@@ -1335,7 +1335,7 @@ status
```
1. This will cause the primary to start checksumming all Uploads.
-1. When a primary successfully checksums a record, then all secondaries rechecksum as well, and they compare the values.
+1. When a primary successfully checksums a record, then all secondaries recalculate the checksum as well, and they compare the values.
For other SSF data types replace `Upload` in the command above with the desired model class.
diff --git a/doc/development/documentation/styleguide/index.md b/doc/development/documentation/styleguide/index.md
index 93b2e33e11c..a000fd0fbd0 100644
--- a/doc/development/documentation/styleguide/index.md
+++ b/doc/development/documentation/styleguide/index.md
@@ -345,6 +345,19 @@ Some contractions, however, should be avoided:
<!-- vale gitlab.Possessive = YES -->
+### Prepositions
+
+Use prepositions at the end of the sentence when needed.
+Dangling or stranded prepositions are fine. For example:
+
+- You can leave the group you're a member of.
+- Share the credentials with users you want to give access to.
+
+These constructions are more casual than the alternatives:
+
+- You can leave the group of which you're a member.
+- Share the credentials with users to which you want to give access.
+
### Acronyms
If you use an acronym, spell it out on first use on a page. You do not need to spell it out more than once on a page.
diff --git a/doc/development/documentation/styleguide/word_list.md b/doc/development/documentation/styleguide/word_list.md
index 09240e63617..1a012051960 100644
--- a/doc/development/documentation/styleguide/word_list.md
+++ b/doc/development/documentation/styleguide/word_list.md
@@ -1177,6 +1177,11 @@ Always follow these words with a noun. For example:
- Use: **Those settings** need to be configured. (Or even better, **Configure those settings.**)
- Instead of: **Those** need to be configured.
+## to which, of which
+
+Try to avoid **to which** and **of which**, and let the preposition dangle at the end of the sentence instead.
+For examples, see [Prepositions](index.md#prepositions).
+
## to-do item
Use lowercase and hyphenate **to-do** item. ([Vale](../testing.md#vale) rule: [`ToDo.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/.vale/gitlab/ToDo.yml))
diff --git a/doc/user/packages/conan_repository/index.md b/doc/user/packages/conan_repository/index.md
index 3d3fe35fd65..dd6605c2f01 100644
--- a/doc/user/packages/conan_repository/index.md
+++ b/doc/user/packages/conan_repository/index.md
@@ -270,8 +270,9 @@ Prerequisites:
```
NOTE:
-If you try to install the package you just created in this tutorial, the package
-already exists on your local computer, so this command has no effect.
+If you try installing the package you created in this tutorial, the install command
+will have no effect because the package already exists.
+Delete `~/.conan/data` to clean up the packages stored in the cache.
## Remove a Conan package
diff --git a/doc/user/packages/container_registry/index.md b/doc/user/packages/container_registry/index.md
index 296bb9ece39..f71a9030630 100644
--- a/doc/user/packages/container_registry/index.md
+++ b/doc/user/packages/container_registry/index.md
@@ -9,7 +9,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
> Searching by image repository name was [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/31322) in GitLab 13.0.
NOTE:
-If you pull container images from Docker Hub, you can use the [GitLab Dependency Proxy](../dependency_proxy/index.md#use-the-dependency-proxy-for-docker-images)
+If you pull container images from Docker Hub, you can use the [GitLab Dependency Proxy](../dependency_proxy/index.md#use-the-dependency-proxy-for-docker-images)
to avoid rate limits and speed up your pipelines.
With the Docker Container Registry integrated into GitLab, every GitLab project can
@@ -32,6 +32,7 @@ You can search, sort, filter, and [delete](#delete-images-using-the-gitlab-ui)
containers on this page. You can share a filtered view by copying the URL from your browser.
Only members of the project or group can access a private project's Container Registry.
+Images downloaded from a private registry may be [available to other users in a shared runner](https://docs.gitlab.com/runner/security/index.html#usage-of-private-docker-images-with-if-not-present-pull-policy).
If a project is public, so is the Container Registry.
diff --git a/doc/user/packages/package_registry/index.md b/doc/user/packages/package_registry/index.md
index 8e160cbb195..65ff715a4ee 100644
--- a/doc/user/packages/package_registry/index.md
+++ b/doc/user/packages/package_registry/index.md
@@ -118,18 +118,22 @@ determine actions such as downloading, pushing, or deleting packages.
The visibility of the Package Registry is independent of the repository and can't be controlled from
your project's settings. For example, if you have a public project and set the repository visibility
-to **Only Project Members**, the Package Registry is then public. However, disabling the Package
+to **Only Project Members**, the Package Registry is then public. Disabling the Package
Registry disables all Package Registry operations.
-[GitLab-#329253](https://gitlab.com/gitlab-org/gitlab/-/issues/329253)
-proposes adding the ability to control Package Registry visibility from the UI.
-
-| | | Anonymous<br/>(everyone on internet) | Guest | Reporter, Developer, Maintainer, Owner |
-| -------------------- | --------------------- | --------- | ----- | ------------------------------------------ |
-| Public project with Package Registry enabled | View Package Registry <br/> and pull packages | Yes | Yes | Yes |
-| Internal project with Package Registry enabled | View Package Registry <br/> and pull packages | No | Yes | Yes |
-| Private project with Package Registry enabled | View Package Registry <br/> and pull packages | No | No | Yes |
-| Any project with Package Registry disabled | All operations on Package Registry | No | No | No |
+| Project visibility | Action | [Role](../../permissions.md#roles) required |
+| ---- | ---- | ---- |
+| Public | View Package Registry | `n/a`, everyone on the internet can perform this action |
+| Public | Publish a package | Developer or higher |
+| Public | Pull a package | `n/a`, everyone on the internet can perform this action |
+| Internal | View Package Registry | Guest or higher |
+| Internal | Publish a package | Developer or higher |
+| Internal | Pull a package | Guest or higher(1) |
+| Private | View Package Registry | Reporter or higher |
+| Private | Publish a package | Developer or higher |
+| Private | Pull a package | Reporter or higher(1) |
+
+1. [GitLab-#329253](https://gitlab.com/gitlab-org/gitlab/-/issues/329253) proposes adding a setting to allow anyone (everyone on the internet) to pull from the Package Registry, no matter what the project visibility is.
## Supported package managers
diff --git a/doc/user/permissions.md b/doc/user/permissions.md
index 3c9f1544158..d70a1a4ba1d 100644
--- a/doc/user/permissions.md
+++ b/doc/user/permissions.md
@@ -342,7 +342,7 @@ This table shows granted privileges for jobs triggered by specific types of user
| Push source and LFS | | | | |
1. Only if the triggering user is not an external one.
-1. Only if the triggering user is a member of the project.
+1. Only if the triggering user is a member of the project. See also [Usage of private Docker images with `if-not-present` pull policy](http://docs.gitlabl.com/runner/security/index.html#usage-of-private-docker-images-with-if-not-present-pull-policy).
### Wiki and issues
diff --git a/doc/user/project/merge_requests/approvals/settings.md b/doc/user/project/merge_requests/approvals/settings.md
index a2a12b22c3b..a8acab3898b 100644
--- a/doc/user/project/merge_requests/approvals/settings.md
+++ b/doc/user/project/merge_requests/approvals/settings.md
@@ -21,22 +21,24 @@ To view or edit merge request approval settings:
### Approval settings
-These settings limit who can approve merge requests.
-
-| Setting | Description |
-| ------ | ------ |
-| [Prevent approval by author](#prevent-approval-by-author) | When enabled, the author of a merge request cannot approve it. |
-| [Prevent approvals by users who add commits](#prevent-approvals-by-users-who-add-commits) | When enabled, users who have committed to a merge request cannot approve it. |
-| [Prevent editing approval rules in merge requests](#prevent-editing-approval-rules-in-merge-requests) | When enabled, users can't override the project's approval rules on merge requests. |
-| [Require user password to approve](#require-user-password-to-approve) | Force potential approvers to first authenticate with a password. |
-
-You can further define what happens to existing approvals when commits are added to the merge request.
-
-| Setting | Description |
-| ------ | ------ |
-| Keep approvals | Do not remove approvals. |
-| [Remove all approvals](#remove-all-approvals-when-commits-are-added-to-the-source-branch) | Remove all existing approvals. |
-| [Remove approvals by Code Owners if their files changed](#remove-approvals-by-code-owners-if-their-files-changed) | If a Code Owner has approved the merge request, and the commit changes files they are the Code Owner for, their approval is removed. |
+These settings limit who can approve merge requests:
+
+- [**Prevent approval by author**](#prevent-approval-by-author):
+ Prevents the author of a merge request from approving it.
+- [**Prevent approvals by users who add commits**](#prevent-approvals-by-users-who-add-commits):
+ Prevents users who add commits to a merge request from also approving it.
+- [**Prevent editing approval rules in merge requests**](#prevent-editing-approval-rules-in-merge-requests):
+ Prevents users from overriding project level approval rules on merge requests.
+- [**Require user password to approve**](#require-user-password-to-approve):
+ Force potential approvers to first authenticate with a password.
+- Code Owner approval removals: Define what happens to existing approvals when
+ commits are added to the merge request.
+ - **Keep approvals**: Do not remove any approvals.
+ - [**Remove all approvals**](#remove-all-approvals-when-commits-are-added-to-the-source-branch):
+ Remove all existing approvals.
+ - [**Remove approvals by Code Owners if their files changed**](#remove-approvals-by-code-owners-if-their-files-changed):
+ If a Code Owner approves a merge request, and a later commit changes files
+ they are a Code Owner for, their approval is removed.
## Prevent approval by author
diff --git a/doc/user/project/merge_requests/methods/index.md b/doc/user/project/merge_requests/methods/index.md
index e72c927198e..249a98f1779 100644
--- a/doc/user/project/merge_requests/methods/index.md
+++ b/doc/user/project/merge_requests/methods/index.md
@@ -10,47 +10,107 @@ type: reference, concepts
The merge method you select for your project determines how the changes in your
merge requests are merged into an existing branch.
+The examples on this page assume a `main` branch with commits A, C, and E, and a
+`feature` branch with commits B and D:
+
+```mermaid
+gitGraph
+ commit id: "A"
+ branch feature
+ commit id: "B"
+ commit id: "D"
+ checkout main
+ commit id: "C"
+ commit id: "E"
+```
+
## Configure a project's merge method
1. On the top bar, select **Main menu > Projects** and find your project.
1. On the left sidebar, select **Settings > Merge requests**.
-1. In the **Merge method** section, select your desired merge method.
+1. Select your desired **Merge method** from these options:
+ - Merge commit
+ - Merge commit with semi-linear history
+ - Fast-forward merge
+1. In **Squash commits when merging**, select the default behavior for handling commits:
+ - **Do not allow**: Squashing is never performed, and the user cannot change the behavior.
+ - **Allow**: Squashing is off by default, but the user can change the behavior.
+ - **Encourage**: Squashing is on by default, but the user can change the behavior.
+ - **Require**: Squashing is always performed, and the user cannot change the behavior.
1. Select **Save changes**.
## Merge commit
-This setting is the default. It always creates a separate merge commit,
-even when using [squash](../squash_and_merge.md). An example commit graph generated using this merge method:
+By default, GitLab creates a merge commit when a branch is merged into `main`.
+A separate merge commit is always created, regardless of whether or not commits
+are [squashed when merging](../squash_and_merge.md). This strategy can result
+in both a squash commit and a merge commit being added to your `main` branch.
+
+These diagrams show how the `feature` branch merges into `main` if you use the
+**Merge commit** strategy. They are equivalent to the command `git merge --no-ff <feature>`,
+and selecting `Merge commit` as the **Merge method** in the GitLab UI:
+
+The merge strategy:
```mermaid
+%%{init: { 'gitGraph': {'logLevel': 'debug', 'showBranches': true, 'showCommitLabel':true,'mainBranchName': 'main'}} }%%
gitGraph
- commit id: "Init"
- branch mr-branch-1
- commit
- checkout main
- commit
- branch mr-branch-2
- commit
- checkout mr-branch-1
- commit
- checkout main
- branch squash-mr
- commit id: "Squashed commits"
- checkout main
- merge squash-mr
- merge mr-branch-1
- commit
- merge mr-branch-2
+ commit id: "A"
+ branch feature
+ commit id: "B"
+ commit id: "D"
+ checkout main
+ commit id: "C"
+ commit id: "E"
+ merge feature
+```
+
+After a feature branch is merged with the **Merge commit** method, your `main` branch
+looks like this:
+
+```mermaid
+%%{init: { 'gitGraph': {'logLevel': 'debug', 'showBranches': true, 'showCommitLabel':true,'mainBranchName': 'main'}} }%%
+gitGraph
+ commit id: "A"
+ commit id: "C"
+ commit id: "E"
+ commit id: "squash commit"
+ commit id: "merge commit"
```
-- For regular merges, it is equivalent to the command `git merge --no-ff <source-branch>`.
-- For squash merges, it squashes all commits in the source branch before merging it normally. It performs actions similar to:
+In comparison, a **squash merge** constructs a squash commit, a virtual copy of all commits
+from the `feature` branch. The original commits (B and D) remain unchanged
+on the `feature` branch, and the squash commit is placed on the `main` branch:
+
+```mermaid
+%%{init: { 'gitGraph': {'showBranches': true, 'showCommitLabel':true,'mainBranchName': 'main'}} }%%
+gitGraph
+ commit id:"A"
+ branch feature
+ checkout main
+ commit id:"C"
+ checkout feature
+ commit id:"B"
+ commit id:"D"
+ checkout main
+ commit id:"E"
+ commit id:"squash commit" type: HIGHLIGHT
+```
+
+The squash merge graph is equivalent to these settings in the GitLab UI:
+
+- **Merge method**: Merge commit.
+- **Squash commits when merging** should be set to either:
+ - Require.
+ - Either Allow or Encourage, and squashing must be selected on the merge request.
+
+The squash merge graph is also equivalent to these commands:
```shell
- git checkout `git merge-base <source-branch> <target-branch>`
- git merge --squash <source-branch>
+ git checkout `git merge-base feature main`
+ git merge --squash <feature>
SOURCE_SHA=`git rev-parse HEAD`
- git checkout <target-branch>
+ git checkout <main>
git merge --no-ff $SOURCE_SHA
```
@@ -58,7 +118,8 @@ gitGraph
A merge commit is created for every merge, but the branch is only merged if
a fast-forward merge is possible. This ensures that if the merge request build
-succeeded, the target branch build also succeeds after the merge. An example commit graph generated using this merge method:
+succeeded, the target branch build also succeeds after the merge. An example
+commit graph generated using this merge method:
```mermaid
gitGraph
@@ -113,8 +174,8 @@ This method is equivalent to `git merge --ff <source-branch>` for regular merges
When the fast-forward merge
([`--ff-only`](https://git-scm.com/docs/git-merge#git-merge---ff-only)) setting
-is enabled, no merge commits are created and all merges are fast-forwarded,
-which means that merging is only allowed if the branch can be fast-forwarded.
+is enabled, no merge commits are created and all merges are fast-forwarded.
+Merging is only allowed if the branch can be fast-forwarded.
When a fast-forward merge is not possible, the user is given the option to rebase, see
[Rebasing in (semi-)linear merge methods](#rebasing-in-semi-linear-merge-methods).
@@ -136,11 +197,16 @@ In these merge methods, you can merge only when your source branch is up-to-date
- Fast-forward merge.
If a fast-forward merge is not possible but a conflict-free rebase is possible,
-GitLab offers you the [`/rebase` quick action](../../../../topics/git/git_rebase.md#rebase-from-the-gitlab-ui),
-and the ability to select **Rebase** from the user interface.
+GitLab provides:
+
+- The [`/rebase` quick action](../../../../topics/git/git_rebase.md#rebase-from-the-gitlab-ui).
+- The option to select **Rebase** in the user interface.
+
+You must rebase the source branch locally before a fast-forward merge if both
+conditions are true:
-If the target branch is ahead of the source branch and a conflict-free rebase is
-not possible, you must rebase the source branch locally before you can do a fast-forward merge.
+- The target branch is ahead of the source branch.
+- A conflict-free rebase is not possible.
![Fast forward merge rebase locally](../img/ff_merge_rebase_locally.png)
diff --git a/lib/api/api.rb b/lib/api/api.rb
index 46d0aa3d19d..6d4d94caaa9 100644
--- a/lib/api/api.rb
+++ b/lib/api/api.rb
@@ -236,6 +236,7 @@ module API
mount ::API::Metrics::Dashboard::Annotations
mount ::API::Metrics::UserStarredDashboards
mount ::API::Namespaces
+ mount ::API::NugetGroupPackages
mount ::API::PackageFiles
mount ::API::Pages
mount ::API::PersonalAccessTokens::SelfInformation
@@ -310,7 +311,6 @@ module API
mount ::API::NotificationSettings
mount ::API::NpmInstancePackages
mount ::API::NpmProjectPackages
- mount ::API::NugetGroupPackages
mount ::API::NugetProjectPackages
mount ::API::PagesDomains
mount ::API::ProjectContainerRepositories
diff --git a/lib/api/concerns/packages/nuget_endpoints.rb b/lib/api/concerns/packages/nuget_endpoints.rb
index e0328e488c6..9654200f4d6 100644
--- a/lib/api/concerns/packages/nuget_endpoints.rb
+++ b/lib/api/concerns/packages/nuget_endpoints.rb
@@ -55,6 +55,13 @@ module API
# https://docs.microsoft.com/en-us/nuget/api/service-index
desc 'The NuGet Service Index' do
detail 'This feature was introduced in GitLab 12.6'
+ success code: 200
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not Found' }
+ ]
+ tags %w[nuget_packages]
end
get 'index', format: :json, urgency: :default do
authorize_read_package!(project_or_group)
@@ -67,7 +74,7 @@ module API
# https://docs.microsoft.com/en-us/nuget/api/registration-base-url-resource
params do
- requires :package_name, type: String, desc: 'The NuGet package name', regexp: API::NO_SLASH_URL_PART_REGEX
+ requires :package_name, type: String, desc: 'The NuGet package name', regexp: API::NO_SLASH_URL_PART_REGEX, documentation: { example: 'MyNuGetPkg' }
end
namespace '/metadata/*package_name' do
after_validation do
@@ -76,6 +83,13 @@ module API
desc 'The NuGet Metadata Service - Package name level' do
detail 'This feature was introduced in GitLab 12.8'
+ success code: 200
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not Found' }
+ ]
+ tags %w[nuget_packages]
end
get 'index', format: :json, urgency: :low do
present ::Packages::Nuget::PackagesMetadataPresenter.new(find_packages(params[:package_name])),
@@ -84,9 +98,16 @@ module API
desc 'The NuGet Metadata Service - Package name and version level' do
detail 'This feature was introduced in GitLab 12.8'
+ success code: 200
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not Found' }
+ ]
+ tags %w[nuget_packages]
end
params do
- requires :package_version, type: String, desc: 'The NuGet package version', regexp: API::NO_SLASH_URL_PART_REGEX
+ requires :package_version, type: String, desc: 'The NuGet package version', regexp: API::NO_SLASH_URL_PART_REGEX, documentation: { example: '1.0.0' }
end
get '*package_version', format: :json, urgency: :low do
present ::Packages::Nuget::PackageMetadataPresenter.new(find_package(params[:package_name], params[:package_version])),
@@ -96,9 +117,9 @@ module API
# https://docs.microsoft.com/en-us/nuget/api/search-query-service-resource
params do
- optional :q, type: String, desc: 'The search term'
- optional :skip, type: Integer, desc: 'The number of results to skip', default: 0, regexp: NON_NEGATIVE_INTEGER_REGEX
- optional :take, type: Integer, desc: 'The number of results to return', default: Kaminari.config.default_per_page, regexp: POSITIVE_INTEGER_REGEX
+ optional :q, type: String, desc: 'The search term', documentation: { example: 'MyNuGet' }
+ optional :skip, type: Integer, desc: 'The number of results to skip', default: 0, regexp: NON_NEGATIVE_INTEGER_REGEX, documentation: { example: 1 }
+ optional :take, type: Integer, desc: 'The number of results to return', default: Kaminari.config.default_per_page, regexp: POSITIVE_INTEGER_REGEX, documentation: { example: 1 }
optional :prerelease, type: ::Grape::API::Boolean, desc: 'Include prerelease versions', default: true
end
namespace '/query' do
@@ -108,6 +129,13 @@ module API
desc 'The NuGet Search Service' do
detail 'This feature was introduced in GitLab 12.8'
+ success code: 200
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not Found' }
+ ]
+ tags %w[nuget_packages]
end
get format: :json, urgency: :low do
search_options = {
diff --git a/lib/api/nuget_group_packages.rb b/lib/api/nuget_group_packages.rb
index eb55e4cbf70..c93b24ee544 100644
--- a/lib/api/nuget_group_packages.rb
+++ b/lib/api/nuget_group_packages.rb
@@ -45,7 +45,7 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a group', regexp: ::API::Concerns::Packages::NugetEndpoints::POSITIVE_INTEGER_REGEX
+ requires :id, types: [Integer, String], desc: 'The group ID or full group path.', regexp: ::API::Concerns::Packages::NugetEndpoints::POSITIVE_INTEGER_REGEX
end
resource :groups, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
diff --git a/lib/bulk_imports/clients/http.rb b/lib/bulk_imports/clients/http.rb
index 4c36f226006..8129ff6151c 100644
--- a/lib/bulk_imports/clients/http.rb
+++ b/lib/bulk_imports/clients/http.rb
@@ -55,20 +55,11 @@ module BulkImports
end
def instance_version
- strong_memoize(:instance_version) do
- response = begin
- with_error_handling do
- Gitlab::HTTP.get(resource_url(:version), default_options)
- end
- rescue BulkImports::NetworkError
- # `version` endpoint is not available, try `metadata` endpoint instead
- with_error_handling do
- Gitlab::HTTP.get(resource_url(:metadata), default_options)
- end
- end
+ Gitlab::VersionInfo.parse(metadata['version'])
+ end
- Gitlab::VersionInfo.parse(response.parsed_response['version'])
- end
+ def instance_enterprise
+ Gitlab::Utils.to_boolean(metadata['enterprise'], default: true)
end
def compatible_for_project_migration?
@@ -87,6 +78,22 @@ module BulkImports
end
end
+ def metadata
+ response = begin
+ with_error_handling do
+ Gitlab::HTTP.get(resource_url(:version), default_options)
+ end
+ rescue BulkImports::NetworkError
+ # `version` endpoint is not available, try `metadata` endpoint instead
+ with_error_handling do
+ Gitlab::HTTP.get(resource_url(:metadata), default_options)
+ end
+ end
+
+ response.parsed_response
+ end
+ strong_memoize_attr :metadata
+
# rubocop:disable GitlabSecurity/PublicSend
def request(method, resource, options = {}, &block)
validate_instance_version!
diff --git a/lib/bulk_imports/groups/stage.rb b/lib/bulk_imports/groups/stage.rb
index 6928ce43191..0db2b1f0698 100644
--- a/lib/bulk_imports/groups/stage.rb
+++ b/lib/bulk_imports/groups/stage.rb
@@ -21,7 +21,7 @@ module BulkImports
# instance version is 15.2.0, 15.2.1, 16.0.0, etc.
def config
- @config ||= {
+ {
group: {
pipeline: BulkImports::Groups::Pipelines::GroupPipeline,
stage: 0
diff --git a/lib/bulk_imports/projects/stage.rb b/lib/bulk_imports/projects/stage.rb
index 2fefdb9055e..73e102696fa 100644
--- a/lib/bulk_imports/projects/stage.rb
+++ b/lib/bulk_imports/projects/stage.rb
@@ -21,7 +21,7 @@ module BulkImports
# instance version is 15.2.0, 15.2.1, 16.0.0, etc.
def config
- @config ||= {
+ {
project: {
pipeline: BulkImports::Projects::Pipelines::ProjectPipeline,
stage: 0
diff --git a/lib/bulk_imports/stage.rb b/lib/bulk_imports/stage.rb
index b45ac139385..5c622db3b01 100644
--- a/lib/bulk_imports/stage.rb
+++ b/lib/bulk_imports/stage.rb
@@ -19,6 +19,8 @@ module BulkImports
private
+ attr_reader :bulk_import, :bulk_import_entity
+
def config
# To be implemented in a sub-class
NotImplementedError
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 0bfabf00780..efbd93fcbbc 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -31225,6 +31225,9 @@ msgstr ""
msgid "ProductAnalytics|Add to Dashboard"
msgstr ""
+msgid "ProductAnalytics|An error occured while loading the %{widgetTitle} widget."
+msgstr ""
+
msgid "ProductAnalytics|Audience"
msgstr ""
@@ -31234,9 +31237,6 @@ msgstr ""
msgid "ProductAnalytics|There is no data for this type of chart currently. Please see the Setup tab if you have not configured the product analytics tool already."
msgstr ""
-msgid "ProductAnalytics|Widgets content"
-msgstr ""
-
msgid "Productivity"
msgstr ""
@@ -45024,6 +45024,12 @@ msgstr ""
msgid "Version %{versionNumber} (latest)"
msgstr ""
+msgid "VersionCheck|Critical security upgrade available"
+msgstr ""
+
+msgid "VersionCheck|Learn more about this critical security release."
+msgstr ""
+
msgid "VersionCheck|Up to date"
msgstr ""
@@ -45033,6 +45039,12 @@ msgstr ""
msgid "VersionCheck|Update available"
msgstr ""
+msgid "VersionCheck|Upgrade now"
+msgstr ""
+
+msgid "VersionCheck|You are currently on version %{currentVersion}. We strongly recommend upgrading your GitLab installation. %{link}"
+msgstr ""
+
msgid "VersionCheck|Your GitLab Version"
msgstr ""
diff --git a/package.json b/package.json
index 5d0ad0226ba..a85dd77a0ad 100644
--- a/package.json
+++ b/package.json
@@ -51,6 +51,7 @@
"@babel/core": "^7.18.5",
"@babel/preset-env": "^7.18.2",
"@codesandbox/sandpack-client": "^1.2.2",
+ "@cubejs-client/core": "^0.31.0",
"@gitlab/at.js": "1.5.7",
"@gitlab/favicon-overlay": "2.0.0",
"@gitlab/svgs": "3.11.0",
diff --git a/spec/factories/bulk_import.rb b/spec/factories/bulk_import.rb
index 748afc0c67c..54d05264269 100644
--- a/spec/factories/bulk_import.rb
+++ b/spec/factories/bulk_import.rb
@@ -5,6 +5,7 @@ FactoryBot.define do
user
source_type { :gitlab }
source_version { BulkImport.min_gl_version_for_project_migration.to_s }
+ source_enterprise { false }
trait :created do
status { 0 }
diff --git a/spec/features/projects/settings/repository_settings_spec.rb b/spec/features/projects/settings/repository_settings_spec.rb
index d73ff0284cd..cb11c6fdbb4 100644
--- a/spec/features/projects/settings/repository_settings_spec.rb
+++ b/spec/features/projects/settings/repository_settings_spec.rb
@@ -273,7 +273,12 @@ RSpec.describe 'Projects > Settings > Repository settings' do
end
end
- expect(page).to have_content('Repository cleanup has started')
+ # TODO: The following line is skipped because a toast with
+ # "An error occurred while loading branch rules. Please try again."
+ # shows up right after which hides the below message. It is causing flakiness.
+ # https://gitlab.com/gitlab-org/gitlab/-/issues/383717#note_1185091998
+
+ # expect(page).to have_content('Repository cleanup has started')
expect(RepositoryCleanupWorker.jobs.count).to eq(1)
end
end
diff --git a/spec/frontend/gitlab_version_check/components/security_patch_upgrade_alert_spec.js b/spec/frontend/gitlab_version_check/components/security_patch_upgrade_alert_spec.js
new file mode 100644
index 00000000000..665dacd5c47
--- /dev/null
+++ b/spec/frontend/gitlab_version_check/components/security_patch_upgrade_alert_spec.js
@@ -0,0 +1,84 @@
+import { GlAlert, GlButton, GlLink, GlSprintf } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import { mockTracking, unmockTracking } from 'helpers/tracking_helper';
+import SecurityPatchUpgradeAlert from '~/gitlab_version_check/components/security_patch_upgrade_alert.vue';
+import { UPGRADE_DOCS_URL, ABOUT_RELEASES_PAGE } from '~/gitlab_version_check/constants';
+
+describe('SecurityPatchUpgradeAlert', () => {
+ let wrapper;
+ let trackingSpy;
+
+ const defaultProps = {
+ currentVersion: '99.9',
+ };
+
+ const createComponent = () => {
+ trackingSpy = mockTracking(undefined, undefined, jest.spyOn);
+
+ wrapper = shallowMount(SecurityPatchUpgradeAlert, {
+ propsData: {
+ ...defaultProps,
+ },
+ stubs: {
+ GlAlert,
+ GlSprintf,
+ },
+ });
+ };
+
+ afterEach(() => {
+ unmockTracking();
+ });
+
+ const findGlAlert = () => wrapper.findComponent(GlAlert);
+ const findGlButton = () => wrapper.findComponent(GlButton);
+ const findGlLink = () => wrapper.findComponent(GlLink);
+
+ describe('template', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('renders non-dismissible GlAlert with version information', () => {
+ expect(findGlAlert().text()).toContain(
+ `You are currently on version ${defaultProps.currentVersion}.`,
+ );
+ expect(findGlAlert().props('dismissible')).toBe(false);
+ });
+
+ it('tracks render security_patch_upgrade_alert correctly', () => {
+ expect(trackingSpy).toHaveBeenCalledWith(undefined, 'render', {
+ label: 'security_patch_upgrade_alert',
+ property: defaultProps.currentVersion,
+ });
+ });
+
+ it('renders GlLink with correct text and link', () => {
+ expect(findGlLink().text()).toBe('Learn more about this critical security release.');
+ expect(findGlLink().attributes('href')).toBe(ABOUT_RELEASES_PAGE);
+ });
+
+ it('tracks click security_patch_upgrade_alert_learn_more when link is clicked', async () => {
+ await findGlLink().vm.$emit('click');
+
+ expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_link', {
+ label: 'security_patch_upgrade_alert_learn_more',
+ property: defaultProps.currentVersion,
+ });
+ });
+
+ it('renders GlButton with correct text and link', () => {
+ expect(findGlButton().text()).toBe('Upgrade now');
+ expect(findGlButton().attributes('href')).toBe(UPGRADE_DOCS_URL);
+ });
+
+ it('tracks click security_patch_upgrade_alert_upgrade_now when button is clicked', async () => {
+ await findGlButton().vm.$emit('click');
+
+ expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_link', {
+ label: 'security_patch_upgrade_alert_upgrade_now',
+ property: defaultProps.currentVersion,
+ });
+ });
+ });
+});
diff --git a/spec/frontend/gitlab_version_check/index_spec.js b/spec/frontend/gitlab_version_check/index_spec.js
index a0a77766872..9e4d50f2cfb 100644
--- a/spec/frontend/gitlab_version_check/index_spec.js
+++ b/spec/frontend/gitlab_version_check/index_spec.js
@@ -5,6 +5,11 @@ import {
VERSION_CHECK_BADGE_NO_PROP_FIXTURE,
VERSION_CHECK_BADGE_NO_SEVERITY_FIXTURE,
VERSION_CHECK_BADGE_FIXTURE,
+ VERSION_CHECK_BADGE_FINDER,
+ VERSION_BADGE_TEXT,
+ SECURITY_PATCH_FIXTURE,
+ SECURITY_PATCH_FINDER,
+ SECURITY_BATCH_TEXT,
} from './mock_data';
describe('initGitlabVersionCheck', () => {
@@ -20,21 +25,25 @@ describe('initGitlabVersionCheck', () => {
});
describe.each`
- description | fixture | badgeTexts
- ${'with no version check badge el'} | ${'<div></div>'} | ${[]}
- ${'with version check badge el but no prop data'} | ${VERSION_CHECK_BADGE_NO_PROP_FIXTURE} | ${[undefined]}
- ${'with version check badge el but no severity data'} | ${VERSION_CHECK_BADGE_NO_SEVERITY_FIXTURE} | ${[undefined]}
- ${'with version check badge el and version data'} | ${VERSION_CHECK_BADGE_FIXTURE} | ${['Up to date']}
- `('$description', ({ fixture, badgeTexts }) => {
+ description | fixture | finders | componentTexts
+ ${'with no version check elements'} | ${'<div></div>'} | ${[]} | ${[]}
+ ${'with version check badge el but no prop data'} | ${VERSION_CHECK_BADGE_NO_PROP_FIXTURE} | ${[VERSION_CHECK_BADGE_FINDER]} | ${[undefined]}
+ ${'with version check badge el but no severity data'} | ${VERSION_CHECK_BADGE_NO_SEVERITY_FIXTURE} | ${[VERSION_CHECK_BADGE_FINDER]} | ${[undefined]}
+ ${'with version check badge el and version data'} | ${VERSION_CHECK_BADGE_FIXTURE} | ${[VERSION_CHECK_BADGE_FINDER]} | ${[VERSION_BADGE_TEXT]}
+ ${'with security patch el'} | ${SECURITY_PATCH_FIXTURE} | ${[SECURITY_PATCH_FINDER]} | ${[SECURITY_BATCH_TEXT]}
+ ${'with security patch and version badge els'} | ${`${SECURITY_PATCH_FIXTURE}${VERSION_CHECK_BADGE_FIXTURE}`} | ${[SECURITY_PATCH_FINDER, VERSION_CHECK_BADGE_FINDER]} | ${[SECURITY_BATCH_TEXT, VERSION_BADGE_TEXT]}
+ `('$description', ({ fixture, finders, componentTexts }) => {
beforeEach(() => {
createApp(fixture);
});
- it(`correctly renders the Version Check Badge`, () => {
+ it(`correctly renders the Version Check Components`, () => {
const vueAppInstances = vueApps.map((v) => v && createWrapper(v));
- const renderedBadgeTexts = vueAppInstances.map((i) => i?.text());
+ const renderedComponentTexts = vueAppInstances.map((v, index) =>
+ v?.find(finders[index]).text(),
+ );
- expect(renderedBadgeTexts).toStrictEqual(badgeTexts);
+ expect(renderedComponentTexts).toStrictEqual(componentTexts);
});
});
});
diff --git a/spec/frontend/gitlab_version_check/mock_data.js b/spec/frontend/gitlab_version_check/mock_data.js
index 826ab35dd7b..6f2107f4d3c 100644
--- a/spec/frontend/gitlab_version_check/mock_data.js
+++ b/spec/frontend/gitlab_version_check/mock_data.js
@@ -4,3 +4,13 @@ export const VERSION_CHECK_BADGE_NO_PROP_FIXTURE =
export const VERSION_CHECK_BADGE_NO_SEVERITY_FIXTURE = `<div class="js-gitlab-version-check-badge" data-version='{ "size": "sm" }'></div>`;
export const VERSION_CHECK_BADGE_FIXTURE = `<div class="js-gitlab-version-check-badge" data-version='{ "severity": "success" }'></div>`;
+
+export const VERSION_CHECK_BADGE_FINDER = '[data-testid="badge-click-wrapper"]';
+
+export const VERSION_BADGE_TEXT = 'Up to date';
+
+export const SECURITY_PATCH_FIXTURE = `<div id="js-security-patch-upgrade-alert" data-current-version="15.1"></div>`;
+
+export const SECURITY_PATCH_FINDER = 'h2';
+
+export const SECURITY_BATCH_TEXT = 'Critical security upgrade available';
diff --git a/spec/helpers/version_check_helper_spec.rb b/spec/helpers/version_check_helper_spec.rb
index e7936adde2d..2bb85e7b6b8 100644
--- a/spec/helpers/version_check_helper_spec.rb
+++ b/spec/helpers/version_check_helper_spec.rb
@@ -46,4 +46,30 @@ RSpec.describe VersionCheckHelper do
expect(helper.gitlab_version_check).to eq({ "severity" => "success" })
end
end
+
+ describe '#show_security_patch_upgrade_alert?' do
+ describe 'return conditions' do
+ where(:show_version_check, :gitlab_version_check, :result) do
+ [
+ [false, nil, false],
+ [false, { "severity" => "success" }, false],
+ [false, { "severity" => "danger" }, false],
+ [true, nil, false],
+ [true, { "severity" => "success" }, false],
+ [true, { "severity" => "danger" }, true]
+ ]
+ end
+
+ with_them do
+ before do
+ allow(helper).to receive(:show_version_check?).and_return(show_version_check)
+ allow(helper).to receive(:gitlab_version_check).and_return(gitlab_version_check)
+ end
+
+ it 'returns correct results' do
+ expect(helper.show_security_patch_upgrade_alert?).to eq result
+ end
+ end
+ end
+ end
end
diff --git a/spec/lib/bulk_imports/clients/http_spec.rb b/spec/lib/bulk_imports/clients/http_spec.rb
index 6962a943755..4fb08fc0478 100644
--- a/spec/lib/bulk_imports/clients/http_spec.rb
+++ b/spec/lib/bulk_imports/clients/http_spec.rb
@@ -9,13 +9,23 @@ RSpec.describe BulkImports::Clients::HTTP do
let(:token) { 'token' }
let(:resource) { 'resource' }
let(:version) { "#{BulkImport::MIN_MAJOR_VERSION}.0.0" }
+ let(:enterprise) { false }
let(:response_double) { double(code: 200, success?: true, parsed_response: {}) }
- let(:version_response) { double(code: 200, success?: true, parsed_response: { 'version' => version }) }
+ let(:metadata_response) do
+ double(
+ code: 200,
+ success?: true,
+ parsed_response: {
+ 'version' => version,
+ 'enterprise' => enterprise
+ }
+ )
+ end
before do
allow(Gitlab::HTTP).to receive(:get)
.with('http://gitlab.example/api/v4/version', anything)
- .and_return(version_response)
+ .and_return(metadata_response)
end
subject { described_class.new(url: url, token: token) }
@@ -213,13 +223,27 @@ RSpec.describe BulkImports::Clients::HTTP do
expect(Gitlab::HTTP).to receive(:get)
.with('http://gitlab.example/api/v4/metadata', anything)
- .and_return(version_response)
+ .and_return(metadata_response)
expect(subject.instance_version).to eq(Gitlab::VersionInfo.parse(version))
end
end
end
+ describe '#instance_enterprise' do
+ it 'returns source instance enterprise information' do
+ expect(subject.instance_enterprise).to eq(false)
+ end
+
+ context 'when enterprise information is missing' do
+ let(:enterprise) { nil }
+
+ it 'defaults to true' do
+ expect(subject.instance_enterprise).to eq(true)
+ end
+ end
+ end
+
describe '#compatible_for_project_migration?' do
context 'when instance version is lower the the expected minimum' do
it 'returns false' do
@@ -254,7 +278,7 @@ RSpec.describe BulkImports::Clients::HTTP do
before do
allow(Gitlab::HTTP).to receive(:get)
.with('http://website.example/gitlab/api/v4/version', anything)
- .and_return(version_response)
+ .and_return(metadata_response)
end
it 'performs network request to a relative gitlab url' do
diff --git a/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_namespaces_spec.rb b/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_namespaces_spec.rb
index ac2de43b7c6..c507bce634e 100644
--- a/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_namespaces_spec.rb
+++ b/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_namespaces_spec.rb
@@ -97,39 +97,48 @@ RSpec.describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameNamespa
let(:namespace) { create(:group, name: 'hello-group') }
it 'moves a project for a namespace' do
- create(:project, :repository, :legacy_storage, namespace: namespace, path: 'hello-project')
- expected_path = Gitlab::GitalyClient::StorageSettings.allow_disk_access do
- File.join(TestEnv.repos_path, 'bye-group', 'hello-project.git')
- end
+ project = create(:project, :repository, :legacy_storage, namespace: namespace, path: 'hello-project')
+ expected_repository = Gitlab::Git::Repository.new(
+ project.repository_storage,
+ 'bye-group/hello-project.git',
+ nil,
+ nil
+ )
subject.move_repositories(namespace, 'hello-group', 'bye-group')
- expect(File.directory?(expected_path)).to be(true)
+ expect(expected_repository).to exist
end
it 'moves a namespace in a subdirectory correctly' do
child_namespace = create(:group, name: 'sub-group', parent: namespace)
- create(:project, :repository, :legacy_storage, namespace: child_namespace, path: 'hello-project')
+ project = create(:project, :repository, :legacy_storage, namespace: child_namespace, path: 'hello-project')
- expected_path = Gitlab::GitalyClient::StorageSettings.allow_disk_access do
- File.join(TestEnv.repos_path, 'hello-group', 'renamed-sub-group', 'hello-project.git')
- end
+ expected_repository = Gitlab::Git::Repository.new(
+ project.repository_storage,
+ 'hello-group/renamed-sub-group/hello-project.git',
+ nil,
+ nil
+ )
subject.move_repositories(child_namespace, 'hello-group/sub-group', 'hello-group/renamed-sub-group')
- expect(File.directory?(expected_path)).to be(true)
+ expect(expected_repository).to exist
end
it 'moves a parent namespace with subdirectories' do
child_namespace = create(:group, name: 'sub-group', parent: namespace)
- create(:project, :repository, :legacy_storage, namespace: child_namespace, path: 'hello-project')
- expected_path = Gitlab::GitalyClient::StorageSettings.allow_disk_access do
- File.join(TestEnv.repos_path, 'renamed-group', 'sub-group', 'hello-project.git')
- end
+ project = create(:project, :repository, :legacy_storage, namespace: child_namespace, path: 'hello-project')
+ expected_repository = Gitlab::Git::Repository.new(
+ project.repository_storage,
+ 'renamed-group/sub-group/hello-project.git',
+ nil,
+ nil
+ )
subject.move_repositories(child_namespace, 'hello-group', 'renamed-group')
- expect(File.directory?(expected_path)).to be(true)
+ expect(expected_repository).to exist
end
end
@@ -175,14 +184,17 @@ RSpec.describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameNamespa
describe '#rename_namespace_dependencies' do
it "moves the repository for a project in the namespace" do
- create(:project, :repository, :legacy_storage, namespace: namespace, path: "the-path-project")
- expected_repo = Gitlab::GitalyClient::StorageSettings.allow_disk_access do
- File.join(TestEnv.repos_path, "the-path0", "the-path-project.git")
- end
+ project = create(:project, :repository, :legacy_storage, namespace: namespace, path: "the-path-project")
+ expected_repository = Gitlab::Git::Repository.new(
+ project.repository_storage,
+ "the-path0/the-path-project.git",
+ nil,
+ nil
+ )
subject.rename_namespace_dependencies(namespace, 'the-path', 'the-path0')
- expect(File.directory?(expected_repo)).to be(true)
+ expect(expected_repository).to exist
end
it "moves the uploads for the namespace" do
@@ -276,9 +288,7 @@ RSpec.describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameNamespa
project.create_repository
subject.rename_namespace(namespace)
- expected_path = Gitlab::GitalyClient::StorageSettings.allow_disk_access do
- File.join(TestEnv.repos_path, 'the-path', 'a-project.git')
- end
+ expected_repository = Gitlab::Git::Repository.new(project.repository_storage, 'the-path/a-project.git', nil, nil)
expect(subject).to receive(:rename_namespace_dependencies)
.with(
@@ -289,7 +299,7 @@ RSpec.describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameNamespa
subject.revert_renames
- expect(File.directory?(expected_path)).to be_truthy
+ expect(expected_repository).to exist
end
it "doesn't break when the namespace was renamed" do
diff --git a/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_projects_spec.rb b/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_projects_spec.rb
index 6292f0246f7..aa2a3329477 100644
--- a/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_projects_spec.rb
+++ b/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_projects_spec.rb
@@ -126,13 +126,16 @@ RSpec.describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameProject
let(:project) { create(:project, :repository, :legacy_storage, path: 'the-path', namespace: known_parent) }
it 'moves the repository for a project' do
- expected_path = Gitlab::GitalyClient::StorageSettings.allow_disk_access do
- File.join(TestEnv.repos_path, 'known-parent', 'new-repo.git')
- end
+ expected_repository = Gitlab::Git::Repository.new(
+ project.repository_storage,
+ 'known-parent/new-repo.git',
+ nil,
+ nil
+ )
subject.move_repository(project, 'known-parent/the-path', 'known-parent/new-repo')
- expect(File.directory?(expected_path)).to be(true)
+ expect(expected_repository).to exist
end
end
@@ -157,9 +160,12 @@ RSpec.describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameProject
project.create_repository
subject.rename_project(project)
- expected_path = Gitlab::GitalyClient::StorageSettings.allow_disk_access do
- File.join(TestEnv.repos_path, 'known-parent', 'the-path.git')
- end
+ expected_repository = Gitlab::Git::Repository.new(
+ project.repository_storage,
+ 'known-parent/the-path.git',
+ nil,
+ nil
+ )
expect(subject).to receive(:move_project_folders)
.with(
@@ -170,7 +176,7 @@ RSpec.describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameProject
subject.revert_renames
- expect(File.directory?(expected_path)).to be_truthy
+ expect(expected_repository).to exist
end
it "doesn't break when the project was renamed" do
diff --git a/spec/requests/api/bulk_imports_spec.rb b/spec/requests/api/bulk_imports_spec.rb
index ad57a370fc5..95279f8d468 100644
--- a/spec/requests/api/bulk_imports_spec.rb
+++ b/spec/requests/api/bulk_imports_spec.rb
@@ -50,6 +50,9 @@ RSpec.describe API::BulkImports do
.to receive(:instance_version)
.and_return(
Gitlab::VersionInfo.new(::BulkImport::MIN_MAJOR_VERSION, ::BulkImport::MIN_MINOR_VERSION_FOR_PROJECT))
+ allow(instance)
+ .to receive(:instance_enterprise)
+ .and_return(false)
end
end
diff --git a/spec/requests/projects/ml/experiments_controller_spec.rb b/spec/requests/projects/ml/experiments_controller_spec.rb
index 67a2fe47dc8..9aaf28f2df6 100644
--- a/spec/requests/projects/ml/experiments_controller_spec.rb
+++ b/spec/requests/projects/ml/experiments_controller_spec.rb
@@ -17,7 +17,7 @@ RSpec.describe Projects::Ml::ExperimentsController do
let(:params) { basic_params }
let(:ff_value) { true }
- let(:threshold) { 4 }
+ let(:threshold) { 5 }
let(:project) { project_with_feature }
let(:basic_params) { { namespace_id: project.namespace.to_param, project_id: project } }
diff --git a/spec/services/bulk_imports/create_service_spec.rb b/spec/services/bulk_imports/create_service_spec.rb
index cb7d51ce7b4..f1e5533139e 100644
--- a/spec/services/bulk_imports/create_service_spec.rb
+++ b/spec/services/bulk_imports/create_service_spec.rb
@@ -41,6 +41,7 @@ RSpec.describe BulkImports::CreateService do
before do
allow_next_instance_of(BulkImports::Clients::HTTP) do |instance|
allow(instance).to receive(:instance_version).and_return(source_version)
+ allow(instance).to receive(:instance_enterprise).and_return(false)
end
end
@@ -53,6 +54,7 @@ RSpec.describe BulkImports::CreateService do
expect(last_bulk_import.user).to eq(user)
expect(last_bulk_import.source_version).to eq(source_version.to_s)
expect(last_bulk_import.user).to eq(user)
+ expect(last_bulk_import.source_enterprise).to eq(false)
expect_snowplow_event(
category: 'BulkImports::CreateService',
diff --git a/spec/tooling/danger/product_intelligence_spec.rb b/spec/tooling/danger/product_intelligence_spec.rb
index ea08e3bc6db..fab8b0c61fa 100644
--- a/spec/tooling/danger/product_intelligence_spec.rb
+++ b/spec/tooling/danger/product_intelligence_spec.rb
@@ -12,12 +12,16 @@ RSpec.describe Tooling::Danger::ProductIntelligence do
subject(:product_intelligence) { fake_danger.new(helper: fake_helper) }
let(:fake_danger) { DangerSpecHelper.fake_danger.include(described_class) }
- let(:changed_files) { ['metrics/counts_7d/test_metric.yml'] }
- let(:changed_lines) { ['+tier: ee'] }
+ let(:previous_label_to_add) { 'label_to_add' }
+ let(:labels_to_add) { [previous_label_to_add] }
+ let(:ci_env) { true }
+ let(:has_product_intelligence_label) { true }
before do
- allow(fake_helper).to receive(:all_changed_files).and_return(changed_files)
allow(fake_helper).to receive(:changed_lines).and_return(changed_lines)
+ allow(fake_helper).to receive(:labels_to_add).and_return(labels_to_add)
+ allow(fake_helper).to receive(:ci?).and_return(ci_env)
+ allow(fake_helper).to receive(:mr_has_labels?).with('product intelligence').and_return(has_product_intelligence_label)
end
describe '#check!' do
@@ -26,17 +30,13 @@ RSpec.describe Tooling::Danger::ProductIntelligence do
let(:markdown_formatted_list) { 'markdown formatted list' }
let(:review_pending_label) { 'product intelligence::review pending' }
let(:approved_label) { 'product intelligence::approved' }
- let(:ci_env) { true }
- let(:previous_label_to_add) { 'label_to_add' }
- let(:labels_to_add) { [previous_label_to_add] }
- let(:has_product_intelligence_label) { true }
+ let(:changed_files) { ['metrics/counts_7d/test_metric.yml'] }
+ let(:changed_lines) { ['+tier: ee'] }
before do
+ allow(fake_helper).to receive(:all_changed_files).and_return(changed_files)
allow(fake_helper).to receive(:changes_by_category).and_return(product_intelligence: changed_files, database: ['other_files.yml'])
- allow(fake_helper).to receive(:ci?).and_return(ci_env)
- allow(fake_helper).to receive(:mr_has_labels?).with('product intelligence').and_return(has_product_intelligence_label)
allow(fake_helper).to receive(:markdown_list).with(changed_files).and_return(markdown_formatted_list)
- allow(fake_helper).to receive(:labels_to_add).and_return(labels_to_add)
end
shared_examples "doesn't add new labels" do
@@ -121,4 +121,58 @@ RSpec.describe Tooling::Danger::ProductIntelligence do
end
end
end
+
+ describe '#check_affected_scopes!' do
+ let(:fixture_dir_glob) { Dir.glob(File.join('spec', 'tooling', 'fixtures', 'metrics', '*.rb')) }
+ let(:changed_lines) { ['+ scope :active, -> { iwhere(email: Array(emails)) }'] }
+
+ before do
+ allow(Dir).to receive(:glob).and_return(fixture_dir_glob)
+ allow(fake_helper).to receive(:markdown_list).with({ 'active' => fixture_dir_glob }).and_return('a')
+ end
+
+ context 'when a model was modified' do
+ let(:modified_files) { ['app/models/super_user.rb'] }
+
+ context 'when a scope is changed' do
+ context 'and a metrics uses the affected scope' do
+ it 'producing warning' do
+ expect(product_intelligence).to receive(:warn).with(%r{#{modified_files}})
+
+ product_intelligence.check_affected_scopes!
+ end
+ end
+
+ context 'when no metrics using the affected scope' do
+ let(:changed_lines) { ['+scope :foo, -> { iwhere(email: Array(emails)) }'] }
+
+ it 'doesnt do anything' do
+ expect(product_intelligence).not_to receive(:warn)
+
+ product_intelligence.check_affected_scopes!
+ end
+ end
+ end
+ end
+
+ context 'when an unrelated model with matching scope was modified' do
+ let(:modified_files) { ['app/models/post_box.rb'] }
+
+ it 'doesnt do anything' do
+ expect(product_intelligence).not_to receive(:warn)
+
+ product_intelligence.check_affected_scopes!
+ end
+ end
+
+ context 'when models arent modified' do
+ let(:modified_files) { ['spec/app/models/user_spec.rb'] }
+
+ it 'doesnt do anything' do
+ expect(product_intelligence).not_to receive(:warn)
+
+ product_intelligence.check_affected_scopes!
+ end
+ end
+ end
end
diff --git a/spec/tooling/fixtures/metrics/sample_instrumentation_metric.rb b/spec/tooling/fixtures/metrics/sample_instrumentation_metric.rb
new file mode 100644
index 00000000000..d6b86137b1b
--- /dev/null
+++ b/spec/tooling/fixtures/metrics/sample_instrumentation_metric.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Usage
+ module Metrics
+ module Instrumentations
+ class ActiveUserCountMetric < DatabaseMetric
+ operation :count
+
+ relation { SuperUser.active }
+ end
+ end
+ end
+ end
+end
diff --git a/spec/views/shared/gitlab_version/_security_patch_upgrade_alert.html.haml_spec.rb b/spec/views/shared/gitlab_version/_security_patch_upgrade_alert.html.haml_spec.rb
new file mode 100644
index 00000000000..942e27f2559
--- /dev/null
+++ b/spec/views/shared/gitlab_version/_security_patch_upgrade_alert.html.haml_spec.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'shared/gitlab_version/_security_patch_upgrade_alert' do
+ describe 'when show_security_patch_upgrade_alert? is true' do
+ before do
+ allow(view).to receive(:show_security_patch_upgrade_alert?).and_return(true)
+ render
+ end
+
+ it 'renders the security patch upgrade alert' do
+ expect(rendered).to have_selector('#js-security-patch-upgrade-alert')
+ end
+ end
+end
diff --git a/tooling/danger/product_intelligence.rb b/tooling/danger/product_intelligence.rb
index 621a7b509b0..58e327408a1 100644
--- a/tooling/danger/product_intelligence.rb
+++ b/tooling/danger/product_intelligence.rb
@@ -4,15 +4,21 @@
module Tooling
module Danger
module ProductIntelligence
+ METRIC_DIRS = %w[lib/gitlab/usage/metrics/instrumentations ee/lib/gitlab/usage/metrics/instrumentations].freeze
APPROVED_LABEL = 'product intelligence::approved'
REVIEW_LABEL = 'product intelligence::review pending'
CHANGED_FILES_MESSAGE = <<~MSG
- For the following files, a review from the [Data team and Product Intelligence team](https://gitlab.com/groups/gitlab-org/analytics-section/product-intelligence/engineers/-/group_members?with_inherited_permissions=exclude) is recommended
- Please check the ~"product intelligence" [Service Ping guide](https://docs.gitlab.com/ee/development/service_ping/) or the [Snowplow guide](https://docs.gitlab.com/ee/development/snowplow/).
+ For the following files, a review from the [Data team and Product Intelligence team](https://gitlab.com/groups/gitlab-org/analytics-section/product-intelligence/engineers/-/group_members?with_inherited_permissions=exclude) is recommended
+ Please check the ~"product intelligence" [Service Ping guide](https://docs.gitlab.com/ee/development/service_ping/) or the [Snowplow guide](https://docs.gitlab.com/ee/development/snowplow/).
- For MR review guidelines, see the [Service Ping review guidelines](https://docs.gitlab.com/ee/development/service_ping/review_guidelines.html) or the [Snowplow review guidelines](https://docs.gitlab.com/ee/development/snowplow/review_guidelines.html).
+ For MR review guidelines, see the [Service Ping review guidelines](https://docs.gitlab.com/ee/development/service_ping/review_guidelines.html) or the [Snowplow review guidelines](https://docs.gitlab.com/ee/development/snowplow/review_guidelines.html).
- %<changed_files>s
+ %<changed_files>s
+
+ MSG
+
+ CHANGED_SCOPE_MESSAGE = <<~MSG
+ The following metrics could be affected by the modified scopes and require ~"product intelligence" review:
MSG
@@ -33,8 +39,61 @@ module Tooling
helper.labels_to_add.concat(labels_to_add) unless labels_to_add.empty?
end
+ def check_affected_scopes!
+ metric_scope_list = metric_scope_affected
+ return if metric_scope_list.empty?
+
+ warn CHANGED_SCOPE_MESSAGE + convert_to_table(metric_scope_list)
+ helper.labels_to_add.concat(missing_labels) unless missing_labels.empty?
+ end
+
private
+ def convert_to_table(items)
+ message = "Scope | Affected files |\n"
+ message += "--- | ----- |\n"
+ items.each_key do |scope|
+ affected_files = items[scope]
+ message += "`#{scope}`| `#{affected_files[0]}` |\n"
+ affected_files[1..]&.each do |file_name|
+ message += " | `#{file_name}` |\n"
+ end
+ end
+ message
+ end
+
+ def metric_scope_affected
+ select_models(helper.modified_files).each_with_object(Hash.new { |h, k| h[k] = [] }) do |file_name, matched_files|
+ helper.changed_lines(file_name).each do |mod_line, _i|
+ next unless mod_line =~ /^\+\s+scope :\w+/
+
+ affected_scope = mod_line.match(/:\w+/)
+ next if affected_scope.nil?
+
+ affected_class = File.basename(file_name, '.rb').split('_').map(&:capitalize).join
+ scope_name = "#{affected_class}.#{affected_scope[0][1..]}"
+
+ each_metric do |metric_def|
+ next unless File.read(metric_def).include?("relation { #{scope_name}")
+
+ matched_files[scope_name].push(metric_def)
+ end
+ end
+ end
+ end
+
+ def select_models(files)
+ files.select do |f|
+ f.start_with?('app/models/', 'ee/app/models/')
+ end
+ end
+
+ def each_metric(&block)
+ METRIC_DIRS.each do |dir|
+ Dir.glob(File.join(dir, '*.rb')).each(&block)
+ end
+ end
+
def missing_labels
return [] unless helper.ci?
diff --git a/yarn.lock b/yarn.lock
index 9930c5671f7..82f0d01c399 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1041,6 +1041,18 @@
resolved "https://registry.yarnpkg.com/@csstools/selector-specificity/-/selector-specificity-2.0.1.tgz#b6b8d81780b9a9f6459f4bfe9226ac6aefaefe87"
integrity sha512-aG20vknL4/YjQF9BSV7ts4EWm/yrjagAN7OWBNmlbEOUiu0llj4OGrFoOKK3g2vey4/p2omKCoHrWtPxSwV3HA==
+"@cubejs-client/core@^0.31.0":
+ version "0.31.15"
+ resolved "https://registry.yarnpkg.com/@cubejs-client/core/-/core-0.31.15.tgz#db0ee90f5ba7f33a3fae6c81e5e13ab1cf2cd71b"
+ integrity sha512-VQqvvJn++nqO8aOr/dFtyUURNFYAlP3XlDiupiGLXmSsuUn0BuozJQAmJ5XxPPhvz5k9qBko7KkZuC6ikZTdcA==
+ dependencies:
+ core-js "^3.6.5"
+ cross-fetch "^3.0.2"
+ dayjs "^1.10.4"
+ ramda "^0.27.2"
+ url-search-params-polyfill "^7.0.0"
+ uuid "^8.3.2"
+
"@discoveryjs/json-ext@^0.5.0":
version "0.5.6"
resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.6.tgz#d5e0706cf8c6acd8c6032f8d54070af261bbbb2f"
@@ -3906,7 +3918,7 @@ core-js-pure@^3.0.0:
resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.6.5.tgz#c79e75f5e38dbc85a662d91eea52b8256d53b813"
integrity sha512-lacdXOimsiD0QyNf9BC/mxivNJ/ybBGJXQFKzRekp1WTHoVUWsUHEn+2T8GJAzzIhyOuXA+gOxCVN3l+5PLPUA==
-core-js@^3.26.1:
+core-js@^3.26.1, core-js@^3.6.5:
version "3.26.1"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.26.1.tgz#7a9816dabd9ee846c1c0fe0e8fcad68f3709134e"
integrity sha512-21491RRQVzUn0GGM9Z1Jrpr6PNPxPi+Za8OM9q4tksTSnlbXXGKK1nXNg/QvwFYettXvSX6zWKCtHHfjN4puyA==
@@ -3991,6 +4003,13 @@ cropper@^2.3.0:
dependencies:
jquery ">= 1.9.1"
+cross-fetch@^3.0.2:
+ version "3.1.5"
+ resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.5.tgz#e1389f44d9e7ba767907f7af8454787952ab534f"
+ integrity sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==
+ dependencies:
+ node-fetch "2.6.7"
+
cross-spawn@^6.0.5:
version "6.0.5"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4"
@@ -4689,6 +4708,11 @@ dateformat@^5.0.1:
resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-5.0.1.tgz#60a27a2deb339f888ba4532f533e25ac73ca3d19"
integrity sha512-DrcKxOW2am3mtqoJwBTK3OlWcF0QSk1p8diEWwpu3Mf//VdURD7XVaeOV738JvcaBiFfm9o2fisoMhiJH0aYxg==
+dayjs@^1.10.4:
+ version "1.11.6"
+ resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.6.tgz#2e79a226314ec3ec904e3ee1dd5a4f5e5b1c7afb"
+ integrity sha512-zZbY5giJAinCG+7AGaw0wIhNZ6J8AhWuSXKvuc1KAyMiRsvGQWqh4L+MomvhdAYjN+lqvVCMq1I41e3YHvXkyQ==
+
de-indent@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/de-indent/-/de-indent-1.0.2.tgz#b2038e846dc33baa5796128d0804b455b8c1e21d"
@@ -9257,7 +9281,7 @@ node-domexception@1.0.0:
resolved "https://registry.yarnpkg.com/node-domexception/-/node-domexception-1.0.0.tgz#6888db46a1f71c0b76b3f7555016b63fe64766e5"
integrity sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==
-node-fetch@^2.6.1, node-fetch@^2.6.7:
+node-fetch@2.6.7, node-fetch@^2.6.1, node-fetch@^2.6.7:
version "2.6.7"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad"
integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==
@@ -10290,6 +10314,11 @@ quick-lru@^4.0.1:
resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-4.0.1.tgz#5b8878f113a58217848c6482026c73e1ba57727f"
integrity sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==
+ramda@^0.27.2:
+ version "0.27.2"
+ resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.27.2.tgz#84463226f7f36dc33592f6f4ed6374c48306c3f1"
+ integrity sha512-SbiLPU40JuJniHexQSAgad32hfwd+DRUdwF2PlVuI5RZD0/vahUco7R8vD86J/tcEKKF9vZrUVwgtmGCqlCKyA==
+
randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5, randombytes@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a"
@@ -12117,6 +12146,11 @@ url-loader@^4.1.1:
mime-types "^2.1.27"
schema-utils "^3.0.0"
+url-search-params-polyfill@^7.0.0:
+ version "7.0.1"
+ resolved "https://registry.yarnpkg.com/url-search-params-polyfill/-/url-search-params-polyfill-7.0.1.tgz#b900cd9a0d9d2ff757d500135256f2344879cbff"
+ integrity sha512-bAw7L2E+jn9XHG5P9zrPnHdO0yJub4U+yXJOdpcpkr7OBd9T8oll4lUos0iSGRcDvfZoLUKfx9a6aNmIhJ4+mQ==
+
url@^0.11.0:
version "0.11.0"
resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1"