diff --git a/app/assets/javascripts/diffs/components/app.vue b/app/assets/javascripts/diffs/components/app.vue
index 1860a45207f..4057e281a48 100644
--- a/app/assets/javascripts/diffs/components/app.vue
+++ b/app/assets/javascripts/diffs/components/app.vue
@@ -46,6 +46,7 @@ import diffsEventHub from '../event_hub';
import { reviewStatuses } from '../utils/file_reviews';
import { diffsApp } from '../utils/performance';
import { fileByFile } from '../utils/preferences';
+import { queueRedisHllEvents } from '../utils/queue_events';
import CollapsedFilesWarning from './collapsed_files_warning.vue';
import CommitWidget from './commit_widget.vue';
import CompareVersions from './compare_versions.vue';
@@ -336,29 +337,33 @@ export default {
}
if (window.gon?.features?.diffSettingsUsageData) {
+ const events = [];
+
if (this.renderTreeList) {
- api.trackRedisHllUserEvent(TRACKING_FILE_BROWSER_TREE);
+ events.push(TRACKING_FILE_BROWSER_TREE);
} else {
- api.trackRedisHllUserEvent(TRACKING_FILE_BROWSER_LIST);
+ events.push(TRACKING_FILE_BROWSER_LIST);
}
if (this.diffViewType === INLINE_DIFF_VIEW_TYPE) {
- api.trackRedisHllUserEvent(TRACKING_DIFF_VIEW_INLINE);
+ events.push(TRACKING_DIFF_VIEW_INLINE);
} else {
- api.trackRedisHllUserEvent(TRACKING_DIFF_VIEW_PARALLEL);
+ events.push(TRACKING_DIFF_VIEW_PARALLEL);
}
if (this.showWhitespace) {
- api.trackRedisHllUserEvent(TRACKING_WHITESPACE_SHOW);
+ events.push(TRACKING_WHITESPACE_SHOW);
} else {
- api.trackRedisHllUserEvent(TRACKING_WHITESPACE_HIDE);
+ events.push(TRACKING_WHITESPACE_HIDE);
}
if (this.viewDiffsFileByFile) {
- api.trackRedisHllUserEvent(TRACKING_SINGLE_FILE_MODE);
+ events.push(TRACKING_SINGLE_FILE_MODE);
} else {
- api.trackRedisHllUserEvent(TRACKING_MULTIPLE_FILES_MODE);
+ events.push(TRACKING_MULTIPLE_FILES_MODE);
}
+
+ queueRedisHllEvents(events);
}
},
beforeCreate() {
diff --git a/app/assets/javascripts/diffs/constants.js b/app/assets/javascripts/diffs/constants.js
index f1cf556fde0..8dda5eadb16 100644
--- a/app/assets/javascripts/diffs/constants.js
+++ b/app/assets/javascripts/diffs/constants.js
@@ -111,6 +111,8 @@ export const CONFLICT_MARKER_OUR = 'conflict_marker_our';
export const CONFLICT_MARKER_THEIR = 'conflict_marker_their';
// Tracking events
+export const DEFER_DURATION = 750;
+
export const TRACKING_CLICK_DIFF_VIEW_SETTING = 'i_code_review_click_diff_view_setting';
export const TRACKING_DIFF_VIEW_INLINE = 'i_code_review_diff_view_inline';
export const TRACKING_DIFF_VIEW_PARALLEL = 'i_code_review_diff_view_parallel';
diff --git a/app/assets/javascripts/diffs/store/actions.js b/app/assets/javascripts/diffs/store/actions.js
index d11e7dc838f..f7bdbe94bac 100644
--- a/app/assets/javascripts/diffs/store/actions.js
+++ b/app/assets/javascripts/diffs/store/actions.js
@@ -1,6 +1,5 @@
import Cookies from 'js-cookie';
import Vue from 'vue';
-import api from '~/api';
import createFlash from '~/flash';
import { diffViewerModes } from '~/ide/constants';
import axios from '~/lib/utils/axios_utils';
@@ -50,6 +49,7 @@ import eventHub from '../event_hub';
import { isCollapsed } from '../utils/diff_file';
import { markFileReview, setReviewsForMergeRequest } from '../utils/file_reviews';
import { getDerivedMergeRequestInformation } from '../utils/merge_request';
+import { queueRedisHllEvents } from '../utils/queue_events';
import TreeWorker from '../workers/tree_worker';
import * as types from './mutation_types';
import {
@@ -368,8 +368,7 @@ export const setInlineDiffViewType = ({ commit }) => {
historyPushState(url);
if (window.gon?.features?.diffSettingsUsageData) {
- api.trackRedisHllUserEvent(TRACKING_CLICK_DIFF_VIEW_SETTING);
- api.trackRedisHllUserEvent(TRACKING_DIFF_VIEW_INLINE);
+ queueRedisHllEvents([TRACKING_CLICK_DIFF_VIEW_SETTING, TRACKING_DIFF_VIEW_INLINE]);
}
};
@@ -381,8 +380,7 @@ export const setParallelDiffViewType = ({ commit }) => {
historyPushState(url);
if (window.gon?.features?.diffSettingsUsageData) {
- api.trackRedisHllUserEvent(TRACKING_CLICK_DIFF_VIEW_SETTING);
- api.trackRedisHllUserEvent(TRACKING_DIFF_VIEW_PARALLEL);
+ queueRedisHllEvents([TRACKING_CLICK_DIFF_VIEW_SETTING, TRACKING_DIFF_VIEW_PARALLEL]);
}
};
@@ -570,13 +568,15 @@ export const setRenderTreeList = ({ commit }, { renderTreeList, trackClick = tru
localStorage.setItem(TREE_LIST_STORAGE_KEY, renderTreeList);
if (window.gon?.features?.diffSettingsUsageData && trackClick) {
- api.trackRedisHllUserEvent(TRACKING_CLICK_FILE_BROWSER_SETTING);
+ const events = [TRACKING_CLICK_FILE_BROWSER_SETTING];
if (renderTreeList) {
- api.trackRedisHllUserEvent(TRACKING_FILE_BROWSER_TREE);
+ events.push(TRACKING_FILE_BROWSER_TREE);
} else {
- api.trackRedisHllUserEvent(TRACKING_FILE_BROWSER_LIST);
+ events.push(TRACKING_FILE_BROWSER_LIST);
}
+
+ queueRedisHllEvents(events);
}
};
@@ -592,13 +592,15 @@ export const setShowWhitespace = async (
notesEventHub.$emit('refetchDiffData');
if (window.gon?.features?.diffSettingsUsageData && trackClick) {
- api.trackRedisHllUserEvent(TRACKING_CLICK_WHITESPACE_SETTING);
+ const events = [TRACKING_CLICK_WHITESPACE_SETTING];
if (showWhitespace) {
- api.trackRedisHllUserEvent(TRACKING_WHITESPACE_SHOW);
+ events.push(TRACKING_WHITESPACE_SHOW);
} else {
- api.trackRedisHllUserEvent(TRACKING_WHITESPACE_HIDE);
+ events.push(TRACKING_WHITESPACE_HIDE);
}
+
+ queueRedisHllEvents(events);
}
};
@@ -819,13 +821,15 @@ export const setFileByFile = ({ state, commit }, { fileByFile }) => {
Cookies.set(DIFF_FILE_BY_FILE_COOKIE_NAME, fileViewMode);
if (window.gon?.features?.diffSettingsUsageData) {
- api.trackRedisHllUserEvent(TRACKING_CLICK_SINGLE_FILE_SETTING);
+ const events = [TRACKING_CLICK_SINGLE_FILE_SETTING];
if (fileByFile) {
- api.trackRedisHllUserEvent(TRACKING_SINGLE_FILE_MODE);
+ events.push(TRACKING_SINGLE_FILE_MODE);
} else {
- api.trackRedisHllUserEvent(TRACKING_MULTIPLE_FILES_MODE);
+ events.push(TRACKING_MULTIPLE_FILES_MODE);
}
+
+ queueRedisHllEvents(events);
}
return axios
diff --git a/app/assets/javascripts/diffs/utils/queue_events.js b/app/assets/javascripts/diffs/utils/queue_events.js
new file mode 100644
index 00000000000..08fcc98d45f
--- /dev/null
+++ b/app/assets/javascripts/diffs/utils/queue_events.js
@@ -0,0 +1,13 @@
+import { delay } from 'lodash';
+import api from '~/api';
+import { DEFER_DURATION } from '../constants';
+
+function trackRedisHllUserEvent(event, deferDuration = 0) {
+ delay(() => api.trackRedisHllUserEvent(event), deferDuration);
+}
+
+export function queueRedisHllEvents(events) {
+ events.forEach((event, index) => {
+ trackRedisHllUserEvent(event, DEFER_DURATION * (index + 1));
+ });
+}
diff --git a/app/assets/javascripts/packages_and_registries/package_registry/components/details/app.vue b/app/assets/javascripts/packages_and_registries/package_registry/components/details/app.vue
index 707f186d4da..65e396b34e9 100644
--- a/app/assets/javascripts/packages_and_registries/package_registry/components/details/app.vue
+++ b/app/assets/javascripts/packages_and_registries/package_registry/components/details/app.vue
@@ -39,7 +39,9 @@ import {
CANCEL_DELETE_PACKAGE_FILE_TRACKING_ACTION,
SHOW_DELETE_SUCCESS_ALERT,
FETCH_PACKAGE_DETAILS_ERROR_MESSAGE,
+ DELETE_PACKAGE_ERROR_MESSAGE,
} from '~/packages_and_registries/package_registry/constants';
+import destroyPackageMutation from '~/packages_and_registries/package_registry/graphql/mutations/destroy_package.mutation.graphql';
import getPackageDetails from '~/packages_and_registries/package_registry/graphql/queries/get_package_details.query.graphql';
import Tracking from '~/tracking';
@@ -156,19 +158,42 @@ export default {
// this.fetchPackageVersions();
}
},
+ deletePackage() {
+ return this.$apollo
+ .mutate({
+ mutation: destroyPackageMutation,
+ variables: {
+ id: this.packageEntity.id,
+ },
+ })
+ .then(({ data }) => {
+ if (data?.destroyPackage?.errors[0]) {
+ throw data.destroyPackage.errors[0];
+ }
+ });
+ },
async confirmPackageDeletion() {
this.track(DELETE_PACKAGE_TRACKING_ACTION);
- await this.deletePackage();
+ try {
+ await this.deletePackage();
- const returnTo =
- !this.groupListUrl || document.referrer.includes(this.projectName)
- ? this.projectListUrl
- : this.groupListUrl; // to avoid security issue url are supplied from backend
+ const returnTo =
+ !this.groupListUrl || document.referrer.includes(this.projectName)
+ ? this.projectListUrl
+ : this.groupListUrl; // to avoid security issue url are supplied from backend
- const modalQuery = objectToQuery({ [SHOW_DELETE_SUCCESS_ALERT]: true });
+ const modalQuery = objectToQuery({ [SHOW_DELETE_SUCCESS_ALERT]: true });
- window.location.replace(`${returnTo}?${modalQuery}`);
+ window.location.replace(`${returnTo}?${modalQuery}`);
+ } catch (error) {
+ createFlash({
+ message: DELETE_PACKAGE_ERROR_MESSAGE,
+ type: 'warning',
+ captureError: true,
+ error,
+ });
+ }
},
handleFileDelete(file) {
this.track(REQUEST_DELETE_PACKAGE_FILE_TRACKING_ACTION);
@@ -225,10 +250,10 @@ export default {
{{ __('Delete') }}
@@ -303,7 +328,6 @@ export default {
= GroupMember::REPORTER || valid_dependency_proxy_deploy_token
+ access_level >= GroupMember::GUEST || valid_dependency_proxy_deploy_token
else
can?(:read_group)
end
diff --git a/doc/ci/environments/index.md b/doc/ci/environments/index.md
index e647a704a87..9e7855ef826 100644
--- a/doc/ci/environments/index.md
+++ b/doc/ci/environments/index.md
@@ -31,7 +31,8 @@ Prerequisites:
To view a list of environments and deployments:
-1. Go to the project's **Deployments > Environments** page.
+1. On the top bar, select **Menu > Projects** and find your project.
+1. On the left sidebar, select **Deployments > Environments**.
The environments are displayed.
![Environments list](img/environments_list.png)
@@ -57,7 +58,8 @@ You can create an environment and deployment in the UI or in your `.gitlab-ci.ym
In the UI:
-1. Go to the project's **Deployments > Environments** page.
+1. On the top bar, select **Menu > Projects** and find your project.
+1. On the left sidebar, select **Deployments > Environments**.
1. Select **New environment**.
1. Enter a name and external URL.
1. Select **Save**.
@@ -326,7 +328,8 @@ If there is a problem with a deployment, you can retry it or roll it back.
To retry or rollback a deployment:
-1. Go to the project's **Deployments > Environments**.
+1. On the top bar, select **Menu > Projects** and find your project.
+1. On the left sidebar, select **Deployments > Environments**.
1. Select the environment.
1. To the right of the deployment name:
- To retry a deployment, select **Re-deploy to environment**.
@@ -465,7 +468,8 @@ GitLab automatically triggers the `stop_review_app` job to stop the environment.
You can view a deployment's expiration date in the GitLab UI.
-1. Go to the project's **Deployments > Environments** page.
+1. On the top bar, select **Menu > Projects** and find your project.
+1. On the left sidebar, select **Deployments > Environments**.
1. Select the name of the deployment.
In the top left, next to the environment name, the expiration date is displayed.
@@ -474,7 +478,8 @@ In the top left, next to the environment name, the expiration date is displayed.
You can manually override a deployment's expiration date.
-1. Go to the project's **Deployments > Environments** page.
+1. On the top bar, select **Menu > Projects** and find your project.
+1. On the left sidebar, select **Deployments > Environments**.
1. Select the deployment name.
1. On the top right, select the thumbtack (**{thumbtack}**).
@@ -491,7 +496,8 @@ You can delete [stopped environments](#stopping-an-environment) in the GitLab UI
To delete a stopped environment in the GitLab UI:
-1. Go to the project's **Deployments > Environments** page.
+1. On the top bar, select **Menu > Projects** and find your project.
+1. On the left sidebar, select **Deployments > Environments**.
1. Select the **Stopped** tab.
1. Next to the environment you want to delete, select **Delete environment**.
1. On the confirmation dialog box, select **Delete environment**.
@@ -596,7 +602,9 @@ Limitations of GitLab Auto Rollback:
GitLab Auto Rollback is turned off by default. To turn it on:
-1. Go to **Project > Settings > CI/CD > Automatic deployment rollbacks**.
+1. On the top bar, select **Menu > Projects** and find your project.
+1. On the left sidebar, select **Settings > CI/CD**.
+1. Expand **Automatic deployment rollbacks**.
1. Select the checkbox for **Enable automatic rollbacks**.
1. Select **Save changes**.
diff --git a/doc/ci/environments/protected_environments.md b/doc/ci/environments/protected_environments.md
index 0c29f0aa7a7..4d89bba9ec1 100644
--- a/doc/ci/environments/protected_environments.md
+++ b/doc/ci/environments/protected_environments.md
@@ -30,18 +30,19 @@ To protect, update, or unprotect an environment, you need to have at least the
To protect an environment:
-1. Navigate to your project's **Settings > CI/CD**.
-1. Expand the **Protected environments** section.
-1. From the **Environment** dropdown menu, select the environment you want to protect.
-1. In the **Allowed to Deploy** dropdown menu, select the role, users, or groups you
+1. On the top bar, select **Menu > Projects** and find your project.
+1. On the left sidebar, select **Settings > CI/CD**.
+1. Expand **Protected environments**.
+1. From the **Environment** list, select the environment you want to protect.
+1. In the **Allowed to deploy** list, select the role, users, or groups you
want to give deploy access to. Keep in mind that:
- There are two roles to choose from:
- - **Maintainers**: Allows access to all maintainers in the project.
- - **Developers**: Allows access to all maintainers and all developers in the project.
- - You can only select groups that are already associated with the project.
- - Only users that have at least the Developer role appear in
- the **Allowed to Deploy** dropdown menu.
-1. Click the **Protect** button.
+ - **Maintainers**: Allows access to all of the project's users with the Maintainer role.
+ - **Developers**: Allows access to all of the project's users with the Maintainer and Developer role.
+ - You can select groups that are already associated with the project only.
+ - Users must have at least the Developer role to appear in
+ the **Allowed to deploy** list.
+1. Select **Protect**.
The protected environment now appears in the list of protected environments.
@@ -134,10 +135,10 @@ appears in the dropdown menu for deployment-only access.
To add deployment-only access:
-1. Add a group with Reporter permissions.
-1. Add user(s) to the group.
+1. Add a group with the Reporter role.
+1. Add users to the group.
1. Invite the group to be a project member.
-1. Follow the steps outlined in [Protecting Environments](#protecting-environments).
+1. Follow the steps in [Protecting Environments](#protecting-environments).
Note that deployment-only access is the only possible access level for groups with [Reporter permissions](../../user/permissions.md).
diff --git a/doc/raketasks/backup_restore.md b/doc/raketasks/backup_restore.md
index 250abf2fa60..e9c9659d4f5 100644
--- a/doc/raketasks/backup_restore.md
+++ b/doc/raketasks/backup_restore.md
@@ -850,66 +850,6 @@ restoring the new data, which causes an error.
Read more about [configuring NFS mounts](../administration/nfs.md)
-### Restore for installation from source
-
-First, ensure your backup tar file is in the backup directory described in the
-`gitlab.yml` configuration:
-
-```yaml
-## Backup settings
-backup:
- path: "tmp/backups" # Relative paths are relative to Rails.root (default: tmp/backups/)
-```
-
-The default is `/home/git/gitlab/tmp/backups`, and it needs to be owned by the `git` user. Now, you can begin the backup procedure:
-
-```shell
-# Stop processes that are connected to the database
-sudo service gitlab stop
-
-sudo -u git -H bundle exec rake gitlab:backup:restore RAILS_ENV=production
-```
-
-Example output:
-
-```plaintext
-Unpacking backup... [DONE]
-Restoring database tables:
--- create_table("events", {:force=>true})
- -> 0.2231s
-[...]
-- Loading fixture events...[DONE]
-- Loading fixture issues...[DONE]
-- Loading fixture keys...[SKIPPING]
-- Loading fixture merge_requests...[DONE]
-- Loading fixture milestones...[DONE]
-- Loading fixture namespaces...[DONE]
-- Loading fixture notes...[DONE]
-- Loading fixture projects...[DONE]
-- Loading fixture protected_branches...[SKIPPING]
-- Loading fixture schema_migrations...[DONE]
-- Loading fixture services...[SKIPPING]
-- Loading fixture snippets...[SKIPPING]
-- Loading fixture taggings...[SKIPPING]
-- Loading fixture tags...[SKIPPING]
-- Loading fixture users...[DONE]
-- Loading fixture users_projects...[DONE]
-- Loading fixture web_hooks...[SKIPPING]
-- Loading fixture wikis...[SKIPPING]
-Restoring repositories:
-- Restoring repository abcd... [DONE]
-- Object pool 1 ...
-Deleting tmp directories...[DONE]
-```
-
-Next, restore `/home/git/gitlab/.secret` if necessary, [as previously mentioned](#restore-prerequisites).
-
-Restart GitLab:
-
-```shell
-sudo service gitlab restart
-```
-
### Restore for Omnibus GitLab installations
This procedure assumes that:
@@ -1027,6 +967,66 @@ issue.
The GitLab Helm chart uses a different process, documented in
[restoring a GitLab Helm chart installation](https://gitlab.com/gitlab-org/charts/gitlab/blob/master/doc/backup-restore/restore.md).
+### Restore for installation from source
+
+First, ensure your backup tar file is in the backup directory described in the
+`gitlab.yml` configuration:
+
+```yaml
+## Backup settings
+backup:
+ path: "tmp/backups" # Relative paths are relative to Rails.root (default: tmp/backups/)
+```
+
+The default is `/home/git/gitlab/tmp/backups`, and it needs to be owned by the `git` user. Now, you can begin the backup procedure:
+
+```shell
+# Stop processes that are connected to the database
+sudo service gitlab stop
+
+sudo -u git -H bundle exec rake gitlab:backup:restore RAILS_ENV=production
+```
+
+Example output:
+
+```plaintext
+Unpacking backup... [DONE]
+Restoring database tables:
+-- create_table("events", {:force=>true})
+ -> 0.2231s
+[...]
+- Loading fixture events...[DONE]
+- Loading fixture issues...[DONE]
+- Loading fixture keys...[SKIPPING]
+- Loading fixture merge_requests...[DONE]
+- Loading fixture milestones...[DONE]
+- Loading fixture namespaces...[DONE]
+- Loading fixture notes...[DONE]
+- Loading fixture projects...[DONE]
+- Loading fixture protected_branches...[SKIPPING]
+- Loading fixture schema_migrations...[DONE]
+- Loading fixture services...[SKIPPING]
+- Loading fixture snippets...[SKIPPING]
+- Loading fixture taggings...[SKIPPING]
+- Loading fixture tags...[SKIPPING]
+- Loading fixture users...[DONE]
+- Loading fixture users_projects...[DONE]
+- Loading fixture web_hooks...[SKIPPING]
+- Loading fixture wikis...[SKIPPING]
+Restoring repositories:
+- Restoring repository abcd... [DONE]
+- Object pool 1 ...
+Deleting tmp directories...[DONE]
+```
+
+Next, restore `/home/git/gitlab/.secret` if necessary, [as previously mentioned](#restore-prerequisites).
+
+Restart GitLab:
+
+```shell
+sudo service gitlab restart
+```
+
### Restoring only one or a few projects or groups from a backup
Although the Rake task used to restore a GitLab instance doesn't support
diff --git a/doc/update/index.md b/doc/update/index.md
index 61419e563cc..ed057782bf9 100644
--- a/doc/update/index.md
+++ b/doc/update/index.md
@@ -203,15 +203,15 @@ accordingly, while also consulting the
The following table, while not exhaustive, shows some examples of the supported
upgrade paths.
-| Target version | Your version | Supported upgrade path | Note |
-| --------------------- | ------------ | ------------------------ | ---- |
-| `14.1.0` | `13.9.2` | `13.9.2` -> `13.12.6` -> `14.0.5` -> `14.1.0` | Two intermediate versions are required: `13.12` and `14.0`, then `14.1`. |
-| `13.5.4` | `12.9.2` | `12.9.2` -> `12.10.14` -> `13.0.14` -> `13.1.11` -> `13.5.4` | Three intermediate versions are required: `12.10`, `13.0` and `13.1`, then `13.5.4`. |
-| `13.2.10` | `11.5.0` | `11.5.0` -> `11.11.8` -> `12.0.12` -> `12.1.17` -> `12.10.14` -> `13.0.14` -> `13.1.11` -> `13.2.10` | Six intermediate versions are required: `11.11`, `12.0`, `12.1`, `12.10`, `13.0` and `13.1`, then `13.2.10`. |
-| `12.10.14` | `11.3.4` | `11.3.4` -> `11.11.8` -> `12.0.12` -> `12.1.17` -> `12.10.14` | Three intermediate versions are required: `11.11`, `12.0` and `12.1`, then `12.10.14`. |
-| `12.9.5` | `10.4.5` | `10.4.5` -> `10.8.7` -> `11.11.8` -> `12.0.12` -> `12.1.17` -> `12.9.5` | Four intermediate versions are required: `10.8`, `11.11`, `12.0` and `12.1`, then `12.9.5`. |
-| `12.2.5` | `9.2.6` | `9.2.6` -> `9.5.10` -> `10.8.7` -> `11.11.8` -> `12.0.12` -> `12.1.17` -> `12.2.5` | Five intermediate versions are required: `9.5`, `10.8`, `11.11`, `12.0`, `12.1`, then `12.2.5`. |
-| `11.3.4` | `8.13.4` | `8.13.4` -> `8.17.7` -> `9.5.10` -> `10.8.7` -> `11.3.4` | `8.17.7` is the last version in version 8, `9.5.10` is the last version in version 9, `10.8.7` is the last version in version 10. |
+| Target version | Your version | Supported upgrade path | Note |
+| -------------- | ------------ | ---------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
+| `14.1.2` | `13.9.2` | `13.9.2` -> `13.12.9` -> `14.0.7` -> `14.1.2` | Two intermediate versions are required: `13.12` and `14.0`, then `14.1`. |
+| `13.5.4` | `12.9.2` | `12.9.2` -> `12.10.14` -> `13.0.14` -> `13.1.11` -> `13.5.4` | Three intermediate versions are required: `12.10`, `13.0` and `13.1`, then `13.5.4`. |
+| `13.2.10` | `11.5.0` | `11.5.0` -> `11.11.8` -> `12.0.12` -> `12.1.17` -> `12.10.14` -> `13.0.14` -> `13.1.11` -> `13.2.10` | Six intermediate versions are required: `11.11`, `12.0`, `12.1`, `12.10`, `13.0` and `13.1`, then `13.2.10`. |
+| `12.10.14` | `11.3.4` | `11.3.4` -> `11.11.8` -> `12.0.12` -> `12.1.17` -> `12.10.14` | Three intermediate versions are required: `11.11`, `12.0` and `12.1`, then `12.10.14`. |
+| `12.9.5` | `10.4.5` | `10.4.5` -> `10.8.7` -> `11.11.8` -> `12.0.12` -> `12.1.17` -> `12.9.5` | Four intermediate versions are required: `10.8`, `11.11`, `12.0` and `12.1`, then `12.9.5`. |
+| `12.2.5` | `9.2.6` | `9.2.6` -> `9.5.10` -> `10.8.7` -> `11.11.8` -> `12.0.12` -> `12.1.17` -> `12.2.5` | Five intermediate versions are required: `9.5`, `10.8`, `11.11`, `12.0`, `12.1`, then `12.2.5`. |
+| `11.3.4` | `8.13.4` | `8.13.4` -> `8.17.7` -> `9.5.10` -> `10.8.7` -> `11.3.4` | `8.17.7` is the last version in version 8, `9.5.10` is the last version in version 9, `10.8.7` is the last version in version 10. |
## Upgrading to a new major version
@@ -222,7 +222,7 @@ cannot guarantee that upgrading between major versions will be seamless.
It is required to follow the following upgrade steps to ensure a successful *major* version upgrade:
-1. Upgrade to the latest minor version of the preceeding major version.
+1. Upgrade to the latest minor version of the preceding major version.
1. Upgrade to the first minor version (`X.0.Z`) of the target major version.
1. Proceed with upgrading to a newer release.
@@ -379,7 +379,7 @@ and [Helm Chart deployments](https://docs.gitlab.com/charts/). They come with ap
- Due to an issue where `BatchedBackgroundMigrationWorkers` were
[not working](https://gitlab.com/gitlab-org/charts/gitlab/-/issues/2785#note_614738345)
for self-managed instances, a [fix was created](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/65106)
- and a [14.0.Z](#1400) version was released. If you haven't udpated to 14.0.Z, you need
+ and a [14.0.Z](#1400) version was released. If you haven't updated to 14.0.Z, you need
to update to at least 14.1.0 that contains the same fix before you update to
a later version.
diff --git a/doc/user/permissions.md b/doc/user/permissions.md
index ca4bb58fd05..f61131a15d4 100644
--- a/doc/user/permissions.md
+++ b/doc/user/permissions.md
@@ -301,7 +301,7 @@ The following table lists group permissions available for each role:
| Create/edit/delete iterations | | | ✓ | ✓ | ✓ |
| Create/edit/delete metrics dashboard annotations | | | ✓ | ✓ | ✓ |
| Enable/disable a dependency proxy | | | ✓ | ✓ | ✓ |
-| Pull a container image using the dependency proxy | | ✓ | ✓ | ✓ | ✓ |
+| Pull a container image using the dependency proxy | ✓ | ✓ | ✓ | ✓ | ✓ |
| Purge the dependency proxy for a group | | | | | ✓ |
| Publish [packages](packages/index.md) | | | ✓ | ✓ | ✓ |
| Use security dashboard **(ULTIMATE)** | | | ✓ | ✓ | ✓ |
diff --git a/lib/gitlab/setup_helper.rb b/lib/gitlab/setup_helper.rb
index c4b5ca58ff0..751405f1045 100644
--- a/lib/gitlab/setup_helper.rb
+++ b/lib/gitlab/setup_helper.rb
@@ -21,7 +21,7 @@ module Gitlab
end
rescue Errno::EEXIST
puts 'Skipping config.toml generation:'
- puts 'A configuration file already exists.'
+ puts "A configuration file for #{config_path} already exists."
rescue ArgumentError => e
puts 'Skipping config.toml generation:'
puts e.message
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 17fe81abd71..c7cea4daae8 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -6497,6 +6497,9 @@ msgstr ""
msgid "Checkout|%{totalCiMinutes} CI minutes"
msgstr ""
+msgid "Checkout|(may be %{linkStart}charged upon purchase%{linkEnd})"
+msgstr ""
+
msgid "Checkout|(x%{numberOfUsers})"
msgstr ""
diff --git a/package.json b/package.json
index dca2e2add59..55e55088bfa 100644
--- a/package.json
+++ b/package.json
@@ -59,7 +59,7 @@
"@gitlab/favicon-overlay": "2.0.0",
"@gitlab/svgs": "1.209.0",
"@gitlab/tributejs": "1.0.0",
- "@gitlab/ui": "32.0.0",
+ "@gitlab/ui": "32.1.0",
"@gitlab/visual-review-tools": "1.6.1",
"@rails/actioncable": "6.1.3-2",
"@rails/ujs": "6.1.3-2",
diff --git a/qa/Gemfile b/qa/Gemfile
index aef75b16089..f025e66fbe3 100644
--- a/qa/Gemfile
+++ b/qa/Gemfile
@@ -8,7 +8,7 @@ gem 'allure-rspec', '~> 2.14.1'
gem 'capybara', '~> 3.35.0'
gem 'capybara-screenshot', '~> 1.0.23'
gem 'rake', '~> 12.3.3'
-gem 'rspec', '~> 3.7'
+gem 'rspec', '~> 3.10'
gem 'selenium-webdriver', '~> 4.0.0.beta4'
gem 'airborne', '~> 0.3.4'
gem 'rest-client', '~> 2.1.0'
@@ -28,6 +28,8 @@ gem 'webdrivers', '~> 4.6'
gem 'chemlab', '~> 0.7'
gem 'chemlab-library-www-gitlab-com', '~> 0.1'
+gem 'deprecation_toolkit', '~> 1.5.1', require: false
+
group :development do
gem 'pry-byebug', '~> 3.5.1', platform: :mri
gem "ruby-debug-ide", "~> 0.7.0"
diff --git a/qa/Gemfile.lock b/qa/Gemfile.lock
index ca6f7da1cc1..dfa7a49f2ef 100644
--- a/qa/Gemfile.lock
+++ b/qa/Gemfile.lock
@@ -56,6 +56,8 @@ GEM
adamantium (~> 0.2.0)
equalizer (~> 0.0.9)
concurrent-ruby (1.1.9)
+ deprecation_toolkit (1.5.1)
+ activesupport (>= 4.2)
diff-lcs (1.3)
domain_name (0.5.20190701)
unf (>= 0.0.5, < 1.0.0)
@@ -141,18 +143,18 @@ GEM
netrc (~> 0.8)
rexml (3.2.5)
rotp (3.1.0)
- rspec (3.9.0)
- rspec-core (~> 3.9.0)
- rspec-expectations (~> 3.9.0)
- rspec-mocks (~> 3.9.0)
- rspec-core (3.9.3)
- rspec-support (~> 3.9.3)
- rspec-expectations (3.9.1)
+ rspec (3.10.0)
+ rspec-core (~> 3.10.0)
+ rspec-expectations (~> 3.10.0)
+ rspec-mocks (~> 3.10.0)
+ rspec-core (3.10.1)
+ rspec-support (~> 3.10.0)
+ rspec-expectations (3.10.1)
diff-lcs (>= 1.2.0, < 2.0)
- rspec-support (~> 3.9.0)
- rspec-mocks (3.9.1)
+ rspec-support (~> 3.10.0)
+ rspec-mocks (3.10.2)
diff-lcs (>= 1.2.0, < 2.0)
- rspec-support (~> 3.9.0)
+ rspec-support (~> 3.10.0)
rspec-parameterized (0.4.2)
binding_ninja (>= 0.2.3)
parser
@@ -161,7 +163,7 @@ GEM
unparser
rspec-retry (0.6.1)
rspec-core (> 3.3)
- rspec-support (3.9.4)
+ rspec-support (3.10.2)
rspec_junit_formatter (0.4.1)
rspec-core (>= 2, < 4, != 2.12.0)
ruby-debug-ide (0.7.2)
@@ -215,6 +217,7 @@ DEPENDENCIES
capybara-screenshot (~> 1.0.23)
chemlab (~> 0.7)
chemlab-library-www-gitlab-com (~> 0.1)
+ deprecation_toolkit (~> 1.5.1)
faker (~> 1.6, >= 1.6.6)
gitlab-qa
knapsack (~> 1.17)
@@ -226,7 +229,7 @@ DEPENDENCIES
rake (~> 12.3.3)
rest-client (~> 2.1.0)
rotp (~> 3.1.0)
- rspec (~> 3.7)
+ rspec (~> 3.10)
rspec-parameterized (~> 0.4.2)
rspec-retry (~> 0.6.1)
rspec_junit_formatter (~> 0.4.1)
diff --git a/qa/qa/page/base.rb b/qa/qa/page/base.rb
index 9ed9cb1634d..8aba1356fd0 100644
--- a/qa/qa/page/base.rb
+++ b/qa/qa/page/base.rb
@@ -108,7 +108,7 @@ module QA
wait_for_requests(skip_finished_loading_check: skip_finished_loading_check)
element_selector = element_selector_css(name, reject_capybara_query_keywords(kwargs))
- find(element_selector, only_capybara_query_keywords(kwargs))
+ find(element_selector, **only_capybara_query_keywords(kwargs))
end
def only_capybara_query_keywords(kwargs)
diff --git a/qa/qa/runtime/application_settings.rb b/qa/qa/runtime/application_settings.rb
index 428ed20c83f..0b2aef47576 100644
--- a/qa/qa/runtime/application_settings.rb
+++ b/qa/qa/runtime/application_settings.rb
@@ -26,7 +26,7 @@ module QA
end
def restore_application_settings(*application_settings_keys)
- set_application_settings(@original_application_settings.slice(*application_settings_keys))
+ set_application_settings(**@original_application_settings.slice(*application_settings_keys))
end
private
diff --git a/qa/qa/runtime/browser.rb b/qa/qa/runtime/browser.rb
index 3844c54f4db..9097690de57 100644
--- a/qa/qa/runtime/browser.rb
+++ b/qa/qa/runtime/browser.rb
@@ -148,7 +148,7 @@ module QA
Capybara::Selenium::Driver.new(
app,
- selenium_options
+ **selenium_options
)
end
diff --git a/qa/qa/runtime/feature.rb b/qa/qa/runtime/feature.rb
index dd7f9cf898c..7011f46542b 100644
--- a/qa/qa/runtime/feature.rb
+++ b/qa/qa/runtime/feature.rb
@@ -32,7 +32,7 @@ module QA
def enabled?(key, **scopes)
feature = JSON.parse(get_features).find { |flag| flag['name'] == key.to_s }
- feature && (feature['state'] == 'on' || feature['state'] == 'conditional' && scopes.present? && enabled_scope?(feature['gates'], scopes))
+ feature && (feature['state'] == 'on' || feature['state'] == 'conditional' && scopes.present? && enabled_scope?(feature['gates'], **scopes))
end
private
@@ -43,7 +43,7 @@ module QA
raise AuthorizationError, "Administrator access is required to enable/disable feature flags. #{e.message}"
end
- def enabled_scope?(gates, scopes)
+ def enabled_scope?(gates, **scopes)
scopes.each do |key, value|
case key
when :project, :group, :user
@@ -71,16 +71,16 @@ module QA
# scopes: Any scope (user, project, group) to restrict the change to
def set_and_verify(key, enable:, **scopes)
msg = "#{enable ? 'En' : 'Dis'}abling feature: #{key}"
- msg += " for scope \"#{scopes_to_s(scopes)}\"" if scopes.present?
+ msg += " for scope \"#{scopes_to_s(**scopes)}\"" if scopes.present?
QA::Runtime::Logger.info(msg)
Support::Retrier.retry_on_exception(sleep_interval: 2) do
- set_feature(key, enable, scopes)
+ set_feature(key, enable, **scopes)
is_enabled = nil
QA::Support::Waiter.wait_until(sleep_interval: 1) do
- is_enabled = enabled?(key, scopes)
+ is_enabled = enabled?(key, **scopes)
is_enabled == enable || !enable && scopes.present?
end
diff --git a/qa/spec/qa_deprecation_toolkit_env.rb b/qa/spec/qa_deprecation_toolkit_env.rb
new file mode 100644
index 00000000000..cdd5d954b20
--- /dev/null
+++ b/qa/spec/qa_deprecation_toolkit_env.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+require 'deprecation_toolkit'
+require 'deprecation_toolkit/rspec'
+require 'concurrent/utility/monotonic_time'
+require 'active_support/gem_version'
+
+module QaDeprecationToolkitEnv
+ # Taken from https://github.com/jeremyevans/ruby-warning/blob/1.1.0/lib/warning.rb#L18
+ def self.kwargs_warning
+ %r{warning: (?:Using the last argument (?:for `.+' )?as keyword parameters is deprecated; maybe \*\* should be added to the call|Passing the keyword argument (?:for `.+' )?as the last hash parameter is deprecated|Splitting the last argument (?:for `.+' )?into positional and keyword parameters is deprecated|The called method (?:`.+' )?is defined here)\n\z}
+ end
+
+ def self.configure!
+ # Enable ruby deprecations for keywords, it's suppressed by default in Ruby 2.7.2
+ Warning[:deprecated] = true
+
+ DeprecationToolkit::Configuration.test_runner = :rspec
+ DeprecationToolkit::Configuration.deprecation_path = 'deprecations'
+ DeprecationToolkit::Configuration.warnings_treated_as_deprecation = [kwargs_warning]
+ end
+end
diff --git a/qa/spec/runtime/api/request_spec.rb b/qa/spec/runtime/api/request_spec.rb
index 93de2f4a87e..a1de71d31f0 100644
--- a/qa/spec/runtime/api/request_spec.rb
+++ b/qa/spec/runtime/api/request_spec.rb
@@ -14,7 +14,7 @@ RSpec.describe QA::Runtime::API::Request do
end
context 'when oauth_access_token is passed in the query string' do
- let(:request) { described_class.new(client, '/users', { oauth_access_token: 'foo' }) }
+ let(:request) { described_class.new(client, '/users', oauth_access_token: 'foo') }
it 'does not adds a private_token query string' do
expect(request.url).to eq 'http://example.com/api/v4/users?oauth_access_token=foo'
diff --git a/qa/spec/spec_helper.rb b/qa/spec/spec_helper.rb
index f4bfd57504e..c4da85d75b0 100644
--- a/qa/spec/spec_helper.rb
+++ b/qa/spec/spec_helper.rb
@@ -6,6 +6,9 @@ require 'rspec-parameterized'
require 'active_support/core_ext/hash'
require 'active_support/core_ext/object/blank'
+require_relative 'qa_deprecation_toolkit_env'
+QaDeprecationToolkitEnv.configure!
+
if ENV['CI'] && QA::Runtime::Env.knapsack? && !ENV['NO_KNAPSACK']
require 'knapsack'
Knapsack::Adapters::RSpecAdapter.bind
diff --git a/spec/controllers/groups/dependency_proxy_for_containers_controller_spec.rb b/spec/controllers/groups/dependency_proxy_for_containers_controller_spec.rb
index 00c3472bf55..dc25d75ee54 100644
--- a/spec/controllers/groups/dependency_proxy_for_containers_controller_spec.rb
+++ b/spec/controllers/groups/dependency_proxy_for_containers_controller_spec.rb
@@ -185,7 +185,7 @@ RSpec.describe Groups::DependencyProxyForContainersController do
end
before do
- group.add_reporter(user)
+ group.add_guest(user)
end
it 'proxies status from the remote token request', :aggregate_failures do
@@ -206,7 +206,7 @@ RSpec.describe Groups::DependencyProxyForContainersController do
end
before do
- group.add_reporter(user)
+ group.add_guest(user)
end
it 'proxies status from the remote manifest request', :aggregate_failures do
@@ -219,7 +219,7 @@ RSpec.describe Groups::DependencyProxyForContainersController do
context 'a valid user' do
before do
- group.add_reporter(user)
+ group.add_guest(user)
end
it_behaves_like 'a successful manifest pull'
@@ -308,7 +308,7 @@ RSpec.describe Groups::DependencyProxyForContainersController do
end
before do
- group.add_reporter(user)
+ group.add_guest(user)
end
it 'proxies status from the remote blob request', :aggregate_failures do
@@ -321,7 +321,7 @@ RSpec.describe Groups::DependencyProxyForContainersController do
context 'a valid user' do
before do
- group.add_reporter(user)
+ group.add_guest(user)
end
it_behaves_like 'a successful blob pull'
diff --git a/spec/frontend/diffs/utils/queue_events_spec.js b/spec/frontend/diffs/utils/queue_events_spec.js
new file mode 100644
index 00000000000..007748d8b2c
--- /dev/null
+++ b/spec/frontend/diffs/utils/queue_events_spec.js
@@ -0,0 +1,36 @@
+import api from '~/api';
+import { DEFER_DURATION } from '~/diffs/constants';
+import { queueRedisHllEvents } from '~/diffs/utils/queue_events';
+
+jest.mock('~/api', () => ({
+ trackRedisHllUserEvent: jest.fn(),
+}));
+
+describe('diffs events queue', () => {
+ describe('queueRedisHllEvents', () => {
+ it('does not dispatch the event immediately', () => {
+ queueRedisHllEvents(['know_event']);
+ expect(api.trackRedisHllUserEvent).not.toHaveBeenCalled();
+ });
+
+ it('does dispatch the event after the defer duration', () => {
+ queueRedisHllEvents(['know_event']);
+ jest.advanceTimersByTime(DEFER_DURATION + 1);
+ expect(api.trackRedisHllUserEvent).toHaveBeenCalled();
+ });
+
+ it('increase defer duration based on the provided events count', () => {
+ let deferDuration = DEFER_DURATION + 1;
+ const events = ['know_event_a', 'know_event_b', 'know_event_c'];
+ queueRedisHllEvents(events);
+
+ expect(api.trackRedisHllUserEvent).not.toHaveBeenCalled();
+
+ events.forEach((event, index) => {
+ jest.advanceTimersByTime(deferDuration);
+ expect(api.trackRedisHllUserEvent).toHaveBeenLastCalledWith(event);
+ deferDuration *= index + 1;
+ });
+ });
+ });
+});
diff --git a/spec/frontend/packages_and_registries/package_registry/components/details/app_spec.js b/spec/frontend/packages_and_registries/package_registry/components/details/app_spec.js
index d6214402fcc..f147bd67e39 100644
--- a/spec/frontend/packages_and_registries/package_registry/components/details/app_spec.js
+++ b/spec/frontend/packages_and_registries/package_registry/components/details/app_spec.js
@@ -1,7 +1,9 @@
-import { GlEmptyState } from '@gitlab/ui';
-import { shallowMount, createLocalVue } from '@vue/test-utils';
+import { GlEmptyState, GlModal } from '@gitlab/ui';
+import { createLocalVue } from '@vue/test-utils';
import VueApollo from 'vue-apollo';
import createMockApollo from 'helpers/mock_apollo_helper';
+import { useMockLocationHelper } from 'helpers/mock_window_location_helper';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import waitForPromises from 'helpers/wait_for_promises';
import createFlash from '~/flash';
@@ -10,11 +12,22 @@ import PackagesApp from '~/packages_and_registries/package_registry/components/d
import InstallationCommands from '~/packages_and_registries/package_registry/components/details/installation_commands.vue';
import PackageHistory from '~/packages_and_registries/package_registry/components/details/package_history.vue';
import PackageTitle from '~/packages_and_registries/package_registry/components/details/package_title.vue';
-import { FETCH_PACKAGE_DETAILS_ERROR_MESSAGE } from '~/packages_and_registries/package_registry/constants';
+import {
+ FETCH_PACKAGE_DETAILS_ERROR_MESSAGE,
+ DELETE_PACKAGE_ERROR_MESSAGE,
+} from '~/packages_and_registries/package_registry/constants';
+import destroyPackageMutation from '~/packages_and_registries/package_registry/graphql/mutations/destroy_package.mutation.graphql';
import getPackageDetails from '~/packages_and_registries/package_registry/graphql/queries/get_package_details.query.graphql';
-import { packageDetailsQuery, packageData, emptyPackageDetailsQuery } from '../../mock_data';
+import {
+ packageDetailsQuery,
+ packageData,
+ emptyPackageDetailsQuery,
+ packageDestroyMutation,
+ packageDestroyMutationError,
+} from '../../mock_data';
jest.mock('~/flash');
+useMockLocationHelper();
const localVue = createLocalVue();
@@ -34,16 +47,23 @@ describe('PackagesApp', () => {
groupListUrl: 'groupListUrl',
};
- function createComponent({ resolver = jest.fn().mockResolvedValue(packageDetailsQuery()) } = {}) {
+ function createComponent({
+ resolver = jest.fn().mockResolvedValue(packageDetailsQuery()),
+ mutationResolver = jest.fn().mockResolvedValue(packageDestroyMutation()),
+ } = {}) {
localVue.use(VueApollo);
- const requestHandlers = [[getPackageDetails, resolver]];
+ const requestHandlers = [
+ [getPackageDetails, resolver],
+ [destroyPackageMutation, mutationResolver],
+ ];
apolloProvider = createMockApollo(requestHandlers);
- wrapper = shallowMount(PackagesApp, {
+ wrapper = shallowMountExtended(PackagesApp, {
localVue,
apolloProvider,
provide,
+ stubs: { PackageTitle },
});
}
@@ -52,6 +72,8 @@ describe('PackagesApp', () => {
const findPackageHistory = () => wrapper.findComponent(PackageHistory);
const findAdditionalMetadata = () => wrapper.findComponent(AdditionalMetadata);
const findInstallationCommands = () => wrapper.findComponent(InstallationCommands);
+ const findDeleteModal = () => wrapper.findComponent(GlModal);
+ const findDeleteButton = () => wrapper.findByTestId('delete-package');
afterEach(() => {
wrapper.destroy();
@@ -121,4 +143,101 @@ describe('PackagesApp', () => {
packageEntity: expect.objectContaining(packageData()),
});
});
+
+ describe('delete package', () => {
+ const originalReferrer = document.referrer;
+ const setReferrer = (value = provide.projectName) => {
+ Object.defineProperty(document, 'referrer', {
+ value,
+ configurable: true,
+ });
+ };
+
+ const performDeletePackage = async () => {
+ await findDeleteButton().trigger('click');
+
+ findDeleteModal().vm.$emit('primary');
+
+ await waitForPromises();
+ };
+
+ afterEach(() => {
+ Object.defineProperty(document, 'referrer', {
+ value: originalReferrer,
+ configurable: true,
+ });
+ });
+
+ it('shows the delete confirmation modal when delete is clicked', async () => {
+ createComponent();
+
+ await waitForPromises();
+
+ await findDeleteButton().trigger('click');
+
+ expect(findDeleteModal().exists()).toBe(true);
+ });
+
+ describe('successful request', () => {
+ it('when referrer contains project name calls window.replace with project url', async () => {
+ setReferrer();
+
+ createComponent();
+
+ await waitForPromises();
+
+ await performDeletePackage();
+
+ expect(window.location.replace).toHaveBeenCalledWith(
+ 'projectListUrl?showSuccessDeleteAlert=true',
+ );
+ });
+
+ it('when referrer does not contain project name calls window.replace with group url', async () => {
+ setReferrer('baz');
+
+ createComponent();
+
+ await waitForPromises();
+
+ await performDeletePackage();
+
+ expect(window.location.replace).toHaveBeenCalledWith(
+ 'groupListUrl?showSuccessDeleteAlert=true',
+ );
+ });
+ });
+
+ describe('request failure', () => {
+ it('on global failure it displays an alert', async () => {
+ createComponent({ mutationResolver: jest.fn().mockRejectedValue() });
+
+ await waitForPromises();
+
+ await performDeletePackage();
+
+ expect(createFlash).toHaveBeenCalledWith(
+ expect.objectContaining({
+ message: DELETE_PACKAGE_ERROR_MESSAGE,
+ }),
+ );
+ });
+
+ it('on payload with error it displays an alert', async () => {
+ createComponent({
+ mutationResolver: jest.fn().mockResolvedValue(packageDestroyMutationError()),
+ });
+
+ await waitForPromises();
+
+ await performDeletePackage();
+
+ expect(createFlash).toHaveBeenCalledWith(
+ expect.objectContaining({
+ message: DELETE_PACKAGE_ERROR_MESSAGE,
+ }),
+ );
+ });
+ });
+ });
});
diff --git a/spec/frontend/packages_and_registries/package_registry/mock_data.js b/spec/frontend/packages_and_registries/package_registry/mock_data.js
index d1b81aa8b5f..110cb5a3798 100644
--- a/spec/frontend/packages_and_registries/package_registry/mock_data.js
+++ b/spec/frontend/packages_and_registries/package_registry/mock_data.js
@@ -125,3 +125,29 @@ export const emptyPackageDetailsQuery = () => ({
},
},
});
+
+export const packageDestroyMutation = () => ({
+ data: {
+ destroyPackage: {
+ errors: [],
+ },
+ },
+});
+export const packageDestroyMutationError = () => ({
+ data: {
+ destroyPackage: null,
+ },
+ errors: [
+ {
+ message:
+ "The resource that you are attempting to access does not exist or you don't have permission to perform this action",
+ locations: [
+ {
+ line: 2,
+ column: 3,
+ },
+ ],
+ path: ['destroyPackage'],
+ },
+ ],
+});
diff --git a/spec/support/helpers/test_env.rb b/spec/support/helpers/test_env.rb
index eca0716f484..aa5fcf222f2 100644
--- a/spec/support/helpers/test_env.rb
+++ b/spec/support/helpers/test_env.rb
@@ -265,7 +265,7 @@ module TestEnv
def setup_workhorse
# Always rebuild the config file
if skip_compile_workhorse?
- Gitlab::SetupHelper::Workhorse.create_configuration(workhorse_dir, nil)
+ Gitlab::SetupHelper::Workhorse.create_configuration(workhorse_dir, nil, force: true)
return
end
diff --git a/yarn.lock b/yarn.lock
index 158d46b1679..92fdeeb3767 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -908,10 +908,10 @@
resolved "https://registry.yarnpkg.com/@gitlab/tributejs/-/tributejs-1.0.0.tgz#672befa222aeffc83e7d799b0500a7a4418e59b8"
integrity sha512-nmKw1+hB6MHvlmPz63yPwVs1qQkycHwsKgxpEbzmky16Y6mL4EJMk3w1b8QlOAF/AIAzjCERPhe/R4MJiohbZw==
-"@gitlab/ui@32.0.0":
- version "32.0.0"
- resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-32.0.0.tgz#2bf8995e405f35c5fa9dcc2ad0de24d79dc9c006"
- integrity sha512-GVQVx8Db9fb/BfYf7Vzdf6MxqLsF5RZta0VanwTm/asGdQxWG7I9fJIPUHqhCK3S9efZ83zXfZBF0M3uHuxveg==
+"@gitlab/ui@32.1.0":
+ version "32.1.0"
+ resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-32.1.0.tgz#3b7a4b4d68a726f2e6a2d87db03cb604e4841398"
+ integrity sha512-FtNWIOE00lCLXAPrRpFTOoFDD6mvDiCB8qr03NQsvFSbEuwfkvxhElaKNeKy+w0HeM8S8Tt2JqSyz9UjprgFUQ==
dependencies:
"@babel/standalone" "^7.0.0"
bootstrap-vue "2.18.1"