diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-12-05 06:13:51 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-12-05 06:13:51 +0300 |
commit | c20abe491ceeb1b8e1350f18f0c91e0a31c73cb5 (patch) | |
tree | b8f9c5888b0ec18b24eb49f790a253ddc7905f1a | |
parent | 35850d3d1643a9e2c5328f45b8a9026ac3d86e35 (diff) |
Add latest changes from gitlab-org/gitlab@master
-rw-r--r-- | GITALY_SERVER_VERSION | 2 | ||||
-rw-r--r-- | app/assets/javascripts/vue_merge_request_widget/components/approvals/approvals.vue | 20 | ||||
-rw-r--r-- | doc/administration/auditor_users.md | 2 | ||||
-rw-r--r-- | doc/administration/backup_restore/index.md | 168 | ||||
-rw-r--r-- | doc/administration/gitaly/configure_gitaly.md | 47 | ||||
-rw-r--r-- | doc/administration/settings/gitaly_timeouts.md | 70 | ||||
-rw-r--r-- | doc/development/mass_insert.md | 2 | ||||
-rw-r--r-- | doc/user/compliance/compliance_center/index.md | 17 | ||||
-rw-r--r-- | doc/user/project/repository/monorepos/index.md | 2 | ||||
-rw-r--r-- | locale/gitlab.pot | 50 | ||||
-rw-r--r-- | spec/frontend/fixtures/merge_requests.rb | 8 | ||||
-rw-r--r-- | spec/frontend/vue_merge_request_widget/components/approvals/approvals_spec.js | 60 | ||||
-rw-r--r-- | spec/lib/gitlab/utils/file_info_spec.rb | 4 | ||||
-rw-r--r-- | spec/requests/api/merge_request_approvals_spec.rb | 2 | ||||
-rw-r--r-- | spec/services/merge_requests/approval_service_spec.rb | 1 |
15 files changed, 365 insertions, 90 deletions
diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION index 0b564deaff7..29ada2ea395 100644 --- a/GITALY_SERVER_VERSION +++ b/GITALY_SERVER_VERSION @@ -1 +1 @@ -251acb8c75aa66481893bf775a44cba669ccc3c9 +c0b07ba36fc8fc40830f061cb55a5c951a166e1c diff --git a/app/assets/javascripts/vue_merge_request_widget/components/approvals/approvals.vue b/app/assets/javascripts/vue_merge_request_widget/components/approvals/approvals.vue index a29393d9f93..524f2c045e6 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/approvals/approvals.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/approvals/approvals.vue @@ -1,6 +1,7 @@ <script> import { GlButton, GlSprintf } from '@gitlab/ui'; import { createAlert } from '~/alert'; +import { visitUrl } from '~/lib/utils/url_utility'; import { STATUS_MERGED } from '~/issues/constants'; import { BV_SHOW_MODAL } from '~/lib/utils/constants'; import { HTTP_STATUS_UNAUTHORIZED } from '~/lib/utils/http_status'; @@ -114,6 +115,13 @@ export default { return this.userHasApproved && !this.userCanApprove && this.mr.state !== STATUS_MERGED; }, approvalText() { + // Repeating a text of this to keep i18n easier to do (vs, construcing a compound string) + if (this.requireSamlAuthToApprove) { + return this.isApproved && this.approvedBy.length > 0 + ? s__('mrWidget|Approve additionally with SAML') + : s__('mrWidget|Approve with SAML'); + } + return this.isApproved && this.approvedBy.length > 0 ? s__('mrWidget|Approve additionally') : s__('mrWidget|Approve'); @@ -161,14 +169,20 @@ export default { .join(', ') .concat('.'); }, + requireSamlAuthToApprove() { + return this.mr.requireSamlAuthToApprove; + }, }, methods: { approve() { + if (this.requireSamlAuthToApprove) { + this.approveWithSamlAuth(); + return; + } if (this.requirePasswordToApprove) { this.$root.$emit(BV_SHOW_MODAL, this.modalId); return; } - this.updateApproval( () => this.service.approveMergeRequest(), () => @@ -179,6 +193,10 @@ export default { ), ); }, + approveWithSamlAuth() { + // Intentionally direct to SAML Identity Provider for renewed authorization even if SSO session exists + visitUrl(this.mr.samlApprovalPath); + }, approveWithAuth(data) { this.updateApproval( () => this.service.approveMergeRequestWithAuth(data), diff --git a/doc/administration/auditor_users.md b/doc/administration/auditor_users.md index 0355f7a3661..f57d09f79b8 100644 --- a/doc/administration/auditor_users.md +++ b/doc/administration/auditor_users.md @@ -35,7 +35,7 @@ To create a new user account with auditor access (or change an existing user): To create a user account with auditor access: 1. On the left sidebar, at the bottom, select **Admin Area**. -1. On the left sidebar, select **Overview > Users**. +1. Select **Overview > Users**. 1. Create a new user or edit an existing one. Set **Access Level** to **Auditor**. 1. If you created a user, select **Create user**. For an existing user, select **Save changes**. diff --git a/doc/administration/backup_restore/index.md b/doc/administration/backup_restore/index.md index cf7c5c3db9a..d8ee58e42d7 100644 --- a/doc/administration/backup_restore/index.md +++ b/doc/administration/backup_restore/index.md @@ -36,6 +36,174 @@ methods to export or back up your data yourself from GitLab.com. Issues are stored in the database, and can't be stored in Git itself. +## GitLab backup archive creation process + +When working with GitLab backups, you might need to know how GitLab creates backup archives. To create backup archives, GitLab: + +1. If creating an incremental backup, extracts the previous backup archive and read its `backup_information.yml` file. +1. Updates or generates the `backup_information.yml` file. +1. Runs all backup sub-tasks: + - `db` to backup the GitLab PostgreSQL database (not Gitaly Cluster). + - `repositories` to back up Git repositories. + - `uploads` to back up attachments. + - `builds` to back up CI job output logs. + - `artifacts` to back up CI job artifacts. + - `pages` to back up page content. + - `lfs` to back up LFS objects. + - `terraform_state` to back up Terraform states. + - `registry` to back up container registry images. + - `packages` to back up packages. + - `ci_secure_files` to back up project-level secure files. +1. Archives the backup staging area into a tar file. +1. Optional. Uploads the new backup archive to object-storage. +1. Cleans up backup staging directory files that are now archived. + +## Backup staging directory + +The backup staging directory is a place to temporarily: + +- Store backup artifacts on disk before the GitLab backup archive is created. +- Extract backup archives on disk before restoring a backup or creating an incremental backup. + +This directory is the same directory where completed GitLab backup archives are created. When creating an untarred backup, the backup artifacts are left in this directory and no +archive is created. + +Example backup staging directory with untarred backup: + +```plaintext +backups/ +├── 1701728344_2023_12_04_16.7.0-pre_gitlab_backup.tar +├── 1701728447_2023_12_04_16.7.0-pre_gitlab_backup.tar +├── artifacts.tar.gz +├── backup_information.yml +├── builds.tar.gz +├── ci_secure_files.tar.gz +├── db +│ ├── ci_database.sql.gz +│ └── database.sql.gz +├── lfs.tar.gz +├── packages.tar.gz +├── pages.tar.gz +├── repositories +│ ├── manifests/ +│ ├── @hashed/ +│ └── @snippets/ +├── terraform_state.tar.gz +└── uploads.tar.gz +``` + +## `backup_information.yml` file + +The `backup_information.yml` file saves all backup inputs that are not included in the backup itself. It includes information such as: + +- The time the backup was created. +- The version of GitLab that generated the backup. +- Any options that were specified, such as skipped sub-tasks. + +This information is used by some sub-tasks to determine how: + +- To restore. +- To link data in the backup with external services (such as server-side repository backups). + +This file is saved into the backup staging directory. + +## Database backups + +Database backups are created and restored by a GitLab backup sub-task called `db`. The database sub-task uses `pg_dump` to create [a SQL dump](https://www.postgresql.org/docs/14/backup-dump.html). The output of `pg_dump` is piped through `gzip` in order to create a compressed SQL file. This file is saved to the backup staging directory. + +## Repository backups + +Repository backups are created and restored by a GitLab backup sub-task called `repositories`. The repositories sub-task uses a Gitaly command +[`gitaly-backup`](https://gitlab.com/gitlab-org/gitaly/-/blob/master/doc/gitaly-backup.md) to create Git repository backups: + +- GitLab uses its database to tell `gitaly-backup` which repositories to back up. +- `gitaly-backup` then calls a series of RPCs on Gitaly to collect the repository backup data for each repository. This data is streamed into a directory structure in the GitLab backup staging directory. + +```mermaid +sequenceDiagram + box Backup host + participant Repositories sub-task + participant gitaly-backup + end + + Repositories sub-task->>+gitaly-backup: List of repositories + + loop Each repository + gitaly-backup->>+Gitaly: ListRefs request + Gitaly->>-gitaly-backup: List of Git references + + gitaly-backup->>+Gitaly: CreateBundleFromRefList request + Gitaly->>-gitaly-backup: Git bundle file + + gitaly-backup->>+Gitaly: GetCustomHooks request + Gitaly->>-gitaly-backup: Custom hooks archive + end + + gitaly-backup->>-Repositories sub-task: Success/failure +``` + +Storages configured to Gitaly Cluster are backed up the same as standalone Gitaly. When Gitaly Cluster receives the RPC calls from `gitaly-backup`, it is responsible for +rebuilding its own database. This means that there is no need to backup the Gitaly Cluster database separately. Because backups operate through RPCs, each repository is only backed +up once no matter the replication factor. + +### Server-side repository backups + +You can configure repository backups as server-side repository backups. When specified, `gitaly-backup` makes a single RPC call for each repository to create the backup. This RPC +does not transmit any repository data. Instead, the RPC triggers the Gitaly node that stores that physical repository to upload the backup data directly to object-storage. Because +the data is no longer transmitted through RPCs from Gitaly, server-side backups require much less network transfer and require no disk storage on the machine that is running the +backup Rake task. The backups stored on object-storage are linked to the created backup archive by [the backup name](backup_gitlab.md#backup-timestamp). + +```mermaid +sequenceDiagram + box Backup host + participant Repositories sub-task + participant gitaly-backup + end + + Repositories sub-task->>+gitaly-backup: List of repositories + + loop Each repository + gitaly-backup->>+Gitaly: BackupRepository request + + Gitaly->>+Object-storage: Git references file + Object-storage->>-Gitaly: Success/failure + + Gitaly->>+Object-storage: Git bundle file + Object-storage->>-Gitaly: Success/failure + + Gitaly->>+Object-storage: Custom hooks archive + Object-storage->>-Gitaly: Success/failure + + Gitaly->>+Object-storage: Backup manifest file + Object-storage->>-Gitaly: Success/failure + + Gitaly->>-gitaly-backup: Success/failure + end + + gitaly-backup->>-Repositories sub-task: Success/failure +``` + +## File backups + +The following GitLab backup sub-tasks back up files: + +- `uploads` +- `builds` +- `artifacts` +- `pages` +- `lfs` +- `terraform_state` +- `registry` +- `packages` +- `ci_secure_files` + +These file sub-tasks determine a set of files within a directory specific to the task. This set of files is then passed to `tar` +to create an archive. This archive is piped (not saved to disk) through `gzip` to save a compressed tar file to the backup staging directory. + +Because backups are created from live instances, the files that tar is trying to archive can sometimes be modified while creating the backup. In this case, an alternate "copy" +strategy can be used. When this strategy is used, `rsync` is first used to create a copy of the files to back up. Then, these copies are passed to `tar` as usual. In this case, +the machine running the backup Rake task must have enough storage for the copied files and the compressed archive. + ## Related features - [Geo](../geo/index.md) diff --git a/doc/administration/gitaly/configure_gitaly.md b/doc/administration/gitaly/configure_gitaly.md index 891416a7deb..535e35cc012 100644 --- a/doc/administration/gitaly/configure_gitaly.md +++ b/doc/administration/gitaly/configure_gitaly.md @@ -1542,50 +1542,3 @@ go_cloud_url = "s3://gitaly-backups?region=minio&endpoint=my.minio.local:8080&di ``` ::EndTabs - -## Configure negotiation timeouts - -> [Introduced](https://gitlab.com/gitlab-org/gitaly/-/issues/5574) in GitLab 16.5. - -Gitaly supports configurable negotiation timeouts. - -Negotiation timeouts can be configured for the `git-upload-pack(1)` and `git-upload-archive(1)` -operations, which are invoked by a Gitaly node when you execute the `git fetch` and -`git archive --remote` commands respectively. You might need to increase the negotiation timeout: - -- For particularly large repositories. -- When performing these commands in parallel. - -These timeouts affect only the [negotiation phase](https://git-scm.com/docs/pack-protocol/2.2.3#_packfile_negotiation) of -remote Git operations, not the entire transfer. - -Valid values for timeouts follow the format of [`ParseDuration`](https://pkg.go.dev/time#ParseDuration) in Go. - -How you configure negotiation timeouts depends on the type of installation you have: - -::Tabs - -:::TabTitle Linux package (Omnibus) - -Edit `/etc/gitlab/gitlab.rb`: - -```ruby -gitaly['configuration'] = { - timeout: { - upload_pack_negotiation: '10m', # 10 minutes - upload_archive_negotiation: '20m', # 20 minutes - } -} -``` - -:::TabTitle Self-compiled (source) - -Edit `/home/git/gitaly/config.toml`: - -```toml -[timeout] -upload_pack_negotiation = "10m" -upload_archive_negotiation = "20m" -``` - -::EndTabs diff --git a/doc/administration/settings/gitaly_timeouts.md b/doc/administration/settings/gitaly_timeouts.md index b60cf141cf6..93db0467d70 100644 --- a/doc/administration/settings/gitaly_timeouts.md +++ b/doc/administration/settings/gitaly_timeouts.md @@ -6,23 +6,75 @@ info: To determine the technical writer assigned to the Stage/Group associated w # Gitaly timeouts **(FREE SELF)** -[Gitaly](../gitaly/index.md) timeouts are configurable. The timeouts can be -configured to make sure that long-running Gitaly calls don't needlessly take up resources. +[Gitaly](../gitaly/index.md) provides two types of configurable timeouts: -To access Gitaly timeout settings: +- Call timeouts, configured by using the GitLab UI. +- Negotiation timeouts, configured by using Gitaly configuration files. + +## Configure the call timeouts + +Configure the following call timeouts to make sure that long-running Gitaly calls don't needlessly take up resources. To +configure the call timeouts: 1. On the left sidebar, at the bottom, select **Admin Area**. 1. Select **Settings > Preferences**. 1. Expand the **Gitaly timeouts** section. +1. Set each timeout as required. -## Available timeouts +### Available call timeouts -The following timeouts are available. +Different call timeouts are available for different Gitaly operations. | Timeout | Default | Description | |:--------|:-----------|:------------| -| Default | 55 seconds | Timeout for most Gitaly calls (not enforced for `git` `fetch` and `push` operations, or Sidekiq jobs). For example, checking if a repository exists on disk. Makes sure that Gitaly calls made within a web request cannot exceed the entire request timeout. It should be shorter than the [worker timeout](../operations/puma.md#change-the-worker-timeout) that can be configured for [Puma](../../install/requirements.md#puma-settings). If a Gitaly call timeout exceeds the worker timeout, the remaining time from the worker timeout is used to avoid having to terminate the worker. | -| Fast | 10 seconds | Timeout for fast Gitaly operations used within requests, sometimes multiple times. For example, checking if a repository exists on disk. If fast operations exceed this threshold, there may be a problem with a storage shard. Failing fast can help maintain the stability of the GitLab instance. | -| Medium | 30 seconds | Timeout for Gitaly operations that should be fast (possibly within requests) but preferably not used multiple times within a request. For example, loading blobs. Timeout that should be set between Default and Fast. | +| Default | 55 seconds | Timeout for most Gitaly calls (not enforced for `git` `fetch` and `push` operations, or Sidekiq jobs). For example, checking if a repository exists on disk. Makes sure that Gitaly calls made in a web request cannot exceed the entire request timeout. It should be shorter than the [worker timeout](../operations/puma.md#change-the-worker-timeout) that can be configured for [Puma](../../install/requirements.md#puma-settings). If a Gitaly call timeout exceeds the worker timeout, the remaining time from the worker timeout is used to avoid having to terminate the worker. | +| Fast | 10 seconds | Timeout for fast Gitaly operations used in requests, sometimes multiple times. For example, checking if a repository exists on disk. If fast operations exceed this threshold, there may be a problem with a storage shard. Failing fast can help maintain the stability of the GitLab instance. | +| Medium | 30 seconds | Timeout for Gitaly operations that should be fast (possibly in requests) but preferably not used multiple times in a request. For example, loading blobs. Timeout that should be set between Default and Fast. | + +## Configure the negotiation timeouts + +> [Introduced](https://gitlab.com/gitlab-org/gitaly/-/issues/5574) in GitLab 16.5. + +You might need to increase the negotiation timeout: + +- For particularly large repositories. +- When performing these commands in parallel. + +You can configure negotiation timeouts for: + +- `git-upload-pack(1)`, which is invoked by a Gitaly node when you execute `git fetch`. +- `git-upload-archive(1)`, which is invoked by a Gitaly node when you execute `git archive --remote`. + +To configure these timeouts: + +::Tabs + +:::TabTitle Linux package (Omnibus) + +Edit `/etc/gitlab/gitlab.rb`: + +```ruby +gitaly['configuration'] = { + timeout: { + upload_pack_negotiation: '10m', # 10 minutes + upload_archive_negotiation: '20m', # 20 minutes + } +} +``` + +:::TabTitle Self-compiled (source) + +Edit `/home/git/gitaly/config.toml`: + +```toml +[timeout] +upload_pack_negotiation = "10m" +upload_archive_negotiation = "20m" +``` + +::EndTabs + +For the values, use the format of [`ParseDuration`](https://pkg.go.dev/time#ParseDuration) in Go. -You can also [configure negotiation timeouts](../gitaly/configure_gitaly.md#configure-negotiation-timeouts). +These timeouts affect only the [negotiation phase](https://git-scm.com/docs/pack-protocol/2.2.3#_packfile_negotiation) of +remote Git operations, not the entire transfer. diff --git a/doc/development/mass_insert.md b/doc/development/mass_insert.md index e16f162abfa..412639927a7 100644 --- a/doc/development/mass_insert.md +++ b/doc/development/mass_insert.md @@ -15,5 +15,5 @@ the following snippet in the rails console. ```ruby u = User.find(1) -Project.last(100).each { |p| p.set_timestamps_for_create && p.add_maintainer(u, current_user: u) } # Change 100 to whatever number of projects you need access to +Project.last(100).each { |p| p.send(:set_timestamps_for_create) && p.add_maintainer(u, current_user: u) } # Change 100 to whatever number of projects you need access to ``` diff --git a/doc/user/compliance/compliance_center/index.md b/doc/user/compliance/compliance_center/index.md index 0f2cce67721..df1883f95d9 100644 --- a/doc/user/compliance/compliance_center/index.md +++ b/doc/user/compliance/compliance_center/index.md @@ -188,8 +188,8 @@ To export a report of merge request compliance violations for projects in a grou 1. On the left sidebar, select **Search or go to** and find your group. 1. On the left sidebar, select **Secure > Compliance center**. -1. On the page, select the **Violations** tab. -1. On the Violations tab, select the **Export full report as CSV** action in the top right corner +1. Select the **Export** action in the top right corner +1. Select **Export violations report** A report is compiled and delivered to your email inbox as an attachment. @@ -235,7 +235,8 @@ To generate the Chain of Custody report: 1. On the left sidebar, select **Search or go to** and find your group. 1. On the left sidebar, select **Secure > Compliance center**. -1. Select **List of all merge commits**. +1. Select the **Export** action in the top right corner +1. Select **Export chain of custody report** Depending on your version of GitLab, the Chain of Custody report is either sent through email or available for download. @@ -251,9 +252,9 @@ To generate a commit-specific Chain of Custody report: 1. On the left sidebar, select **Search or go to** and find your group. 1. On the left sidebar, select **Secure > Compliance center**. -1. At the top of the compliance report, to the right of **List of all commits**, select the down arrow - (**{chevron-lg-down}**). -1. Enter the commit SHA, and then select **Export commit custody report**. +1. Select the **Export** action in the top right corner +1. Select **Export custody report of a specific commit** +1. Enter the commit SHA, and then select **Export custody report**. Depending on your version of GitLab, the Chain of Custody report is either sent through email or available for download. @@ -358,8 +359,8 @@ To export a report of compliance frameworks on projects in a group: 1. On the left sidebar, select **Search or go to** and find your group. 1. On the left sidebar, select **Secure > Compliance center**. -1. On the page, select the **Projects** tab. -1. On the Frameworks tab, select the **Export as CSV** action in the top right corner +1. Select the **Export** action in the top right corner +1. Select **Export list of project frameworks** A report is compiled and delivered to your email inbox as an attachment. diff --git a/doc/user/project/repository/monorepos/index.md b/doc/user/project/repository/monorepos/index.md index 144f46cd7d5..b73757a952e 100644 --- a/doc/user/project/repository/monorepos/index.md +++ b/doc/user/project/repository/monorepos/index.md @@ -189,7 +189,7 @@ You might experience a `fatal: the remote end hung up unexpectedly` error when a - The same large repository in parallel. You can attempt to mitigate this issue by increasing the default negotiation timeout values. For more information, see -[Configure negotiation timeouts](../../../../administration/gitaly/configure_gitaly.md#configure-negotiation-timeouts). +[Configure the negotiation timeouts](../../../../administration/settings/gitaly_timeouts.md#configure-the-negotiation-timeouts). ## Optimize your repository diff --git a/locale/gitlab.pot b/locale/gitlab.pot index aa789f786a3..b6cafab7c4d 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -1439,9 +1439,6 @@ msgstr "" msgid "(leave blank if you don't want to change it)" msgstr "" -msgid "(max size 15 MB)" -msgstr "" - msgid "(no user)" msgstr "" @@ -6111,6 +6108,9 @@ msgstr "" msgid "Approval options" msgstr "" +msgid "Approval rejected." +msgstr "" + msgid "Approval rules" msgstr "" @@ -6272,7 +6272,7 @@ msgstr "" msgid "ApprovalSettings|Remove approvals by Code Owners if their files changed" msgstr "" -msgid "ApprovalSettings|Require user password to approve" +msgid "ApprovalSettings|Require user re-authentication (password or SAML) to approve" msgstr "" msgid "ApprovalSettings|There was an error loading merge request approval settings." @@ -12429,13 +12429,34 @@ msgstr "" msgid "Completed in %{duration_seconds} seconds (%{relative_time})" msgstr "" -msgid "Compliance Center|Export full report as CSV" +msgid "Compliance Center Export|(limited to 15 MB)" +msgstr "" + +msgid "Compliance Center Export|Example: 2dc6aa3" +msgstr "" + +msgid "Compliance Center Export|Export as CSV" +msgstr "" + +msgid "Compliance Center Export|Export chain of custody report" +msgstr "" + +msgid "Compliance Center Export|Export custody report" +msgstr "" + +msgid "Compliance Center Export|Export custody report of a specific commit" msgstr "" -msgid "Compliance Center|Export merge request violations as CSV. You will be emailed after the export is processed." +msgid "Compliance Center Export|Export list of project frameworks" msgstr "" -msgid "Compliance Center|Export projects as CSV. You will be emailed after the export is processed." +msgid "Compliance Center Export|Export violations report" +msgstr "" + +msgid "Compliance Center Export|Invalid hash" +msgstr "" + +msgid "Compliance Center Export|Send email of the chosen report as CSV" msgstr "" msgid "Compliance Center|Frameworks" @@ -19975,9 +19996,6 @@ msgstr "" msgid "Export as CSV" msgstr "" -msgid "Export commit custody report" -msgstr "" - msgid "Export group" msgstr "" @@ -25935,9 +25953,6 @@ msgstr "" msgid "Invalid format selected" msgstr "" -msgid "Invalid hash" -msgstr "" - msgid "Invalid input, please avoid emoji" msgstr "" @@ -28695,9 +28710,6 @@ msgstr "" msgid "List available repositories" msgstr "" -msgid "List of all commits" -msgstr "" - msgid "List of suitable GCP locations" msgstr "" @@ -57854,6 +57866,12 @@ msgstr "" msgid "mrWidget|Approve additionally" msgstr "" +msgid "mrWidget|Approve additionally with SAML" +msgstr "" + +msgid "mrWidget|Approve with SAML" +msgstr "" + msgid "mrWidget|Approved by" msgstr "" diff --git a/spec/frontend/fixtures/merge_requests.rb b/spec/frontend/fixtures/merge_requests.rb index a1896a6470b..e8272a1f93a 100644 --- a/spec/frontend/fixtures/merge_requests.rb +++ b/spec/frontend/fixtures/merge_requests.rb @@ -2,7 +2,13 @@ require 'spec_helper' -RSpec.describe Projects::MergeRequestsController, '(JavaScript fixtures)', type: :controller do +RSpec + .describe( + Projects::MergeRequestsController, + '(JavaScript fixtures)', + type: :controller, + feature_category: :code_review_workflow + ) do include JavaScriptFixturesHelpers let(:namespace) { create(:namespace, name: 'frontend-fixtures') } diff --git a/spec/frontend/vue_merge_request_widget/components/approvals/approvals_spec.js b/spec/frontend/vue_merge_request_widget/components/approvals/approvals_spec.js index 2aed037be6f..c81f4328d2a 100644 --- a/spec/frontend/vue_merge_request_widget/components/approvals/approvals_spec.js +++ b/spec/frontend/vue_merge_request_widget/components/approvals/approvals_spec.js @@ -4,6 +4,7 @@ import { GlButton, GlSprintf } from '@gitlab/ui'; import { shallowMount } from '@vue/test-utils'; import { createMockSubscription as createMockApolloSubscription } from 'mock-apollo-client'; import approvedByCurrentUser from 'test_fixtures/graphql/merge_requests/approvals/approvals.query.graphql.json'; +import { visitUrl } from '~/lib/utils/url_utility'; import createMockApollo from 'helpers/mock_apollo_helper'; import waitForPromises from 'helpers/wait_for_promises'; import { getIdFromGraphQLId } from '~/graphql_shared/utils'; @@ -28,6 +29,10 @@ jest.mock('~/alert', () => ({ dismiss: mockAlertDismiss, })), })); +jest.mock('~/lib/utils/url_utility', () => ({ + ...jest.requireActual('~/lib/utils/url_utility'), + visitUrl: jest.fn(), +})); const TEST_HELP_PATH = 'help/path'; const testApprovedBy = () => [1, 7, 10].map((id) => ({ id })); @@ -113,6 +118,7 @@ describe('MRWidget approvals', () => { targetProjectFullPath: 'gitlab-org/gitlab', id: 1, iid: '1', + requireSamlAuthToApprove: false, }; jest.spyOn(eventHub, '$emit').mockImplementation(() => {}); @@ -172,6 +178,22 @@ describe('MRWidget approvals', () => { category: 'primary', }); }); + + describe('with SAML auth requried for approval', () => { + beforeEach(async () => { + const response = createCanApproveResponse(); + mr.requireSamlAuthToApprove = true; + createComponent({}, { query: response }); + await waitForPromises(); + }); + it('approve action is rendered with correct text', () => { + expect(findActionData()).toEqual({ + variant: 'confirm', + text: 'Approve with SAML', + category: 'primary', + }); + }); + }); }); describe('and MR is approved', () => { @@ -194,6 +216,25 @@ describe('MRWidget approvals', () => { }); }); + describe('with approvers, with SAML auth requried for approval', () => { + beforeEach(async () => { + canApproveResponse.data.project.mergeRequest.approvedBy.nodes = + approvedByCurrentUser.data.project.mergeRequest.approvedBy.nodes; + canApproveResponse.data.project.mergeRequest.approvedBy.nodes[0].id = 69; + mr.requireSamlAuthToApprove = true; + createComponent({}, { query: canApproveResponse }); + await waitForPromises(); + }); + + it('approve additionally action is rendered with correct text', () => { + expect(findActionData()).toEqual({ + variant: 'confirm', + text: 'Approve additionally with SAML', + category: 'secondary', + }); + }); + }); + describe('with approvers', () => { beforeEach(async () => { canApproveResponse.data.project.mergeRequest.approvedBy.nodes = @@ -215,6 +256,25 @@ describe('MRWidget approvals', () => { }); }); + describe('when SAML auth is required and user clicks Approve with SAML', () => { + const fakeGroupSamlPath = '/example_group_saml'; + + beforeEach(async () => { + mr.requireSamlAuthToApprove = true; + mr.samlApprovalPath = fakeGroupSamlPath; + + createComponent({}, { query: createCanApproveResponse() }); + await waitForPromises(); + }); + + it('redirects the user to the group SAML path', async () => { + const action = findAction(); + action.vm.$emit('click'); + await nextTick(); + expect(visitUrl).toHaveBeenCalledWith(fakeGroupSamlPath); + }); + }); + describe('when approve action is clicked', () => { beforeEach(async () => { createComponent({}, { query: canApproveResponse }); diff --git a/spec/lib/gitlab/utils/file_info_spec.rb b/spec/lib/gitlab/utils/file_info_spec.rb index 480036b2fd0..1f52fcb48b6 100644 --- a/spec/lib/gitlab/utils/file_info_spec.rb +++ b/spec/lib/gitlab/utils/file_info_spec.rb @@ -16,7 +16,7 @@ RSpec.describe Gitlab::Utils::FileInfo, feature_category: :shared do describe '.linked?' do it 'raises an error when file does not exist' do - expect { subject.linked?('foo') }.to raise_error(Errno::ENOENT) + expect { subject.linked?("#{tmpdir}/foo") }.to raise_error(Errno::ENOENT) end shared_examples 'identifies a linked file' do @@ -56,7 +56,7 @@ RSpec.describe Gitlab::Utils::FileInfo, feature_category: :shared do describe '.shares_hard_link?' do it 'raises an error when file does not exist' do - expect { subject.shares_hard_link?('foo') }.to raise_error(Errno::ENOENT) + expect { subject.shares_hard_link?("#{tmpdir}/foo") }.to raise_error(Errno::ENOENT) end shared_examples 'identifies a file that shares a hard link' do diff --git a/spec/requests/api/merge_request_approvals_spec.rb b/spec/requests/api/merge_request_approvals_spec.rb index df2b20c62c3..2de59750273 100644 --- a/spec/requests/api/merge_request_approvals_spec.rb +++ b/spec/requests/api/merge_request_approvals_spec.rb @@ -8,8 +8,6 @@ RSpec.describe API::MergeRequestApprovals, feature_category: :source_code_manage let_it_be(:bot) { create(:user, :project_bot) } let_it_be(:project) { create(:project, :public, :repository, creator: user, namespace: user.namespace) } let_it_be(:approver) { create :user } - let_it_be(:group) { create :group } - let(:merge_request) { create(:merge_request, :simple, author: user, source_project: project) } describe 'GET :id/merge_requests/:merge_request_iid/approvals' do diff --git a/spec/services/merge_requests/approval_service_spec.rb b/spec/services/merge_requests/approval_service_spec.rb index e7fe5c19fa3..8761aba432f 100644 --- a/spec/services/merge_requests/approval_service_spec.rb +++ b/spec/services/merge_requests/approval_service_spec.rb @@ -13,6 +13,7 @@ RSpec.describe MergeRequests::ApprovalService, feature_category: :code_review_wo before do project.add_developer(user) + stub_feature_flags ff_require_saml_auth_to_approve: false end context 'with invalid approval' do |