Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
4b4d338d32
commit
5092e9b37c
54 changed files with 2189 additions and 1202 deletions
|
@ -7,14 +7,34 @@ module Resolvers
|
|||
alias_method :project, :object
|
||||
|
||||
argument :iid, GraphQL::ID_TYPE,
|
||||
required: true,
|
||||
description: 'IID of the Pipeline, e.g., "1".'
|
||||
required: false,
|
||||
description: 'IID of the Pipeline. For example, "1".'
|
||||
|
||||
def resolve(iid:)
|
||||
BatchLoader::GraphQL.for(iid).batch(key: project) do |iids, loader, args|
|
||||
finder = ::Ci::PipelinesFinder.new(project, context[:current_user], iids: iids)
|
||||
argument :sha, GraphQL::STRING_TYPE,
|
||||
required: false,
|
||||
description: 'SHA of the Pipeline. For example, "dyd0f15ay83993f5ab66k927w28673882x99100b".'
|
||||
|
||||
finder.execute.each { |pipeline| loader.call(pipeline.iid.to_s, pipeline) }
|
||||
def ready?(iid: nil, sha: nil)
|
||||
unless iid.present? ^ sha.present?
|
||||
raise Gitlab::Graphql::Errors::ArgumentError, 'Provide one of an IID or SHA'
|
||||
end
|
||||
|
||||
super
|
||||
end
|
||||
|
||||
def resolve(iid: nil, sha: nil)
|
||||
if iid
|
||||
BatchLoader::GraphQL.for(iid).batch(key: project) do |iids, loader, args|
|
||||
finder = ::Ci::PipelinesFinder.new(project, current_user, iids: iids)
|
||||
|
||||
finder.execute.each { |pipeline| loader.call(pipeline.iid.to_s, pipeline) }
|
||||
end
|
||||
else
|
||||
BatchLoader::GraphQL.for(sha).batch(key: project) do |shas, loader, args|
|
||||
finder = ::Ci::PipelinesFinder.new(project, current_user, shas: shas)
|
||||
|
||||
finder.execute.each { |pipeline| loader.call(pipeline.sha.to_s, pipeline) }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -95,6 +95,9 @@ module Types
|
|||
field :path, GraphQL::STRING_TYPE, null: true,
|
||||
description: "Relative path to the pipeline's page."
|
||||
|
||||
field :commit_path, GraphQL::STRING_TYPE, null: true,
|
||||
description: 'Path to the commit that triggered the pipeline.'
|
||||
|
||||
field :project, Types::ProjectType, null: true,
|
||||
description: 'Project the pipeline belongs to.'
|
||||
|
||||
|
@ -109,6 +112,10 @@ module Types
|
|||
Gitlab::Graphql::Loaders::BatchModelLoader.new(User, object.user_id).find
|
||||
end
|
||||
|
||||
def commit_path
|
||||
::Gitlab::Routing.url_helpers.project_commit_path(object.project, object.sha)
|
||||
end
|
||||
|
||||
def path
|
||||
::Gitlab::Routing.url_helpers.project_pipeline_path(object.project, object)
|
||||
end
|
||||
|
|
|
@ -812,14 +812,15 @@ module Ci
|
|||
end
|
||||
|
||||
def cache
|
||||
cache = options[:cache]
|
||||
cache = Array.wrap(options[:cache])
|
||||
|
||||
if cache && project.jobs_cache_index
|
||||
cache = cache.merge(
|
||||
key: "#{cache[:key]}-#{project.jobs_cache_index}")
|
||||
if project.jobs_cache_index
|
||||
cache = cache.map do |single_cache|
|
||||
single_cache.merge(key: "#{single_cache[:key]}-#{project.jobs_cache_index}")
|
||||
end
|
||||
end
|
||||
|
||||
[cache]
|
||||
cache
|
||||
end
|
||||
|
||||
def credentials
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Allow search for pipeline by SHA as well as IID via GraphQL
|
||||
merge_request: 54471
|
||||
author:
|
||||
type: changed
|
5
changelogs/unreleased/lm-multiple-cache-per-file.yml
Normal file
5
changelogs/unreleased/lm-multiple-cache-per-file.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Adds ability to have multiple cache per job
|
||||
merge_request: 53410
|
||||
author:
|
||||
type: changed
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
name: multiple_cache_per_job
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/53410
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/321877
|
||||
milestone: '13.10'
|
||||
type: development
|
||||
group: group::pipeline authoring
|
||||
default_enabled: false
|
|
@ -201,4 +201,4 @@ successfully, you must replicate their data using some other means.
|
|||
| [GitLab Pages](../../pages/index.md) | [No](https://gitlab.com/groups/gitlab-org/-/epics/589) | No | No | |
|
||||
| [CI Pipeline Artifacts](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/models/ci/pipeline_artifact.rb) | [No](https://gitlab.com/gitlab-org/gitlab/-/issues/238464) | No | Via Object Storage provider if supported. Native Geo support (Beta). | Persists additional artifacts after a pipeline completes |
|
||||
| [Dependency proxy images](../../../user/packages/dependency_proxy/index.md) | [No](https://gitlab.com/gitlab-org/gitlab/-/issues/259694) | No | No | Blocked on [Geo: Secondary Mimicry](https://gitlab.com/groups/gitlab-org/-/epics/1528). Note that replication of this cache is not needed for Disaster Recovery purposes because it can be recreated from external sources. |
|
||||
| [Vulnerability Export](../../../user/application_security/vulnerability_report/#export-vulnerabilities) | [Not planned](https://gitlab.com/groups/gitlab-org/-/epics/3111) | No | Via Object Storage provider if supported. Native Geo support (Beta). | Not planned because they are ephemeral and sensitive. They can be regenerated on demand. |
|
||||
| [Vulnerability Export](../../../user/application_security/vulnerability_report/#export-vulnerability-details) | [Not planned](https://gitlab.com/groups/gitlab-org/-/epics/3111) | No | Via Object Storage provider if supported. Native Geo support (Beta). | Not planned because they are ephemeral and sensitive. They can be regenerated on demand. |
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1890,7 +1890,7 @@ This endpoint:
|
|||
merge requests).
|
||||
- From [GitLab 13.2](https://gitlab.com/gitlab-org/gitlab/-/issues/220382) on
|
||||
[Premium or higher](https://about.gitlab.com/pricing/) tiers, group
|
||||
admins can [configure](../user/group/index.md#enabling-delayed-project-removal)
|
||||
admins can [configure](../user/group/index.md#enable-delayed-project-removal)
|
||||
projects within a group to be deleted after a delayed period. When enabled,
|
||||
actual deletion happens after the number of days specified in the
|
||||
[default deletion delay](../user/admin_area/settings/visibility_and_access_controls.md#default-deletion-delay).
|
||||
|
@ -1898,7 +1898,7 @@ This endpoint:
|
|||
WARNING:
|
||||
The default behavior of [Delayed Project deletion](https://gitlab.com/gitlab-org/gitlab/-/issues/32935)
|
||||
in GitLab 12.6 was changed to [Immediate deletion](https://gitlab.com/gitlab-org/gitlab/-/issues/220382)
|
||||
in GitLab 13.2, as discussed in [Enabling delayed project removal](../user/group/index.md#enabling-delayed-project-removal).
|
||||
in GitLab 13.2, as discussed in [Enable delayed project removal](../user/group/index.md#enable-delayed-project-removal).
|
||||
|
||||
```plaintext
|
||||
DELETE /projects/:id
|
||||
|
|
|
@ -2754,7 +2754,62 @@ URI-encoded `%2F`. A value made only of dots (`.`, `%2E`) is also forbidden.
|
|||
|
||||
You can specify a [fallback cache key](#fallback-cache-key) to use if the specified `cache:key` is not found.
|
||||
|
||||
##### Fallback cache key
|
||||
##### Multiple caches
|
||||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/32814) in GitLab 13.10.
|
||||
> - It's [deployed behind a feature flag](../../user/feature_flags.md), disabled by default.
|
||||
> - It's disabled on GitLab.com.
|
||||
> - It's not recommended for production use.
|
||||
> - To use it in GitLab self-managed instances, ask a GitLab administrator to [enable it](#enable-or-disable-multiple-caches). **(FREE SELF)**
|
||||
|
||||
WARNING:
|
||||
This feature might not be available to you. Check the **version history** note above for details.
|
||||
|
||||
You can have a maximum of four caches:
|
||||
|
||||
```yaml
|
||||
test-job:
|
||||
stage: build
|
||||
cache:
|
||||
- key:
|
||||
files:
|
||||
- Gemfile.lock
|
||||
paths:
|
||||
- vendor/ruby
|
||||
- key:
|
||||
files:
|
||||
- yarn.lock
|
||||
paths:
|
||||
- .yarn-cache/
|
||||
script:
|
||||
- bundle install --path=vendor
|
||||
- yarn install --cache-folder .yarn-cache
|
||||
- echo Run tests...
|
||||
```
|
||||
|
||||
If multiple caches are combined with a [Fallback cache key](#fallback-cache-key),
|
||||
the fallback is fetched multiple times if multiple caches are not found.
|
||||
|
||||
##### Enable or disable multiple caches **(FREE SELF)**
|
||||
|
||||
The multiple caches feature is under development and not ready for production use.
|
||||
It is deployed behind a feature flag that is **disabled by default**.
|
||||
[GitLab administrators with access to the GitLab Rails console](../../administration/feature_flags.md)
|
||||
can enable it.
|
||||
|
||||
To enable it:
|
||||
|
||||
```ruby
|
||||
Feature.enable(:multiple_cache_per_job)
|
||||
```
|
||||
|
||||
To disable it:
|
||||
|
||||
```ruby
|
||||
Feature.disable(:multiple_cache_per_job)
|
||||
```
|
||||
|
||||
#### Fallback cache key
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab-runner/-/merge_requests/1534) in GitLab Runner 13.4.
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ This document lists the different implementations of CSV export in GitLab codeba
|
|||
| Downloading | - Query and write data in batches to a temporary file.<br>- Loads the file into memory.<br>- Sends the file to the client. | - Report available immediately. | - Large amount of data might cause request timeout.<br>- Memory intensive.<br>- Request expires when user navigates to a different page. | [Export Chain of Custody Report](../user/compliance/compliance_dashboard/#chain-of-custody-report) |
|
||||
| As email attachment | - Asynchronously process the query with background job.<br>- Email uses the export as an attachment. | - Asynchronous processing. | - Requires users use a different app (email) to download the CSV.<br>- Email providers may limit attachment size. | - [Export Issues](../user/project/issues/csv_export.md)<br>- [Export Merge Requests](../user/project/merge_requests/csv_export.md) |
|
||||
| As downloadable link in email (*) | - Asynchronously process the query with background job.<br>- Email uses an export link. | - Asynchronous processing.<br>- Bypasses email provider attachment size limit. | - Requires users use a different app (email).<br>- Requires additional storage and cleanup. | [Export User Permissions](https://gitlab.com/gitlab-org/gitlab/-/issues/1772) |
|
||||
| Polling (non-persistent state) | - Asynchronously processes the query with the background job.<br>- Frontend(FE) polls every few seconds to check if CSV file is ready. | - Asynchronous processing.<br>- Automatically downloads to local machine on completion.<br>- In-app solution. | - Non-persistable request - request expires when user navigates to a different page.<br>- API is processed for each polling request. | [Export Vulnerabilities](../user/application_security/vulnerability_report/#export-vulnerabilities) |
|
||||
| Polling (non-persistent state) | - Asynchronously processes the query with the background job.<br>- Frontend(FE) polls every few seconds to check if CSV file is ready. | - Asynchronous processing.<br>- Automatically downloads to local machine on completion.<br>- In-app solution. | - Non-persistable request - request expires when user navigates to a different page.<br>- API is processed for each polling request. | [Export Vulnerabilities](../user/application_security/vulnerability_report/#export-vulnerability-details) |
|
||||
| Polling (persistent state) (*) | - Asynchronously processes the query with background job.<br>- Backend (BE) maintains the export state<br>- FE polls every few seconds to check status.<br>- FE shows 'Download link' when export is ready.<br>- User can download or regenerate a new report. | - Asynchronous processing.<br>- No database calls made during the polling requests (HTTP 304 status is returned until export status changes).<br>- Does not require user to stay on page until export is complete.<br>- In-app solution.<br>- Can be expanded into a generic CSV feature (such as dashboard / CSV API). | - Requires to maintain export states in DB.<br>- Does not automatically download the CSV export to local machine, requires users to click 'Download' button. | [Export Merge Commits Report](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/43055) |
|
||||
|
||||
NOTE:
|
||||
|
|
|
@ -28,7 +28,7 @@ the tiers are no longer mentioned in GitLab documentation:
|
|||
- [Managing group memberships via LDAP](../user/group/index.md#manage-group-memberships-via-ldap)
|
||||
- [Member locking](../user/group/index.md#prevent-members-from-being-added-to-a-group)
|
||||
- [Overriding user permissions](../user/group/index.md#override-user-permissions)
|
||||
- [User contribution analysis](../user/group/index.md#user-contribution-analysis)
|
||||
- [User contribution analytics](../user/group/contribution_analytics/index.md)
|
||||
- [Kerberos integration](../integration/kerberos.md)
|
||||
- Issue Boards:
|
||||
- [Configurable issue boards](../user/project/issue_board.md#configurable-issue-boards)
|
||||
|
|
|
@ -79,7 +79,7 @@ The default behavior of [Delayed Project deletion](https://gitlab.com/gitlab-org
|
|||
[Immediate deletion](https://gitlab.com/gitlab-org/gitlab/-/issues/220382) in GitLab 13.2.
|
||||
|
||||
Projects in a group (but not a personal namespace) can be deleted after a delayed period, by
|
||||
[configuring in Group Settings](../../group/index.md#enabling-delayed-project-removal).
|
||||
[configuring in Group Settings](../../group/index.md#enable-delayed-project-removal).
|
||||
The default period is seven days, and can be changed. Setting this period to `0` enables immediate removal
|
||||
of projects or groups.
|
||||
|
||||
|
|
|
@ -5,42 +5,80 @@ group: Threat Insights
|
|||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
|
||||
---
|
||||
|
||||
# GitLab Vulnerability Reports **(ULTIMATE)**
|
||||
# Vulnerability Report **(ULTIMATE)**
|
||||
|
||||
Each vulnerability report contains vulnerabilities from the scans of the most recent branch merged into the default branch.
|
||||
The Vulnerability Report provides information about vulnerabilities from scans of the branch most
|
||||
recently merged into the default branch. It is available at the instance, group, and project level.
|
||||
|
||||
The vulnerability reports display the total number of vulnerabilities by severity (for example,
|
||||
Critical, High, Medium, Low, Info, Unknown). Below this, a table shows each vulnerability's detected date, status, severity, description, identifier, the scanner where it was detected, and activity (including related issues or available solutions). By default, the vulnerability report is filtered to display all detected and confirmed vulnerabilities.
|
||||
The Vulnerability Report contains:
|
||||
|
||||
- Totals of vulnerabilities per severity level.
|
||||
- Filters for common vulnerability attributes.
|
||||
- Details of each vulnerability, presented in tabular layout.
|
||||
|
||||
The project-level Vulnerability Report also contains:
|
||||
|
||||
- A time stamp showing when it was updated, including a link to the latest pipeline.
|
||||
- The number of failures that occurred in the most recent pipeline. Select the failure
|
||||
notification to view the **Failed jobs** tab of the pipeline's page.
|
||||
|
||||
![Vulnerability Report](img/group_vulnerability_report_v13_9.png)
|
||||
|
||||
Clicking any vulnerability in the table takes you to its
|
||||
[vulnerability details](../vulnerabilities) page to see more information on that vulnerability.
|
||||
From the Vulnerability Report you can:
|
||||
|
||||
The **Activity** column indicates the number of issues that have been created for the vulnerability.
|
||||
Hover over an **Activity** entry and select a link go to that issue.
|
||||
- [Filter the list of vulnerabilities](#filter-the-list-of-vulnerabilities).
|
||||
- [View more details about a vulnerability](#view-details-of-a-vulnerability).
|
||||
- [View an issue raised for a vulnerability](#view-issues-raised-for-a-vulnerability).
|
||||
- [Change the status of vulnerabilities](#change-status-of-vulnerabilities).
|
||||
- [Export details of vulnerabilities](#export-vulnerability-details).
|
||||
|
||||
![Display attached issues](img/vulnerability_list_table_v13_9.png)
|
||||
## Vulnerability filters
|
||||
|
||||
## Filter options
|
||||
You can filter the vulnerabilities table by:
|
||||
|
||||
You can filter which vulnerabilities display by:
|
||||
|
||||
| Filter | Available options |
|
||||
| Filter | Available options |
|
||||
|:---------|:------------------|
|
||||
| Status | Detected, Confirmed, Dismissed, Resolved |
|
||||
| Severity | Critical, High, Medium, Low, Info, Unknown |
|
||||
| Status | Detected, Confirmed, Dismissed, Resolved. |
|
||||
| Severity | Critical, High, Medium, Low, Info, Unknown. |
|
||||
| Scanner | [Available scanners](../index.md#security-scanning-tools). |
|
||||
| Project | Projects configured in the Security Center settings, or all projects in the group for the group level report. This filter is not displayed on the project level vulnerability report. |
|
||||
| Activity | Vulnerabilities with issues and vulnerabilities that are no longer detected in the default branch. |
|
||||
| Project | For more details, see [Project filter](#project-filter). |
|
||||
| Activity | For more details, see [Activity filter](#activity-filter). |
|
||||
|
||||
### Filter the list of vulnerabilities
|
||||
|
||||
To filter the list of vulnerabilities:
|
||||
|
||||
1. Select a filter.
|
||||
1. Select values from the dropdown.
|
||||
1. Repeat the above steps for each desired filter.
|
||||
|
||||
The vulnerability table is applied immediately. The vulnerability severity totals are also updated.
|
||||
|
||||
The filters' criteria are combined to show only vulnerabilities matching all criteria.
|
||||
An exception to this behavior is the Activity filter. For more details about how it works, see
|
||||
[Activity filter](#activity-filter).
|
||||
|
||||
### Project filter
|
||||
|
||||
The content of the Project filter depends on the current level:
|
||||
|
||||
| Level | Content of the Project filter |
|
||||
|:---------------|:------------------------------|
|
||||
| Instance level | Only projects you've [added to the instance-level Security Center](../security_dashboard/index.md#adding-projects-to-the-security-center). |
|
||||
| Group level | All projects in the group. |
|
||||
| Project level | Not applicable. |
|
||||
|
||||
### Activity filter
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/259255) in GitLab 13.9
|
||||
|
||||
The Activity filter behaves differently from the other Vulnerability Report filters. The other filter options all OR together to show results from any vulnerability matching one of the filter criteria. With the Activity filter, the selected values form mutually exclusive sets to allow for precisely locating the desired vulnerability records. Additionally, not all options can be selected in combination. Selection behavior when using the Activity filter:
|
||||
The Activity filter behaves differently from the other filters. The selected values form mutually
|
||||
exclusive sets to allow for precisely locating the desired vulnerability records. Additionally, not
|
||||
all options can be selected in combination.
|
||||
|
||||
| Activity Selection | Results Displayed |
|
||||
Selection behavior when using the Activity filter:
|
||||
|
||||
| Activity selection | Results displayed |
|
||||
|:------------------------------------|:------------------|
|
||||
| All | Vulnerabilities with any Activity status (same as ignoring this filter). Selecting this will deselect any other Activity filter options. |
|
||||
| No activity | Only vulnerabilities without either an associated Issue or that are no longer detected. Selecting this will deselect any other Activity filter options. |
|
||||
|
@ -48,9 +86,21 @@ The Activity filter behaves differently from the other Vulnerability Report filt
|
|||
| No longer detected | Only vulnerabilities that are no longer detected in the latest pipeline scan of the `default` branch. Does not include vulnerabilities with one or more associated issues. |
|
||||
| With issues and No longer detected | Only vulnerabilities that have one or more associated issues and also are no longer detected in the latest pipeline scan of the `default` branch. |
|
||||
|
||||
Contents of the unfiltered vulnerability report can be exported using our [export feature](#export-vulnerabilities).
|
||||
## View details of a vulnerability
|
||||
|
||||
You can also change the status of vulnerabilities in the table:
|
||||
To view more details of a vulnerability, select the vulnerability's **Description**. The
|
||||
[vulnerability's details](../vulnerabilities) page is opened.
|
||||
|
||||
## View issues raised for a vulnerability
|
||||
|
||||
The **Activity** column indicates the number of issues that have been created for the vulnerability.
|
||||
Hover over an **Activity** entry and select a link go to that issue.
|
||||
|
||||
![Display attached issues](img/vulnerability_list_table_v13_9.png)
|
||||
|
||||
## Change status of vulnerabilities
|
||||
|
||||
To change the status of vulnerabilities in the table:
|
||||
|
||||
1. Select the checkbox for each vulnerability you want to update the status of.
|
||||
1. In the dropdown that appears select the desired status, then select **Change status**.
|
||||
|
@ -72,31 +122,37 @@ the **Failed jobs** tab of the pipeline page.
|
|||
|
||||
![Project Vulnerability Report](img/project_security_dashboard_v13_9.png)
|
||||
|
||||
## Export vulnerabilities
|
||||
## Export vulnerability details
|
||||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/213014) in the Security Center (previously known as the Instance Security Dashboard) and project-level Vulnerability Report (previously known as the Project Security Dashboard) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 13.0.
|
||||
> - [Added](https://gitlab.com/gitlab-org/gitlab/-/issues/213013) to the group-level Vulnerability Report in [GitLab Ultimate](https://about.gitlab.com/pricing/) 13.1.
|
||||
|
||||
You can export all your vulnerabilities in CSV (comma separated values) format by clicking the
|
||||
**{upload}** **Export** button located at top right of the Security Dashboard. When the report is
|
||||
ready, the CSV report downloads to your local machine. The report contains all vulnerabilities for
|
||||
the projects defined in the Security Dashboard, as filters don't apply to the export function.
|
||||
You can export details of the vulnerabilities listed in the Vulnerability Report. The export format
|
||||
is CSV (comma separated values). Note that all vulnerabilities are included because filters don't
|
||||
apply to the export.
|
||||
|
||||
Fields included are:
|
||||
|
||||
- Group name
|
||||
- Project name
|
||||
- Scanner type
|
||||
- Scanner name
|
||||
- Status
|
||||
- Vulnerability
|
||||
- Details
|
||||
- Additional information
|
||||
- Severity
|
||||
- [CVE](https://cve.mitre.org/) (Common Vulnerabilities and Exposures)
|
||||
- [CWE](https://cwe.mitre.org/) (Common Weakness Enumeration)
|
||||
- Other identifiers
|
||||
|
||||
### Export details in CSV format
|
||||
|
||||
To export details of all vulnerabilities listed in the Vulnerability Report, select **Export**.
|
||||
|
||||
The details are retrieved from the database, then the CSV file is downloaded to your local
|
||||
computer.
|
||||
|
||||
NOTE:
|
||||
It may take several minutes for the download to start if your project contains
|
||||
thousands of vulnerabilities. Don't close the page until the download finishes.
|
||||
|
||||
The fields in the export include:
|
||||
|
||||
- Group Name
|
||||
- Project Name
|
||||
- Scanner Type
|
||||
- Scanner Name
|
||||
- Status
|
||||
- Vulnerability
|
||||
- Details
|
||||
- Additional Information
|
||||
- Severity
|
||||
- [CVE](https://cve.mitre.org/) (Common Vulnerabilities and Exposures)
|
||||
- [CWE](https://cwe.mitre.org/) (Common Weakness Enumeration)
|
||||
- Other Identifiers
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 39 KiB |
Binary file not shown.
Before Width: | Height: | Size: 9.3 KiB |
Binary file not shown.
Before Width: | Height: | Size: 3.1 KiB |
Binary file not shown.
Before Width: | Height: | Size: 63 KiB |
BIN
doc/user/group/img/select_group_dropdown_13_10.png
Normal file
BIN
doc/user/group/img/select_group_dropdown_13_10.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 36 KiB |
Binary file not shown.
Before Width: | Height: | Size: 7.3 KiB |
|
@ -59,7 +59,7 @@ To create a group:
|
|||
- Alphanumeric characters
|
||||
- Emojis
|
||||
- Underscores
|
||||
- Dashes, dots, spaces and parenthesis (however, it cannot start with any of these characters)
|
||||
- Dashes, dots, spaces, and parentheses (however, it cannot start with any of these characters)
|
||||
|
||||
For a list of words that cannot be used as group names, see [reserved names](../reserved_names.md).
|
||||
|
||||
|
@ -214,13 +214,9 @@ In [GitLab Premium or higher](https://about.gitlab.com/pricing/), GitLab adminis
|
|||
There are two different ways to add a new project to a group:
|
||||
|
||||
- Select a group, and then click **New project**. You can then continue [creating your project](../../user/project/working_with_projects.md#create-a-project).
|
||||
- While you are creating a project, select a group from the dropdown menu.
|
||||
|
||||
![New project](img/create_new_project_from_group_v13_6.png)
|
||||
|
||||
- While you are creating a project, select a group namespace
|
||||
you've already created from the dropdown menu.
|
||||
|
||||
![Select group](img/select_group_dropdown.png)
|
||||
![Select group](img/select_group_dropdown_13_10.png)
|
||||
|
||||
### Specify who can add projects to a group
|
||||
|
||||
|
@ -261,22 +257,11 @@ You can view the most recent actions taken in a group.
|
|||
To view the activity feed in Atom format, select the
|
||||
**RSS** (**{rss}**) icon.
|
||||
|
||||
## Transfer projects into groups
|
||||
|
||||
Learn how to [transfer a project into a group](../project/settings/index.md#transferring-an-existing-project-into-another-namespace).
|
||||
|
||||
## Share a project with a group
|
||||
|
||||
You can [share your projects with a group](../project/members/share_project_with_groups.md)
|
||||
and give all group members access to the project at once.
|
||||
|
||||
Alternatively, you can [lock the sharing with group feature](#prevent-a-project-from-being-shared-with-groups).
|
||||
|
||||
## Share a group with another group
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/18328) in GitLab 12.7.
|
||||
|
||||
Similar to how you [share a project with a group](#share-a-project-with-a-group),
|
||||
Similar to how you [share a project with a group](../project/members/share_project_with_groups.md),
|
||||
you can share a group with another group. Members get direct access
|
||||
to the shared group. This is not valid for inherited members.
|
||||
|
||||
|
@ -301,7 +286,7 @@ Group links can be created by using either a CN or a filter. To create these gro
|
|||
For more information on the administration of LDAP and group sync, refer to the [main LDAP documentation](../../administration/auth/ldap/index.md#group-sync).
|
||||
|
||||
NOTE:
|
||||
If an LDAP user is a group member when LDAP Synchronization is added, and they are not part of the LDAP group, they are removed from the group.
|
||||
When you add LDAP synchronization, if an LDAP user is a group member and they are not part of the LDAP group, they are removed from the group.
|
||||
|
||||
### Create group links via CN **(PREMIUM SELF)**
|
||||
|
||||
|
@ -311,7 +296,7 @@ To create group links via CN:
|
|||
|
||||
1. Select the **LDAP Server** for the link.
|
||||
1. As the **Sync method**, select `LDAP Group cn`.
|
||||
1. In the **LDAP Group cn** text input box, begin typing the CN of the group. There is a dropdown menu with matching CNs within the configured `group_base`. Select your CN from this list.
|
||||
1. In the **LDAP Group cn** field, begin typing the CN of the group. There is a dropdown menu with matching CNs in the configured `group_base`. Select your CN from this list.
|
||||
1. In the **LDAP Access** section, select the [permission level](../permissions.md) for users synced in this group.
|
||||
1. Select the **Add Synchronization** button.
|
||||
|
||||
|
@ -329,7 +314,7 @@ To create group links via filter:
|
|||
|
||||
### Override user permissions **(PREMIUM SELF)**
|
||||
|
||||
LDAP user permissions can be manually overridden by an admin user. To override a user's permissions:
|
||||
LDAP user permissions can be manually overridden by an administrator. To override a user's permissions:
|
||||
|
||||
1. Go to your group's **Members** page.
|
||||
1. In the row for the user you are editing, select the pencil (**{pencil}**) icon.
|
||||
|
@ -337,28 +322,16 @@ LDAP user permissions can be manually overridden by an admin user. To override a
|
|||
|
||||
Now you can edit the user's permissions from the **Members** page.
|
||||
|
||||
## Epics **(ULTIMATE)**
|
||||
|
||||
> Introduced in [GitLab Ultimate](https://about.gitlab.com/pricing/) 10.2.
|
||||
|
||||
Epics let you manage your portfolio of projects more efficiently and with less
|
||||
effort by tracking groups of issues that share a theme, across projects and
|
||||
milestones.
|
||||
|
||||
[Learn more about Epics.](epics/index.md)
|
||||
|
||||
## Group wikis **(PREMIUM)**
|
||||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/13195) in [GitLab Premium](https://about.gitlab.com/pricing/) 13.5.
|
||||
|
||||
Group wikis work the same way as [project wikis](../project/wiki/index.md), please refer to those docs for details on usage.
|
||||
Group wikis work the same way as [project wikis](../project/wiki/index.md).
|
||||
|
||||
Group wikis can be edited by members with [Developer permissions](../../user/permissions.md#group-members-permissions)
|
||||
and above.
|
||||
|
||||
Group wiki repositories can be moved through the [Group repository storage moves API](../../api/group_repository_storage_moves.md).
|
||||
|
||||
### Group wikis limitations
|
||||
You can move group wiki repositories by using the [Group repository storage moves API](../../api/group_repository_storage_moves.md).
|
||||
|
||||
There are a few limitations compared to project wikis:
|
||||
|
||||
|
@ -366,29 +339,7 @@ There are a few limitations compared to project wikis:
|
|||
- Group wikis are not included in global search and Geo replication.
|
||||
- Changes to group wikis don't show up in the group's activity feed.
|
||||
|
||||
For updates, you can follow:
|
||||
|
||||
- [The epic tracking feature parity with project wikis](https://gitlab.com/groups/gitlab-org/-/epics/2782).
|
||||
|
||||
## Group Security Dashboard **(ULTIMATE)**
|
||||
|
||||
Get an overview of the vulnerabilities of all the projects in a group and its subgroups.
|
||||
|
||||
[Learn more about the Group Security Dashboard.](../application_security/security_dashboard/index.md)
|
||||
|
||||
## Insights **(ULTIMATE)**
|
||||
|
||||
> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/725) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 12.0.
|
||||
|
||||
Configure the Insights that matter for your groups or projects, allowing users
|
||||
to explore data such as:
|
||||
|
||||
- Triage hygiene
|
||||
- Issues created/closed per a given period
|
||||
- Average time for merge requests to be merged
|
||||
- Much more
|
||||
|
||||
[Learn more about Insights](insights/index.md).
|
||||
For updates, follow [the epic that tracks feature parity with project wikis](https://gitlab.com/groups/gitlab-org/-/epics/2782).
|
||||
|
||||
## Transfer a group
|
||||
|
||||
|
@ -403,66 +354,66 @@ When transferring groups, note:
|
|||
- Changing a group's parent can have unintended side effects. See [Redirects when changing repository paths](../project/repository/index.md#redirects-when-changing-repository-paths).
|
||||
- You can only transfer groups to groups you manage.
|
||||
- You must update your local repositories to point to the new location.
|
||||
- If the immediate parent group's visibility is lower than the group's current visibility, visibility levels for subgroups and projects will change to match the new parent group's visibility.
|
||||
- If the immediate parent group's visibility is lower than the group's current visibility, visibility levels for subgroups and projects change to match the new parent group's visibility.
|
||||
- Only explicit group membership is transferred, not inherited membership. If the group's owners have only inherited membership, this leaves the group without an owner. In this case, the user transferring the group becomes the group's owner.
|
||||
- Transfers will fail if [packages](../packages/index.md) exist in any of the projects within the group, or in any of its subgroups.
|
||||
- Transfers fail if [packages](../packages/index.md) exist in any of the projects in the group, or in any of its subgroups.
|
||||
|
||||
## Change a group's path
|
||||
|
||||
Changing a group's path (group URL) can have unintended side effects. Read
|
||||
[how redirects will behave](../project/repository/index.md#redirects-when-changing-repository-paths)
|
||||
before proceeding.
|
||||
[how redirects behave](../project/repository/index.md#redirects-when-changing-repository-paths)
|
||||
before you proceed.
|
||||
|
||||
If you are vacating the path so it can be claimed by another group or user,
|
||||
you may need to rename the group too, since both names and paths must
|
||||
If you are changing the path so it can be claimed by another group or user,
|
||||
you may need to rename the group too. Both names and paths must
|
||||
be unique.
|
||||
|
||||
To retain ownership of the original namespace and protect the URL redirects,
|
||||
create a new group and transfer projects to it instead.
|
||||
|
||||
To change your group path (group URL):
|
||||
|
||||
1. Navigate to your group's **Settings > General** page.
|
||||
1. Go to your group's **Settings > General** page.
|
||||
1. Expand the **Path, transfer, remove** section.
|
||||
1. Enter a new name under **Change group URL**.
|
||||
1. Click **Change group URL**.
|
||||
1. Under **Change group URL**, enter a new name.
|
||||
1. Select **Change group URL**.
|
||||
|
||||
WARNING:
|
||||
It is currently not possible to rename a namespace if it contains a
|
||||
It is not possible to rename a namespace if it contains a
|
||||
project with [Container Registry](../packages/container_registry/index.md) tags,
|
||||
because the project cannot be moved.
|
||||
|
||||
NOTE:
|
||||
If you want to retain ownership over the original namespace and
|
||||
protect the URL redirects, then instead of changing a group's path or renaming a
|
||||
username, you can create a new group and transfer projects to it.
|
||||
|
||||
## Use a custom name for the initial branch
|
||||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/43290) in GitLab 13.6.
|
||||
|
||||
By default, when you create a new project in GitLab, the initial branch is called `master`.
|
||||
For groups, a group owner can customize the initial branch name to something
|
||||
else. This way, every new project created under that group from then on will start from the custom branch name rather than `master`. To do so:
|
||||
else. This way, every new project created under that group from then on starts from the custom branch name rather than `master`.
|
||||
|
||||
1. Go to the **Group page > Settings > Repository** and expand **Default initial
|
||||
branch name**.
|
||||
To use a custom name for the initial branch:
|
||||
|
||||
1. Go to the group's **Settings > Repository** page.
|
||||
1. Expand the **Default initial branch name** section.
|
||||
1. Change the default initial branch to a custom name of your choice.
|
||||
1. **Save Changes**.
|
||||
1. Select **Save changes**.
|
||||
|
||||
## Remove a group
|
||||
|
||||
To remove a group and its contents:
|
||||
|
||||
1. Navigate to your group's **Settings > General** page.
|
||||
1. Go to your group's **Settings > General** page.
|
||||
1. Expand the **Path, transfer, remove** section.
|
||||
1. In the Remove group section, click the **Remove group** button.
|
||||
1. Confirm the action when asked to.
|
||||
1. In the Remove group section, select **Remove group**.
|
||||
1. Confirm the action.
|
||||
|
||||
This action either:
|
||||
This action removes the group. It also adds a background job to delete all projects in the group.
|
||||
|
||||
- Removes the group, and also queues a background job to delete all projects in that group.
|
||||
- Since [GitLab 12.8](https://gitlab.com/gitlab-org/gitlab/-/issues/33257), on [Premium](https://about.gitlab.com/pricing/premium/) or higher tiers, this action adds a background job to mark a group for deletion. By default, the job schedules the deletion 7 days in the future. You can modify this waiting period through the [instance settings](../admin_area/settings/visibility_and_access_controls.md#default-deletion-delay).
|
||||
Specifically:
|
||||
|
||||
Since [GitLab 13.6](https://gitlab.com/gitlab-org/gitlab/-/issues/39504), if the user who sets up the deletion leaves or is otherwise removed from the group before the
|
||||
actual deletion happens, the job is cancelled, and the group is no longer scheduled for deletion.
|
||||
- In [GitLab 12.8 and later](https://gitlab.com/gitlab-org/gitlab/-/issues/33257), on [Premium](https://about.gitlab.com/pricing/premium/) or higher tiers, this action adds a background job to mark a group for deletion. By default, the job schedules the deletion 7 days in the future. You can modify this waiting period through the [instance settings](../admin_area/settings/visibility_and_access_controls.md#default-deletion-delay).
|
||||
- In [GitLab 13.6 and later](https://gitlab.com/gitlab-org/gitlab/-/issues/39504), if the user who sets up the deletion is removed from the group before the
|
||||
deletion happens, the job is cancelled, and the group is no longer scheduled for deletion.
|
||||
|
||||
## Restore a group **(PREMIUM)**
|
||||
|
||||
|
@ -470,15 +421,9 @@ actual deletion happens, the job is cancelled, and the group is no longer schedu
|
|||
|
||||
To restore a group that is marked for deletion:
|
||||
|
||||
1. Navigate to your group's **Settings > General** page.
|
||||
1. Go to your group's **Settings > General** page.
|
||||
1. Expand the **Path, transfer, remove** section.
|
||||
1. In the Restore group section, click the **Restore group** button.
|
||||
|
||||
## Enforce two-factor authentication for group members
|
||||
|
||||
Add a security layer to your group by
|
||||
[enforcing two-factor authentication (2FA)](../../security/two_factor_authentication.md#enforcing-2fa-for-all-users-in-a-group)
|
||||
for all group members.
|
||||
1. In the Restore group section, select **Restore group**.
|
||||
|
||||
## Prevent a project from being shared with groups
|
||||
|
||||
|
@ -486,34 +431,33 @@ Prevent projects in a group from [sharing
|
|||
a project with another group](../project/members/share_project_with_groups.md) to enable tighter control over project access.
|
||||
|
||||
For example, let's say you have two distinct teams (Group A and Group B) working together in a project, and to inherit the group membership, you share the project between the
|
||||
two groups A and B. **Share with group lock** prevents any project within
|
||||
two groups A and B. **Share with group lock** prevents any project in
|
||||
the group from being shared with another group,
|
||||
guaranteeing that only the right group members have access to those projects.
|
||||
|
||||
To enable this feature, navigate to the group settings page. Select
|
||||
**Share with group lock** and **Save the group**.
|
||||
To prevent a project from being shared with groups:
|
||||
|
||||
![Checkbox for share with group lock](img/share_with_group_lock.png)
|
||||
1. Go to the group's **Settings > General** page.
|
||||
1. Select **Share with group lock**.
|
||||
1. Select **Save the group**.
|
||||
|
||||
## Prevent members from being added to a group **(PREMIUM)**
|
||||
|
||||
Member lock lets a group owner prevent any new project membership to all of the
|
||||
projects within a group, allowing tighter control over project membership.
|
||||
projects in a group, allowing tighter control over project membership.
|
||||
|
||||
For example, if you want to lock the group for an [Audit Event](../../administration/audit_events.md),
|
||||
enable Member lock to guarantee that project membership cannot be modified during that audit.
|
||||
enable member lock to guarantee that project membership cannot be modified during the audit.
|
||||
|
||||
To enable this feature:
|
||||
To prevent members from being added to a group:
|
||||
|
||||
1. Navigate to the group's **Settings > General** page.
|
||||
1. Expand the **Permissions, LFS, 2FA** section, and select **Member lock**.
|
||||
1. Click **Save changes**.
|
||||
1. Go to the group's **Settings > General** page.
|
||||
1. Expand the **Permissions, LFS, 2FA** section.
|
||||
1. Select **Member lock**.
|
||||
1. Select **Save changes**.
|
||||
|
||||
![Checkbox for membership lock](img/member_lock.png)
|
||||
|
||||
This will disable the option for all users who previously had permissions to
|
||||
operate project memberships, so no new users can be added. Furthermore, any
|
||||
request to add a new user to a project through API will not be possible.
|
||||
All users who previously had permissions can no longer add members to a group.
|
||||
API requests to add a new user to a project are not possible.
|
||||
|
||||
## Restrict group access by IP address **(PREMIUM)**
|
||||
|
||||
|
@ -521,13 +465,12 @@ request to add a new user to a project through API will not be possible.
|
|||
> - [Moved](https://gitlab.com/gitlab-org/gitlab/-/issues/215410) to [GitLab Premium](https://about.gitlab.com/pricing/) in 13.1.
|
||||
|
||||
NOTE:
|
||||
IP Access Restrictions are currently not functioning as expected on GitLab.com. If enabled,
|
||||
users cannot perform Git operations through SSH, or access projects via the UI. Please
|
||||
review the [following bug report](https://gitlab.com/gitlab-org/gitlab/-/issues/271673) for
|
||||
more information.
|
||||
IP access restrictions are not functioning as expected on GitLab.com. If enabled,
|
||||
users cannot perform Git operations through SSH, or access projects in the UI.
|
||||
For more information, [see this issue](https://gitlab.com/gitlab-org/gitlab/-/issues/271673).
|
||||
|
||||
To make sure only people from within your organization can access particular
|
||||
resources, you have the option to restrict access to groups and their
|
||||
To ensure only people from your organization can access particular
|
||||
resources, you can restrict access to groups and their
|
||||
underlying subgroups, projects, issues, and so on, by IP address. This can help ensure that
|
||||
particular content doesn't leave the premises, while not blocking off access to
|
||||
the entire instance. IP access restrictions can only be configured at the group level.
|
||||
|
@ -545,55 +488,48 @@ Restriction currently applies to:
|
|||
To avoid accidental lock-out, admins and group owners are able to access
|
||||
the group regardless of the IP restriction.
|
||||
|
||||
To enable this feature:
|
||||
To restrict group access by IP address:
|
||||
|
||||
1. Navigate to the group’s **Settings > General** page.
|
||||
1. Expand the **Permissions, LFS, 2FA** section, and enter IP address ranges into **Allow access to the following IP addresses** field.
|
||||
1. Click **Save changes**.
|
||||
1. Go to the group’s **Settings > General** page.
|
||||
1. Expand the **Permissions, LFS, 2FA** section.
|
||||
1. In the **Allow access to the following IP addresses** field, enter IP address ranges.
|
||||
1. Select **Save changes**.
|
||||
|
||||
![Domain restriction by IP address](img/restrict-by-ip.gif)
|
||||
|
||||
## Restrict group access by domain **(PREMIUM)**
|
||||
|
||||
>- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/7297) in [GitLab Premium](https://about.gitlab.com/pricing/) 12.2.
|
||||
>- Support for specifying multiple email domains [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/33143) in GitLab 13.1
|
||||
>- Support for specifying multiple email domains [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/33143) added in GitLab 13.1.
|
||||
|
||||
You can restrict access to groups by allowing only users with email addresses in particular domains to be added to the group.
|
||||
You can prevent users with email addresses in specific domains from being added to a group.
|
||||
|
||||
Add email domains you want to allow and users with emails from different domains won't be allowed to be added to this group.
|
||||
To restrict group access by domain:
|
||||
|
||||
Some domains cannot be restricted. These are the most popular public email domains, such as:
|
||||
|
||||
- `gmail.com`
|
||||
- `yahoo.com`
|
||||
- `hotmail.com`
|
||||
- `aol.com`
|
||||
- `msn.com`
|
||||
- `hotmail.co.uk`
|
||||
- `hotmail.fr`
|
||||
- `live.com`
|
||||
- `outlook.com`
|
||||
- `icloud.com`
|
||||
|
||||
To enable this feature:
|
||||
|
||||
1. Navigate to the group's **Settings > General** page.
|
||||
1. Expand the **Permissions, LFS, 2FA** section, and enter the domain names into **Restrict membership by email** field.
|
||||
1. Click **Save changes**.
|
||||
1. Go to the group's **Settings > General** page.
|
||||
1. Expand the **Permissions, LFS, 2FA** section.
|
||||
1. In the **Restrict membership by email** field, enter the domain names.
|
||||
1. Select **Save changes**.
|
||||
|
||||
![Domain restriction by email](img/restrict-by-email.gif)
|
||||
|
||||
This will enable the domain-checking for all new users added to the group from this moment on.
|
||||
Any time you attempt to add a new user, they are compared against this list.
|
||||
|
||||
Some domains cannot be restricted. These are the most popular public email domains, such as:
|
||||
|
||||
- `gmail.com`, `yahoo.com`, `aol.com`, `icloud.com`
|
||||
- `hotmail.com`, `hotmail.co.uk`, `hotmail.fr`
|
||||
- `msn.com`, `live.com`, `outlook.com`
|
||||
|
||||
NOTE:
|
||||
Domain restrictions only apply to groups and do not prevent users from being added as members of projects owned by the restricted group.
|
||||
Domain restrictions apply to groups only. They do not prevent users from being added as members of projects owned by the restricted group.
|
||||
|
||||
## Group file templates **(PREMIUM)**
|
||||
|
||||
Group file templates allow you to share a set of templates for common file
|
||||
Use group file templates to share a set of templates for common file
|
||||
types with every project in a group. It is analogous to the
|
||||
[instance template repository](../admin_area/settings/instance_template_repository.md)
|
||||
feature, and the selected project should follow the same naming conventions as
|
||||
[instance template repository](../admin_area/settings/instance_template_repository.md).
|
||||
The selected project should follow the same naming conventions as
|
||||
are documented on that page.
|
||||
|
||||
You can only choose projects in the group as the template source.
|
||||
|
@ -601,18 +537,17 @@ This includes projects shared with the group, but it **excludes** projects in
|
|||
subgroups or parent groups of the group being configured.
|
||||
|
||||
You can configure this feature for both subgroups and immediate parent groups. A project
|
||||
in a subgroup will have access to the templates for that subgroup, as well as
|
||||
in a subgroup has access to the templates for that subgroup, as well as
|
||||
any immediate parent groups.
|
||||
|
||||
![Group file template dropdown](img/group_file_template_dropdown.png)
|
||||
To enable group file templates:
|
||||
|
||||
To enable this feature, navigate to the group settings page, expand the
|
||||
**Templates** section, choose a project to act as the template repository, and
|
||||
**Save group**.
|
||||
1. Go to the group settings page.
|
||||
1. Expand the **Templates** section.
|
||||
1. Choose a project to act as the template repository.
|
||||
1. Select **Save group**.
|
||||
|
||||
![Group file template settings](img/group_file_template_settings.png)
|
||||
|
||||
To learn how to create templates for issues and merge requests, visit
|
||||
To learn how to create templates for issues and merge requests, see
|
||||
[Description templates](../project/description_templates.md).
|
||||
|
||||
### Group-level project templates **(PREMIUM)**
|
||||
|
@ -620,19 +555,20 @@ To learn how to create templates for issues and merge requests, visit
|
|||
Define project templates at a group level by setting a group as the template source.
|
||||
[Learn more about group-level project templates](custom_project_templates.md).
|
||||
|
||||
## Disabling email notifications
|
||||
## Disable email notifications
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/23585) in GitLab 12.2.
|
||||
|
||||
You can disable all email notifications related to the group, which includes its subgroups and projects.
|
||||
|
||||
To enable this feature:
|
||||
To disable email notifications:
|
||||
|
||||
1. Navigate to the group's **Settings > General** page.
|
||||
1. Expand the **Permissions, LFS, 2FA** section, and select **Disable email notifications**.
|
||||
1. Click **Save changes**.
|
||||
1. Go to the group's **Settings > General** page.
|
||||
1. Expand the **Permissions, LFS, 2FA** section.
|
||||
1. Select **Disable email notifications**.
|
||||
1. Select **Save changes**.
|
||||
|
||||
## Disabling group mentions
|
||||
## Disable group mentions
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/21301) in GitLab 12.6.
|
||||
|
||||
|
@ -643,28 +579,30 @@ Groups with disabled mentions are visualized accordingly in the autocompletion d
|
|||
|
||||
This is particularly helpful for groups with a large number of users.
|
||||
|
||||
To enable this feature:
|
||||
To disable group mentions:
|
||||
|
||||
1. Navigate to the group's **Settings > General** page.
|
||||
1. Expand the **Permissions, LFS, 2FA** section, and select **Disable group mentions**.
|
||||
1. Click **Save changes**.
|
||||
1. Go to the group's **Settings > General** page.
|
||||
1. Expand the **Permissions, LFS, 2FA** section.
|
||||
1. Select **Disable group mentions**.
|
||||
1. Select **Save changes**.
|
||||
|
||||
## Enabling delayed project removal **(PREMIUM)**
|
||||
## Enable delayed project removal **(PREMIUM)**
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/220382) in GitLab 13.2.
|
||||
|
||||
By default, projects within a group are deleted immediately.
|
||||
By default, projects in a group are deleted immediately.
|
||||
Optionally, on [Premium](https://about.gitlab.com/pricing/) or higher tiers,
|
||||
you can configure the projects within a group to be deleted after a delayed interval.
|
||||
you can configure the projects in a group to be deleted after a delayed interval.
|
||||
|
||||
During this interval period, the projects will be in a read-only state and can be restored, if required.
|
||||
The interval period defaults to 7 days, and can be modified by an admin in the [instance settings](../admin_area/settings/visibility_and_access_controls.md#default-deletion-delay).
|
||||
During this interval period, the projects are in a read-only state and can be restored, if required.
|
||||
The interval period defaults to 7 days, and can be modified by an administrator in the [instance settings](../admin_area/settings/visibility_and_access_controls.md#default-deletion-delay).
|
||||
|
||||
To enable delayed deletion of projects:
|
||||
|
||||
1. Navigate to the group's **Settings > General** page.
|
||||
1. Expand the **Permissions, LFS, 2FA** section, and check **Enable delayed project removal**.
|
||||
1. Click **Save changes**.
|
||||
1. Go to the group's **Settings > General** page.
|
||||
1. Expand the **Permissions, LFS, 2FA** section.
|
||||
1. Check **Enable delayed project removal**.
|
||||
1. Select **Save changes**.
|
||||
|
||||
NOTE:
|
||||
The group setting for delayed deletion is not inherited by subgroups and has to be individually defined for each group.
|
||||
|
@ -673,29 +611,19 @@ The group setting for delayed deletion is not inherited by subgroups and has to
|
|||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/216987) in GitLab 13.3.
|
||||
|
||||
By default, projects within a group can be forked.
|
||||
By default, projects in a group can be forked.
|
||||
Optionally, on [Premium](https://about.gitlab.com/pricing/) or higher tiers,
|
||||
you can prevent the projects within a group from being forked outside of the current top-level group.
|
||||
you can prevent the projects in a group from being forked outside of the current top-level group.
|
||||
|
||||
Previously this setting was available only for groups enforcing group managed account. This setting will be
|
||||
removed from SAML setting page and migrated to group setting, but in the interim period of changes both of those settings will be taken into consideration, if even one is set to `true` then it will be assumed group does not allow forking projects outside.
|
||||
|
||||
To enable prevent project forking:
|
||||
|
||||
1. Navigate to the top-level group's **Settings > General** page.
|
||||
1. Expand the **Permissions, LFS, 2FA** section, and check **Prevent project forking outside current group**.
|
||||
1. Click **Save changes**.
|
||||
|
||||
## Advanced settings
|
||||
|
||||
- **Projects**: View all projects within that group, add members to each project,
|
||||
access each project's settings, and remove any project, all from the same screen.
|
||||
- **Webhooks**: Configure [webhooks](../project/integrations/webhooks.md) for your group.
|
||||
- **Kubernetes cluster integration**: Connect your GitLab group with [Kubernetes clusters](clusters/index.md).
|
||||
- **Audit Events**: View [Audit Events](../../administration/audit_events.md#group-events)
|
||||
for the group.
|
||||
- **Pipelines quota**: Keep track of the [pipeline quota](../admin_area/settings/continuous_integration.md) for the group.
|
||||
- **Integrations**: Configure [integrations](../admin_area/settings/project_integration_management.md) for your group.
|
||||
1. Go to the top-level group's **Settings > General** page.
|
||||
1. Expand the **Permissions, LFS, 2FA** section.
|
||||
1. Check **Prevent project forking outside current group**.
|
||||
1. Select **Save changes**.
|
||||
|
||||
## Group push rules **(PREMIUM)**
|
||||
|
||||
|
@ -703,60 +631,43 @@ To enable prevent project forking:
|
|||
> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/224129) in GitLab 13.4.
|
||||
|
||||
Group push rules allow group maintainers to set
|
||||
[push rules](../../push_rules/push_rules.md) for newly created projects within the specific group.
|
||||
[push rules](../../push_rules/push_rules.md) for newly created projects in the specific group.
|
||||
|
||||
To configure push rules for a group, navigate to **{push-rules}** on the group's
|
||||
sidebar.
|
||||
To configure push rules for a group:
|
||||
|
||||
When set, new subgroups have push rules set for them based on either:
|
||||
1. Go to the groups's **Push Rules** page.
|
||||
1. Select the settings you want.
|
||||
1. Select **Save Push Rules**.
|
||||
|
||||
The group's new subgroups have push rules set for them based on either:
|
||||
|
||||
- The closest parent group with push rules defined.
|
||||
- Push rules set at the instance level, if no parent groups have push rules defined.
|
||||
|
||||
## Maximum artifacts size **(FREE SELF)**
|
||||
## Related topics
|
||||
|
||||
For information about setting a maximum artifact size for a group, see
|
||||
[Maximum artifacts size](../admin_area/settings/continuous_integration.md#maximum-artifacts-size).
|
||||
|
||||
## User contribution analysis **(PREMIUM)**
|
||||
|
||||
With [GitLab Contribution Analytics](contribution_analytics/index.md),
|
||||
you have an overview of the contributions (pushes, merge requests,
|
||||
and issues) performed by your group members.
|
||||
|
||||
## Issue analytics **(PREMIUM)**
|
||||
|
||||
With [GitLab Issue Analytics](issues_analytics/index.md), you can see a bar chart of the number of issues created each month in your groups.
|
||||
|
||||
## Repositories analytics **(PREMIUM)**
|
||||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/263478) in GitLab 13.6.
|
||||
> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/276003) in GitLab 13.7.
|
||||
|
||||
With [GitLab Repositories Analytics](repositories_analytics/index.md), you can view overall activity of all projects with code coverage.
|
||||
|
||||
## Dependency Proxy
|
||||
|
||||
Use GitLab as a [dependency proxy](../packages/dependency_proxy/index.md) for upstream Docker images.
|
||||
|
||||
<!-- ## Troubleshooting
|
||||
|
||||
Include any troubleshooting steps that you can foresee. If you know beforehand what issues
|
||||
one might have when setting this up, or when something is changed, or on upgrading, it's
|
||||
important to describe those, too. Think of things that may go wrong and include them here.
|
||||
This is important to minimize requests for support, and to avoid doc comments with
|
||||
questions that you know someone might ask.
|
||||
|
||||
Each scenario can be a third-level heading, e.g. `### Getting error message X`.
|
||||
If you have none to add when creating a doc, leave this section in place
|
||||
but commented out to help encourage others to add to it in the future. -->
|
||||
|
||||
## DORA4 analytics overview **(ULTIMATE ONLY)**
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/291747) in GitLab [Ultimate](https://about.gitlab.com/pricing/) 13.9 as a [Beta feature](https://about.gitlab.com/handbook/product/gitlab-the-product/#beta).
|
||||
|
||||
Group details include the following analytics:
|
||||
|
||||
- Deployment Frequency
|
||||
|
||||
For more information, see [DORA4 Project Analytics API](../../api/dora4_group_analytics.md).
|
||||
- [Maximum artifacts size](../admin_area/settings/continuous_integration.md#maximum-artifacts-size). **(FREE SELF)**
|
||||
- [Repositories analytics](repositories_analytics/index.md): View overall activity of all projects with code coverage.
|
||||
[Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/263478) in GitLab 13.6. **(PREMIUM)**
|
||||
- [Contribution analytics](contribution_analytics/index.md): View the contributions (pushes, merge requests,
|
||||
and issues) of group members. **(PREMIUM)**
|
||||
- [Issue analytics](issues_analytics/index.md): View a bar chart of your group's number of issues per month. **(PREMIUM)**
|
||||
- Use GitLab as a [dependency proxy](../packages/dependency_proxy/index.md) for upstream Docker images.
|
||||
- [DORA4 Project Analytics API](../../api/dora4_group_analytics.md): View deployment frequency analytics.
|
||||
[Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/291747) in GitLab Ultimate 13.9 as a
|
||||
[Beta feature](https://about.gitlab.com/handbook/product/gitlab-the-product/#beta). **(ULTIMATE SELF)**
|
||||
- [Epics](epics/index.md): Track groups of issues that share a theme. **(ULTIMATE)**
|
||||
- [Security Dashboard](../application_security/security_dashboard/index.md): View the vulnerabilities of all
|
||||
the projects in a group and its subgroups. **(ULTIMATE)**
|
||||
- [Insights](insights/index.md): Configure insights like triage hygiene, issues created/closed per a given period, and
|
||||
average time for merge requests to be merged. **(ULTIMATE)**
|
||||
- [Webhooks](../project/integrations/webhooks.md).
|
||||
- [Kubernetes cluster integration](clusters/index.md).
|
||||
- [Audit Events](../../administration/audit_events.md#group-events). **(PREMIUM)**
|
||||
- [Pipelines quota](../admin_area/settings/continuous_integration.md): Keep track of the pipeline quota for the group.
|
||||
- [Integrations](../admin_area/settings/project_integration_management.md).
|
||||
- [Transfer a project into a group](../project/settings/index.md#transferring-an-existing-project-into-another-namespace).
|
||||
- [Share a project with a group](../project/members/share_project_with_groups.md): Give all group members access to the project at once.
|
||||
- [Lock the sharing with group feature](#prevent-a-project-from-being-shared-with-groups).
|
||||
- [Enforce two-factor authentication (2FA)](../../security/two_factor_authentication.md#enforcing-2fa-for-all-users-in-a-group): Enforce 2FA
|
||||
for all group members.
|
||||
|
|
|
@ -266,7 +266,7 @@ This action:
|
|||
|
||||
- Deletes a project including all associated resources (issues, merge requests etc).
|
||||
- From [GitLab 13.2](https://gitlab.com/gitlab-org/gitlab/-/issues/220382) on [Premium](https://about.gitlab.com/pricing/) or higher tiers,
|
||||
group owners can [configure](../../group/index.md#enabling-delayed-project-removal) projects within a group
|
||||
group owners can [configure](../../group/index.md#enable-delayed-project-removal) projects within a group
|
||||
to be deleted after a delayed period.
|
||||
When enabled, actual deletion happens after number of days
|
||||
specified in [instance settings](../../admin_area/settings/visibility_and_access_controls.md#default-deletion-delay).
|
||||
|
|
|
@ -212,7 +212,7 @@ To delete a project, first navigate to the home page for that project.
|
|||
1. Click **Delete project**
|
||||
1. Confirm this action by typing in the expected text.
|
||||
|
||||
Projects in personal namespaces are deleted immediately on request. For information on delayed deletion of projects in a group, please see [Enabling delayed project removal](../group/index.md#enabling-delayed-project-removal).
|
||||
Projects in personal namespaces are deleted immediately on request. For information on delayed deletion of projects in a group, please see [Enable delayed project removal](../group/index.md#enable-delayed-project-removal).
|
||||
|
||||
## Project settings
|
||||
|
||||
|
|
|
@ -7,52 +7,90 @@ module Gitlab
|
|||
##
|
||||
# Entry that represents a cache configuration
|
||||
#
|
||||
class Cache < ::Gitlab::Config::Entry::Node
|
||||
include ::Gitlab::Config::Entry::Configurable
|
||||
include ::Gitlab::Config::Entry::Validatable
|
||||
include ::Gitlab::Config::Entry::Attributable
|
||||
class Cache < ::Gitlab::Config::Entry::Simplifiable
|
||||
strategy :Caches, if: -> (config) { Feature.enabled?(:multiple_cache_per_job) }
|
||||
strategy :Cache, if: -> (config) { Feature.disabled?(:multiple_cache_per_job) }
|
||||
|
||||
ALLOWED_KEYS = %i[key untracked paths when policy].freeze
|
||||
ALLOWED_POLICY = %w[pull-push push pull].freeze
|
||||
DEFAULT_POLICY = 'pull-push'
|
||||
ALLOWED_WHEN = %w[on_success on_failure always].freeze
|
||||
DEFAULT_WHEN = 'on_success'
|
||||
class Caches < ::Gitlab::Config::Entry::ComposableArray
|
||||
include ::Gitlab::Config::Entry::Validatable
|
||||
|
||||
validations do
|
||||
validates :config, type: Hash, allowed_keys: ALLOWED_KEYS
|
||||
validates :policy,
|
||||
inclusion: { in: ALLOWED_POLICY, message: 'should be pull-push, push, or pull' },
|
||||
allow_blank: true
|
||||
MULTIPLE_CACHE_LIMIT = 4
|
||||
|
||||
with_options allow_nil: true do
|
||||
validates :when,
|
||||
inclusion: {
|
||||
in: ALLOWED_WHEN,
|
||||
message: 'should be on_success, on_failure or always'
|
||||
}
|
||||
validations do
|
||||
validates :config, presence: true
|
||||
|
||||
validate do
|
||||
unless config.is_a?(Hash) || config.is_a?(Array)
|
||||
errors.add(:config, 'can only be a Hash or an Array')
|
||||
end
|
||||
|
||||
if config.is_a?(Array) && config.count > MULTIPLE_CACHE_LIMIT
|
||||
errors.add(:config, "no more than #{MULTIPLE_CACHE_LIMIT} caches can be created")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def initialize(*args)
|
||||
super
|
||||
|
||||
@key = nil
|
||||
end
|
||||
|
||||
def composable_class
|
||||
Entry::Cache::Cache
|
||||
end
|
||||
end
|
||||
|
||||
entry :key, Entry::Key,
|
||||
description: 'Cache key used to define a cache affinity.'
|
||||
class Cache < ::Gitlab::Config::Entry::Node
|
||||
include ::Gitlab::Config::Entry::Configurable
|
||||
include ::Gitlab::Config::Entry::Validatable
|
||||
include ::Gitlab::Config::Entry::Attributable
|
||||
|
||||
entry :untracked, ::Gitlab::Config::Entry::Boolean,
|
||||
description: 'Cache all untracked files.'
|
||||
ALLOWED_KEYS = %i[key untracked paths when policy].freeze
|
||||
ALLOWED_POLICY = %w[pull-push push pull].freeze
|
||||
DEFAULT_POLICY = 'pull-push'
|
||||
ALLOWED_WHEN = %w[on_success on_failure always].freeze
|
||||
DEFAULT_WHEN = 'on_success'
|
||||
|
||||
entry :paths, Entry::Paths,
|
||||
description: 'Specify which paths should be cached across builds.'
|
||||
validations do
|
||||
validates :config, type: Hash, allowed_keys: ALLOWED_KEYS
|
||||
validates :policy,
|
||||
inclusion: { in: ALLOWED_POLICY, message: 'should be pull-push, push, or pull' },
|
||||
allow_blank: true
|
||||
|
||||
attributes :policy, :when
|
||||
with_options allow_nil: true do
|
||||
validates :when,
|
||||
inclusion: {
|
||||
in: ALLOWED_WHEN,
|
||||
message: 'should be on_success, on_failure or always'
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
def value
|
||||
result = super
|
||||
entry :key, Entry::Key,
|
||||
description: 'Cache key used to define a cache affinity.'
|
||||
|
||||
result[:key] = key_value
|
||||
result[:policy] = policy || DEFAULT_POLICY
|
||||
# Use self.when to avoid conflict with reserved word
|
||||
result[:when] = self.when || DEFAULT_WHEN
|
||||
entry :untracked, ::Gitlab::Config::Entry::Boolean,
|
||||
description: 'Cache all untracked files.'
|
||||
|
||||
result
|
||||
entry :paths, Entry::Paths,
|
||||
description: 'Specify which paths should be cached across builds.'
|
||||
|
||||
attributes :policy, :when
|
||||
|
||||
def value
|
||||
result = super
|
||||
|
||||
result[:key] = key_value
|
||||
result[:policy] = policy || DEFAULT_POLICY
|
||||
# Use self.when to avoid conflict with reserved word
|
||||
result[:when] = self.when || DEFAULT_WHEN
|
||||
|
||||
result
|
||||
end
|
||||
end
|
||||
|
||||
class UnknownStrategy < ::Gitlab::Config::Entry::Node
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -67,6 +67,10 @@ module Gitlab
|
|||
def self.display_codequality_backend_comparison?(project)
|
||||
::Feature.enabled?(:codequality_backend_comparison, project, default_enabled: :yaml)
|
||||
end
|
||||
|
||||
def self.multiple_cache_per_job?
|
||||
::Feature.enabled?(:multiple_cache_per_job, default_enabled: :yaml)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -28,8 +28,16 @@ module Gitlab
|
|||
.fabricate(attributes.delete(:except))
|
||||
@rules = Gitlab::Ci::Build::Rules
|
||||
.new(attributes.delete(:rules), default_when: 'on_success')
|
||||
@cache = Seed::Build::Cache
|
||||
.new(pipeline, attributes.delete(:cache))
|
||||
|
||||
if multiple_cache_per_job?
|
||||
cache = Array.wrap(attributes.delete(:cache))
|
||||
@cache = cache.map do |cache|
|
||||
Seed::Build::Cache.new(pipeline, cache)
|
||||
end
|
||||
else
|
||||
@cache = Seed::Build::Cache
|
||||
.new(pipeline, attributes.delete(:cache))
|
||||
end
|
||||
end
|
||||
|
||||
def name
|
||||
|
@ -197,7 +205,21 @@ module Gitlab
|
|||
|
||||
def cache_attributes
|
||||
strong_memoize(:cache_attributes) do
|
||||
@cache.build_attributes
|
||||
if multiple_cache_per_job?
|
||||
if @cache.empty?
|
||||
{}
|
||||
else
|
||||
{ options: { cache: @cache.map(&:attributes) } }
|
||||
end
|
||||
else
|
||||
@cache.build_attributes
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def multiple_cache_per_job?
|
||||
strong_memoize(:multiple_cache_per_job) do
|
||||
::Gitlab::Ci::Features.multiple_cache_per_job?
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -18,18 +18,18 @@ module Gitlab
|
|||
raise ArgumentError, "unknown cache keys: #{local_cache.keys}" if local_cache.any?
|
||||
end
|
||||
|
||||
def build_attributes
|
||||
def attributes
|
||||
{
|
||||
options: {
|
||||
cache: {
|
||||
key: key_string,
|
||||
paths: @paths,
|
||||
policy: @policy,
|
||||
untracked: @untracked,
|
||||
when: @when
|
||||
}.compact.presence
|
||||
}.compact
|
||||
}
|
||||
key: key_string,
|
||||
paths: @paths,
|
||||
policy: @policy,
|
||||
untracked: @untracked,
|
||||
when: @when
|
||||
}.compact
|
||||
end
|
||||
|
||||
def build_attributes
|
||||
{ options: { cache: attributes.presence }.compact }
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
@ -28,7 +28,7 @@ module Gitlab
|
|||
end
|
||||
|
||||
def render_name_and_description(object)
|
||||
content = "### #{object[:name]}\n"
|
||||
content = "### `#{object[:name]}`\n"
|
||||
|
||||
if object[:description].present?
|
||||
content += "\n#{object[:description]}"
|
||||
|
|
1
qa/qa.rb
1
qa/qa.rb
|
@ -95,6 +95,7 @@ module QA
|
|||
autoload :Visibility, 'qa/resource/visibility'
|
||||
autoload :ProjectSnippet, 'qa/resource/project_snippet'
|
||||
autoload :Design, 'qa/resource/design'
|
||||
autoload :RegistryRepository, 'qa/resource/registry_repository'
|
||||
|
||||
module KubernetesCluster
|
||||
autoload :Base, 'qa/resource/kubernetes_cluster/base'
|
||||
|
|
|
@ -13,7 +13,7 @@ module QA
|
|||
element :tag_delete_button
|
||||
end
|
||||
|
||||
def has_image_repository?(name)
|
||||
def has_registry_repository?(name)
|
||||
find('a[data-testid="details-link"]', text: name)
|
||||
end
|
||||
|
||||
|
|
|
@ -151,6 +151,10 @@ module QA
|
|||
"#{api_get_path}/runners"
|
||||
end
|
||||
|
||||
def api_registry_repositories_path
|
||||
"#{api_get_path}/registry/repositories"
|
||||
end
|
||||
|
||||
def api_commits_path
|
||||
"#{api_get_path}/repository/commits"
|
||||
end
|
||||
|
@ -256,6 +260,12 @@ module QA
|
|||
parse_body(response)
|
||||
end
|
||||
|
||||
def registry_repositories
|
||||
response = get Runtime::API::Request.new(api_client, "#{api_registry_repositories_path}").url
|
||||
|
||||
parse_body(response)
|
||||
end
|
||||
|
||||
def repository_branches
|
||||
parse_body(get(Runtime::API::Request.new(api_client, api_repository_branches_path).url))
|
||||
end
|
||||
|
|
53
qa/qa/resource/registry_repository.rb
Normal file
53
qa/qa/resource/registry_repository.rb
Normal file
|
@ -0,0 +1,53 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'securerandom'
|
||||
|
||||
module QA
|
||||
module Resource
|
||||
class RegistryRepository < Base
|
||||
attr_accessor :name,
|
||||
:repository_id
|
||||
|
||||
attribute :project do
|
||||
Project.fabricate_via_api! do |resource|
|
||||
resource.name = 'project-with-registry'
|
||||
resource.description = 'Project with Registry'
|
||||
end
|
||||
end
|
||||
|
||||
def initialize
|
||||
@name = project.path_with_namespace
|
||||
@repository_id = nil
|
||||
end
|
||||
|
||||
def fabricate!
|
||||
end
|
||||
|
||||
def fabricate_via_api!
|
||||
resource_web_url(api_get)
|
||||
rescue ResourceNotFoundError
|
||||
super
|
||||
end
|
||||
|
||||
def remove_via_api!
|
||||
registry_repositories = project.registry_repositories
|
||||
if registry_repositories && !registry_repositories.empty?
|
||||
this_registry_repository = registry_repositories.find { |registry_repository| registry_repository[:path] == name }
|
||||
|
||||
@repository_id = this_registry_repository[:id]
|
||||
|
||||
QA::Runtime::Logger.debug("Deleting registry '#{name}'")
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
def api_delete_path
|
||||
"/projects/#{project.id}/registry/repositories/#{@repository_id}"
|
||||
end
|
||||
|
||||
def api_get_path
|
||||
"/projects/#{project.id}/registry/repositories"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -38,7 +38,11 @@ module QA
|
|||
end.merge_via_api!
|
||||
|
||||
expect(merge_request[:state]).to eq('merged')
|
||||
expect(project).not_to have_branch(branch)
|
||||
|
||||
# Retry in case the branch deletion takes more time to finish
|
||||
QA::Support::Retrier.retry_on_exception(max_attempts: 5, sleep_interval: 5) do
|
||||
expect(project).not_to have_branch(branch)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -10,6 +10,13 @@ module QA
|
|||
end
|
||||
end
|
||||
|
||||
let(:registry_repository) do
|
||||
Resource::RegistryRepository.fabricate! do |repository|
|
||||
repository.name = "#{project.path_with_namespace}"
|
||||
repository.project = project
|
||||
end
|
||||
end
|
||||
|
||||
let!(:gitlab_ci_yaml) do
|
||||
<<~YAML
|
||||
build:
|
||||
|
@ -26,6 +33,10 @@ module QA
|
|||
YAML
|
||||
end
|
||||
|
||||
after do
|
||||
registry_repository&.remove_via_api!
|
||||
end
|
||||
|
||||
it 'pushes project image to the container registry and deletes tag', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/1699' do
|
||||
Flow::Login.sign_in
|
||||
project.visit!
|
||||
|
@ -52,9 +63,9 @@ module QA
|
|||
Page::Project::Menu.perform(&:go_to_container_registry)
|
||||
|
||||
Page::Project::Registry::Show.perform do |registry|
|
||||
expect(registry).to have_image_repository(project.path_with_namespace)
|
||||
expect(registry).to have_registry_repository(registry_repository.name)
|
||||
|
||||
registry.click_on_image(project.path_with_namespace)
|
||||
registry.click_on_image(registry_repository.name)
|
||||
expect(registry).to have_tag('master')
|
||||
|
||||
registry.click_delete
|
||||
|
|
|
@ -6,7 +6,7 @@ RSpec.describe Resolvers::ProjectPipelineResolver do
|
|||
include GraphqlHelpers
|
||||
|
||||
let_it_be(:project) { create(:project) }
|
||||
let_it_be(:pipeline) { create(:ci_pipeline, project: project, iid: '1234') }
|
||||
let_it_be(:pipeline) { create(:ci_pipeline, project: project, iid: '1234', sha: 'sha') }
|
||||
let_it_be(:other_pipeline) { create(:ci_pipeline) }
|
||||
let(:current_user) { create(:user) }
|
||||
|
||||
|
@ -30,7 +30,15 @@ RSpec.describe Resolvers::ProjectPipelineResolver do
|
|||
expect(result).to eq(pipeline)
|
||||
end
|
||||
|
||||
it 'keeps the queries under the threshold' do
|
||||
it 'resolves pipeline for the passed sha' do
|
||||
result = batch_sync do
|
||||
resolve_pipeline(project, { sha: 'sha' })
|
||||
end
|
||||
|
||||
expect(result).to eq(pipeline)
|
||||
end
|
||||
|
||||
it 'keeps the queries under the threshold for iid' do
|
||||
create(:ci_pipeline, project: project, iid: '1235')
|
||||
|
||||
control = ActiveRecord::QueryRecorder.new do
|
||||
|
@ -45,6 +53,21 @@ RSpec.describe Resolvers::ProjectPipelineResolver do
|
|||
end.not_to exceed_query_limit(control)
|
||||
end
|
||||
|
||||
it 'keeps the queries under the threshold for sha' do
|
||||
create(:ci_pipeline, project: project, sha: 'sha2')
|
||||
|
||||
control = ActiveRecord::QueryRecorder.new do
|
||||
batch_sync { resolve_pipeline(project, { sha: 'sha' }) }
|
||||
end
|
||||
|
||||
expect do
|
||||
batch_sync do
|
||||
resolve_pipeline(project, { sha: 'sha' })
|
||||
resolve_pipeline(project, { sha: 'sha2' })
|
||||
end
|
||||
end.not_to exceed_query_limit(control)
|
||||
end
|
||||
|
||||
it 'does not resolve a pipeline outside the project' do
|
||||
result = batch_sync do
|
||||
resolve_pipeline(other_pipeline.project, { iid: '1234' })
|
||||
|
@ -53,8 +76,14 @@ RSpec.describe Resolvers::ProjectPipelineResolver do
|
|||
expect(result).to be_nil
|
||||
end
|
||||
|
||||
it 'errors when no iid is passed' do
|
||||
expect { resolve_pipeline(project, {}) }.to raise_error(ArgumentError)
|
||||
it 'errors when no iid or sha is passed' do
|
||||
expect { resolve_pipeline(project, {}) }
|
||||
.to raise_error(Gitlab::Graphql::Errors::ArgumentError)
|
||||
end
|
||||
|
||||
it 'errors when both iid and sha are passed' do
|
||||
expect { resolve_pipeline(project, { iid: '1234', sha: 'sha' }) }
|
||||
.to raise_error(Gitlab::Graphql::Errors::ArgumentError)
|
||||
end
|
||||
|
||||
context 'when the pipeline is a dangling pipeline' do
|
||||
|
|
|
@ -12,7 +12,7 @@ RSpec.describe Types::Ci::PipelineType do
|
|||
id iid sha before_sha status detailed_status config_source duration
|
||||
coverage created_at updated_at started_at finished_at committed_at
|
||||
stages user retryable cancelable jobs source_job downstream
|
||||
upstream path project active user_permissions warnings
|
||||
upstream path project active user_permissions warnings commit_path
|
||||
]
|
||||
|
||||
if Gitlab.ee?
|
||||
|
|
|
@ -7,227 +7,287 @@ RSpec.describe Gitlab::Ci::Config::Entry::Cache do
|
|||
|
||||
subject(:entry) { described_class.new(config) }
|
||||
|
||||
describe 'validations' do
|
||||
context 'with multiple caches' do
|
||||
before do
|
||||
entry.compose!
|
||||
end
|
||||
|
||||
context 'when entry config value is correct' do
|
||||
let(:policy) { nil }
|
||||
let(:key) { 'some key' }
|
||||
let(:when_config) { nil }
|
||||
describe '#valid?' do
|
||||
context 'when configuration is valid with a single cache' do
|
||||
let(:config) { { key: 'key', paths: ["logs/"], untracked: true } }
|
||||
|
||||
let(:config) do
|
||||
{
|
||||
key: key,
|
||||
untracked: true,
|
||||
paths: ['some/path/']
|
||||
}.tap do |config|
|
||||
config[:policy] = policy if policy
|
||||
config[:when] = when_config if when_config
|
||||
it 'is valid' do
|
||||
expect(entry).to be_valid
|
||||
end
|
||||
end
|
||||
|
||||
describe '#value' do
|
||||
shared_examples 'hash key value' do
|
||||
it 'returns hash value' do
|
||||
expect(entry.value).to eq(key: key, untracked: true, paths: ['some/path/'], policy: 'pull-push', when: 'on_success')
|
||||
context 'when configuration is valid with multiple caches' do
|
||||
let(:config) do
|
||||
[
|
||||
{ key: 'key', paths: ["logs/"], untracked: true },
|
||||
{ key: 'key2', paths: ["logs/"], untracked: true },
|
||||
{ key: 'key3', paths: ["logs/"], untracked: true }
|
||||
]
|
||||
end
|
||||
|
||||
it 'is valid' do
|
||||
expect(entry).to be_valid
|
||||
end
|
||||
end
|
||||
|
||||
context 'when configuration is not a Hash or Array' do
|
||||
let(:config) { 'invalid' }
|
||||
|
||||
it 'is invalid' do
|
||||
expect(entry).not_to be_valid
|
||||
end
|
||||
end
|
||||
|
||||
context 'when entry values contain more than four caches' do
|
||||
let(:config) do
|
||||
[
|
||||
{ key: 'key', paths: ["logs/"], untracked: true },
|
||||
{ key: 'key2', paths: ["logs/"], untracked: true },
|
||||
{ key: 'key3', paths: ["logs/"], untracked: true },
|
||||
{ key: 'key4', paths: ["logs/"], untracked: true },
|
||||
{ key: 'key5', paths: ["logs/"], untracked: true }
|
||||
]
|
||||
end
|
||||
|
||||
it 'is invalid' do
|
||||
expect(entry.errors).to eq(["caches config no more than 4 caches can be created"])
|
||||
expect(entry).not_to be_valid
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with a single cache' do
|
||||
before do
|
||||
stub_feature_flags(multiple_cache_per_job: false)
|
||||
end
|
||||
describe 'validations' do
|
||||
before do
|
||||
entry.compose!
|
||||
end
|
||||
|
||||
context 'when entry config value is correct' do
|
||||
let(:policy) { nil }
|
||||
let(:key) { 'some key' }
|
||||
let(:when_config) { nil }
|
||||
|
||||
let(:config) do
|
||||
{
|
||||
key: key,
|
||||
untracked: true,
|
||||
paths: ['some/path/']
|
||||
}.tap do |config|
|
||||
config[:policy] = policy if policy
|
||||
config[:when] = when_config if when_config
|
||||
end
|
||||
end
|
||||
|
||||
it_behaves_like 'hash key value'
|
||||
|
||||
context 'with files' do
|
||||
let(:key) { { files: %w[a-file other-file] } }
|
||||
describe '#value' do
|
||||
shared_examples 'hash key value' do
|
||||
it 'returns hash value' do
|
||||
expect(entry.value).to eq(key: key, untracked: true, paths: ['some/path/'], policy: 'pull-push', when: 'on_success')
|
||||
end
|
||||
end
|
||||
|
||||
it_behaves_like 'hash key value'
|
||||
|
||||
context 'with files' do
|
||||
let(:key) { { files: %w[a-file other-file] } }
|
||||
|
||||
it_behaves_like 'hash key value'
|
||||
end
|
||||
|
||||
context 'with files and prefix' do
|
||||
let(:key) { { files: %w[a-file other-file], prefix: 'prefix-value' } }
|
||||
|
||||
it_behaves_like 'hash key value'
|
||||
end
|
||||
|
||||
context 'with prefix' do
|
||||
let(:key) { { prefix: 'prefix-value' } }
|
||||
|
||||
it 'key is nil' do
|
||||
expect(entry.value).to match(a_hash_including(key: nil))
|
||||
end
|
||||
end
|
||||
|
||||
context 'with `policy`' do
|
||||
where(:policy, :result) do
|
||||
'pull-push' | 'pull-push'
|
||||
'push' | 'push'
|
||||
'pull' | 'pull'
|
||||
'unknown' | 'unknown' # invalid
|
||||
end
|
||||
|
||||
with_them do
|
||||
it { expect(entry.value).to include(policy: result) }
|
||||
end
|
||||
end
|
||||
|
||||
context 'without `policy`' do
|
||||
it 'assigns policy to default' do
|
||||
expect(entry.value).to include(policy: 'pull-push')
|
||||
end
|
||||
end
|
||||
|
||||
context 'with `when`' do
|
||||
where(:when_config, :result) do
|
||||
'on_success' | 'on_success'
|
||||
'on_failure' | 'on_failure'
|
||||
'always' | 'always'
|
||||
'unknown' | 'unknown' # invalid
|
||||
end
|
||||
|
||||
with_them do
|
||||
it { expect(entry.value).to include(when: result) }
|
||||
end
|
||||
end
|
||||
|
||||
context 'without `when`' do
|
||||
it 'assigns when to default' do
|
||||
expect(entry.value).to include(when: 'on_success')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with files and prefix' do
|
||||
let(:key) { { files: %w[a-file other-file], prefix: 'prefix-value' } }
|
||||
describe '#valid?' do
|
||||
it { is_expected.to be_valid }
|
||||
|
||||
it_behaves_like 'hash key value'
|
||||
end
|
||||
context 'with files' do
|
||||
let(:key) { { files: %w[a-file other-file] } }
|
||||
|
||||
context 'with prefix' do
|
||||
let(:key) { { prefix: 'prefix-value' } }
|
||||
|
||||
it 'key is nil' do
|
||||
expect(entry.value).to match(a_hash_including(key: nil))
|
||||
it { is_expected.to be_valid }
|
||||
end
|
||||
end
|
||||
|
||||
context 'with `policy`' do
|
||||
where(:policy, :result) do
|
||||
'pull-push' | 'pull-push'
|
||||
'push' | 'push'
|
||||
'pull' | 'pull'
|
||||
'unknown' | 'unknown' # invalid
|
||||
where(:policy, :valid) do
|
||||
'pull-push' | true
|
||||
'push' | true
|
||||
'pull' | true
|
||||
'unknown' | false
|
||||
end
|
||||
|
||||
with_them do
|
||||
it { expect(entry.value).to include(policy: result) }
|
||||
end
|
||||
end
|
||||
|
||||
context 'without `policy`' do
|
||||
it 'assigns policy to default' do
|
||||
expect(entry.value).to include(policy: 'pull-push')
|
||||
it 'returns expected validity' do
|
||||
expect(entry.valid?).to eq(valid)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with `when`' do
|
||||
where(:when_config, :result) do
|
||||
'on_success' | 'on_success'
|
||||
'on_failure' | 'on_failure'
|
||||
'always' | 'always'
|
||||
'unknown' | 'unknown' # invalid
|
||||
where(:when_config, :valid) do
|
||||
'on_success' | true
|
||||
'on_failure' | true
|
||||
'always' | true
|
||||
'unknown' | false
|
||||
end
|
||||
|
||||
with_them do
|
||||
it { expect(entry.value).to include(when: result) }
|
||||
it 'returns expected validity' do
|
||||
expect(entry.valid?).to eq(valid)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'without `when`' do
|
||||
it 'assigns when to default' do
|
||||
expect(entry.value).to include(when: 'on_success')
|
||||
context 'with key missing' do
|
||||
let(:config) do
|
||||
{ untracked: true,
|
||||
paths: ['some/path/'] }
|
||||
end
|
||||
|
||||
describe '#value' do
|
||||
it 'sets key with the default' do
|
||||
expect(entry.value[:key])
|
||||
.to eq(Gitlab::Ci::Config::Entry::Key.default)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#valid?' do
|
||||
it { is_expected.to be_valid }
|
||||
context 'when entry value is not correct' do
|
||||
describe '#errors' do
|
||||
subject { entry.errors }
|
||||
|
||||
context 'with files' do
|
||||
let(:key) { { files: %w[a-file other-file] } }
|
||||
context 'when is not a hash' do
|
||||
let(:config) { 'ls' }
|
||||
|
||||
it { is_expected.to be_valid }
|
||||
end
|
||||
end
|
||||
|
||||
context 'with `policy`' do
|
||||
where(:policy, :valid) do
|
||||
'pull-push' | true
|
||||
'push' | true
|
||||
'pull' | true
|
||||
'unknown' | false
|
||||
end
|
||||
|
||||
with_them do
|
||||
it 'returns expected validity' do
|
||||
expect(entry.valid?).to eq(valid)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with `when`' do
|
||||
where(:when_config, :valid) do
|
||||
'on_success' | true
|
||||
'on_failure' | true
|
||||
'always' | true
|
||||
'unknown' | false
|
||||
end
|
||||
|
||||
with_them do
|
||||
it 'returns expected validity' do
|
||||
expect(entry.valid?).to eq(valid)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with key missing' do
|
||||
let(:config) do
|
||||
{ untracked: true,
|
||||
paths: ['some/path/'] }
|
||||
end
|
||||
|
||||
describe '#value' do
|
||||
it 'sets key with the default' do
|
||||
expect(entry.value[:key])
|
||||
.to eq(Gitlab::Ci::Config::Entry::Key.default)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when entry value is not correct' do
|
||||
describe '#errors' do
|
||||
subject { entry.errors }
|
||||
|
||||
context 'when is not a hash' do
|
||||
let(:config) { 'ls' }
|
||||
|
||||
it 'reports errors with config value' do
|
||||
is_expected.to include 'cache config should be a hash'
|
||||
end
|
||||
end
|
||||
|
||||
context 'when policy is unknown' do
|
||||
let(:config) { { policy: 'unknown' } }
|
||||
|
||||
it 'reports error' do
|
||||
is_expected.to include('cache policy should be pull-push, push, or pull')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when `when` is unknown' do
|
||||
let(:config) { { when: 'unknown' } }
|
||||
|
||||
it 'reports error' do
|
||||
is_expected.to include('cache when should be on_success, on_failure or always')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when descendants are invalid' do
|
||||
context 'with invalid keys' do
|
||||
let(:config) { { key: 1 } }
|
||||
|
||||
it 'reports error with descendants' do
|
||||
is_expected.to include 'key should be a hash, a string or a symbol'
|
||||
it 'reports errors with config value' do
|
||||
is_expected.to include 'cache config should be a hash'
|
||||
end
|
||||
end
|
||||
|
||||
context 'with empty key' do
|
||||
let(:config) { { key: {} } }
|
||||
context 'when policy is unknown' do
|
||||
let(:config) { { policy: 'unknown' } }
|
||||
|
||||
it 'reports error with descendants' do
|
||||
is_expected.to include 'key config missing required keys: files'
|
||||
it 'reports error' do
|
||||
is_expected.to include('cache policy should be pull-push, push, or pull')
|
||||
end
|
||||
end
|
||||
|
||||
context 'with invalid files' do
|
||||
let(:config) { { key: { files: 'a-file' } } }
|
||||
context 'when `when` is unknown' do
|
||||
let(:config) { { when: 'unknown' } }
|
||||
|
||||
it 'reports error with descendants' do
|
||||
is_expected.to include 'key:files config should be an array of strings'
|
||||
it 'reports error' do
|
||||
is_expected.to include('cache when should be on_success, on_failure or always')
|
||||
end
|
||||
end
|
||||
|
||||
context 'with prefix without files' do
|
||||
let(:config) { { key: { prefix: 'a-prefix' } } }
|
||||
context 'when descendants are invalid' do
|
||||
context 'with invalid keys' do
|
||||
let(:config) { { key: 1 } }
|
||||
|
||||
it 'reports error with descendants' do
|
||||
is_expected.to include 'key config missing required keys: files'
|
||||
it 'reports error with descendants' do
|
||||
is_expected.to include 'key should be a hash, a string or a symbol'
|
||||
end
|
||||
end
|
||||
|
||||
context 'with empty key' do
|
||||
let(:config) { { key: {} } }
|
||||
|
||||
it 'reports error with descendants' do
|
||||
is_expected.to include 'key config missing required keys: files'
|
||||
end
|
||||
end
|
||||
|
||||
context 'with invalid files' do
|
||||
let(:config) { { key: { files: 'a-file' } } }
|
||||
|
||||
it 'reports error with descendants' do
|
||||
is_expected.to include 'key:files config should be an array of strings'
|
||||
end
|
||||
end
|
||||
|
||||
context 'with prefix without files' do
|
||||
let(:config) { { key: { prefix: 'a-prefix' } } }
|
||||
|
||||
it 'reports error with descendants' do
|
||||
is_expected.to include 'key config missing required keys: files'
|
||||
end
|
||||
end
|
||||
|
||||
context 'when there is an unknown key present' do
|
||||
let(:config) { { key: { unknown: 'a-file' } } }
|
||||
|
||||
it 'reports error with descendants' do
|
||||
is_expected.to include 'key config contains unknown keys: unknown'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when there is an unknown key present' do
|
||||
let(:config) { { key: { unknown: 'a-file' } } }
|
||||
let(:config) { { invalid: true } }
|
||||
|
||||
it 'reports error with descendants' do
|
||||
is_expected.to include 'key config contains unknown keys: unknown'
|
||||
is_expected.to include 'cache config contains unknown keys: invalid'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when there is an unknown key present' do
|
||||
let(:config) { { invalid: true } }
|
||||
|
||||
it 'reports error with descendants' do
|
||||
is_expected.to include 'cache config contains unknown keys: invalid'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -537,7 +537,7 @@ RSpec.describe Gitlab::Ci::Config::Entry::Job do
|
|||
|
||||
it 'overrides default config' do
|
||||
expect(entry[:image].value).to eq(name: 'some_image')
|
||||
expect(entry[:cache].value).to eq(key: 'test', policy: 'pull-push', when: 'on_success')
|
||||
expect(entry[:cache].value).to eq([key: 'test', policy: 'pull-push', when: 'on_success'])
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -552,7 +552,43 @@ RSpec.describe Gitlab::Ci::Config::Entry::Job do
|
|||
|
||||
it 'uses config from default entry' do
|
||||
expect(entry[:image].value).to eq 'specified'
|
||||
expect(entry[:cache].value).to eq(key: 'test', policy: 'pull-push', when: 'on_success')
|
||||
expect(entry[:cache].value).to eq([key: 'test', policy: 'pull-push', when: 'on_success'])
|
||||
end
|
||||
end
|
||||
|
||||
context 'with multiple_cache_per_job FF disabled' do
|
||||
before do
|
||||
stub_feature_flags(multiple_cache_per_job: false)
|
||||
end
|
||||
|
||||
context 'when job config overrides default config' do
|
||||
before do
|
||||
entry.compose!(deps)
|
||||
end
|
||||
|
||||
let(:config) do
|
||||
{ script: 'rspec', image: 'some_image', cache: { key: 'test' } }
|
||||
end
|
||||
|
||||
it 'overrides default config' do
|
||||
expect(entry[:image].value).to eq(name: 'some_image')
|
||||
expect(entry[:cache].value).to eq(key: 'test', policy: 'pull-push', when: 'on_success')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when job config does not override default config' do
|
||||
before do
|
||||
allow(default).to receive('[]').with(:image).and_return(specified)
|
||||
|
||||
entry.compose!(deps)
|
||||
end
|
||||
|
||||
let(:config) { { script: 'ls', cache: { key: 'test' } } }
|
||||
|
||||
it 'uses config from default entry' do
|
||||
expect(entry[:image].value).to eq 'specified'
|
||||
expect(entry[:cache].value).to eq(key: 'test', policy: 'pull-push', when: 'on_success')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -126,49 +126,105 @@ RSpec.describe Gitlab::Ci::Config::Entry::Root do
|
|||
expect(root.jobs_value.keys).to eq([:rspec, :spinach, :release])
|
||||
expect(root.jobs_value[:rspec]).to eq(
|
||||
{ name: :rspec,
|
||||
script: %w[rspec ls],
|
||||
before_script: %w(ls pwd),
|
||||
image: { name: 'ruby:2.7' },
|
||||
services: [{ name: 'postgres:9.1' }, { name: 'mysql:5.5' }],
|
||||
stage: 'test',
|
||||
cache: { key: 'k', untracked: true, paths: ['public/'], policy: 'pull-push', when: 'on_success' },
|
||||
variables: { 'VAR' => 'root', 'VAR2' => 'val 2' },
|
||||
ignore: false,
|
||||
after_script: ['make clean'],
|
||||
only: { refs: %w[branches tags] },
|
||||
scheduling_type: :stage }
|
||||
script: %w[rspec ls],
|
||||
before_script: %w(ls pwd),
|
||||
image: { name: 'ruby:2.7' },
|
||||
services: [{ name: 'postgres:9.1' }, { name: 'mysql:5.5' }],
|
||||
stage: 'test',
|
||||
cache: [{ key: 'k', untracked: true, paths: ['public/'], policy: 'pull-push', when: 'on_success' }],
|
||||
variables: { 'VAR' => 'root', 'VAR2' => 'val 2' },
|
||||
ignore: false,
|
||||
after_script: ['make clean'],
|
||||
only: { refs: %w[branches tags] },
|
||||
scheduling_type: :stage }
|
||||
)
|
||||
expect(root.jobs_value[:spinach]).to eq(
|
||||
{ name: :spinach,
|
||||
before_script: [],
|
||||
script: %w[spinach],
|
||||
image: { name: 'ruby:2.7' },
|
||||
services: [{ name: 'postgres:9.1' }, { name: 'mysql:5.5' }],
|
||||
stage: 'test',
|
||||
cache: { key: 'k', untracked: true, paths: ['public/'], policy: 'pull-push', when: 'on_success' },
|
||||
variables: { 'VAR' => 'root', 'VAR2' => 'val 2' },
|
||||
ignore: false,
|
||||
after_script: ['make clean'],
|
||||
only: { refs: %w[branches tags] },
|
||||
scheduling_type: :stage }
|
||||
before_script: [],
|
||||
script: %w[spinach],
|
||||
image: { name: 'ruby:2.7' },
|
||||
services: [{ name: 'postgres:9.1' }, { name: 'mysql:5.5' }],
|
||||
stage: 'test',
|
||||
cache: [{ key: 'k', untracked: true, paths: ['public/'], policy: 'pull-push', when: 'on_success' }],
|
||||
variables: { 'VAR' => 'root', 'VAR2' => 'val 2' },
|
||||
ignore: false,
|
||||
after_script: ['make clean'],
|
||||
only: { refs: %w[branches tags] },
|
||||
scheduling_type: :stage }
|
||||
)
|
||||
expect(root.jobs_value[:release]).to eq(
|
||||
{ name: :release,
|
||||
stage: 'release',
|
||||
before_script: [],
|
||||
script: ["make changelog | tee release_changelog.txt"],
|
||||
release: { name: "Release $CI_TAG_NAME", tag_name: 'v0.06', description: "./release_changelog.txt" },
|
||||
image: { name: "ruby:2.7" },
|
||||
services: [{ name: "postgres:9.1" }, { name: "mysql:5.5" }],
|
||||
cache: { key: "k", untracked: true, paths: ["public/"], policy: "pull-push", when: 'on_success' },
|
||||
only: { refs: %w(branches tags) },
|
||||
variables: { 'VAR' => 'job', 'VAR2' => 'val 2' },
|
||||
after_script: [],
|
||||
ignore: false,
|
||||
scheduling_type: :stage }
|
||||
stage: 'release',
|
||||
before_script: [],
|
||||
script: ["make changelog | tee release_changelog.txt"],
|
||||
release: { name: "Release $CI_TAG_NAME", tag_name: 'v0.06', description: "./release_changelog.txt" },
|
||||
image: { name: "ruby:2.7" },
|
||||
services: [{ name: "postgres:9.1" }, { name: "mysql:5.5" }],
|
||||
cache: [{ key: "k", untracked: true, paths: ["public/"], policy: "pull-push", when: 'on_success' }],
|
||||
only: { refs: %w(branches tags) },
|
||||
variables: { 'VAR' => 'job', 'VAR2' => 'val 2' },
|
||||
after_script: [],
|
||||
ignore: false,
|
||||
scheduling_type: :stage }
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with multuple_cache_per_job FF disabled' do
|
||||
before do
|
||||
stub_feature_flags(multiple_cache_per_job: false)
|
||||
root.compose!
|
||||
end
|
||||
|
||||
describe '#jobs_value' do
|
||||
it 'returns jobs configuration' do
|
||||
expect(root.jobs_value.keys).to eq([:rspec, :spinach, :release])
|
||||
expect(root.jobs_value[:rspec]).to eq(
|
||||
{ name: :rspec,
|
||||
script: %w[rspec ls],
|
||||
before_script: %w(ls pwd),
|
||||
image: { name: 'ruby:2.7' },
|
||||
services: [{ name: 'postgres:9.1' }, { name: 'mysql:5.5' }],
|
||||
stage: 'test',
|
||||
cache: { key: 'k', untracked: true, paths: ['public/'], policy: 'pull-push', when: 'on_success' },
|
||||
variables: { 'VAR' => 'root', 'VAR2' => 'val 2' },
|
||||
ignore: false,
|
||||
after_script: ['make clean'],
|
||||
only: { refs: %w[branches tags] },
|
||||
scheduling_type: :stage }
|
||||
)
|
||||
expect(root.jobs_value[:spinach]).to eq(
|
||||
{ name: :spinach,
|
||||
before_script: [],
|
||||
script: %w[spinach],
|
||||
image: { name: 'ruby:2.7' },
|
||||
services: [{ name: 'postgres:9.1' }, { name: 'mysql:5.5' }],
|
||||
stage: 'test',
|
||||
cache: { key: 'k', untracked: true, paths: ['public/'], policy: 'pull-push', when: 'on_success' },
|
||||
variables: { 'VAR' => 'root', 'VAR2' => 'val 2' },
|
||||
ignore: false,
|
||||
after_script: ['make clean'],
|
||||
only: { refs: %w[branches tags] },
|
||||
scheduling_type: :stage }
|
||||
)
|
||||
expect(root.jobs_value[:release]).to eq(
|
||||
{ name: :release,
|
||||
stage: 'release',
|
||||
before_script: [],
|
||||
script: ["make changelog | tee release_changelog.txt"],
|
||||
release: { name: "Release $CI_TAG_NAME", tag_name: 'v0.06', description: "./release_changelog.txt" },
|
||||
image: { name: "ruby:2.7" },
|
||||
services: [{ name: "postgres:9.1" }, { name: "mysql:5.5" }],
|
||||
cache: { key: "k", untracked: true, paths: ["public/"], policy: "pull-push", when: 'on_success' },
|
||||
only: { refs: %w(branches tags) },
|
||||
variables: { 'VAR' => 'job', 'VAR2' => 'val 2' },
|
||||
after_script: [],
|
||||
ignore: false,
|
||||
scheduling_type: :stage }
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -187,6 +243,52 @@ RSpec.describe Gitlab::Ci::Config::Entry::Root do
|
|||
spinach: { before_script: [], variables: { VAR: 'job' }, script: 'spinach' } }
|
||||
end
|
||||
|
||||
context 'with multiple_cache_per_job FF disabled' do
|
||||
context 'when composed' do
|
||||
before do
|
||||
stub_feature_flags(multiple_cache_per_job: false)
|
||||
root.compose!
|
||||
end
|
||||
|
||||
describe '#errors' do
|
||||
it 'has no errors' do
|
||||
expect(root.errors).to be_empty
|
||||
end
|
||||
end
|
||||
|
||||
describe '#jobs_value' do
|
||||
it 'returns jobs configuration' do
|
||||
expect(root.jobs_value).to eq(
|
||||
rspec: { name: :rspec,
|
||||
script: %w[rspec ls],
|
||||
before_script: %w(ls pwd),
|
||||
image: { name: 'ruby:2.7' },
|
||||
services: [{ name: 'postgres:9.1' }, { name: 'mysql:5.5' }],
|
||||
stage: 'test',
|
||||
cache: { key: 'k', untracked: true, paths: ['public/'], policy: 'pull-push', when: 'on_success' },
|
||||
variables: { 'VAR' => 'root' },
|
||||
ignore: false,
|
||||
after_script: ['make clean'],
|
||||
only: { refs: %w[branches tags] },
|
||||
scheduling_type: :stage },
|
||||
spinach: { name: :spinach,
|
||||
before_script: [],
|
||||
script: %w[spinach],
|
||||
image: { name: 'ruby:2.7' },
|
||||
services: [{ name: 'postgres:9.1' }, { name: 'mysql:5.5' }],
|
||||
stage: 'test',
|
||||
cache: { key: 'k', untracked: true, paths: ['public/'], policy: 'pull-push', when: 'on_success' },
|
||||
variables: { 'VAR' => 'job' },
|
||||
ignore: false,
|
||||
after_script: ['make clean'],
|
||||
only: { refs: %w[branches tags] },
|
||||
scheduling_type: :stage }
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when composed' do
|
||||
before do
|
||||
root.compose!
|
||||
|
@ -202,29 +304,29 @@ RSpec.describe Gitlab::Ci::Config::Entry::Root do
|
|||
it 'returns jobs configuration' do
|
||||
expect(root.jobs_value).to eq(
|
||||
rspec: { name: :rspec,
|
||||
script: %w[rspec ls],
|
||||
before_script: %w(ls pwd),
|
||||
image: { name: 'ruby:2.7' },
|
||||
services: [{ name: 'postgres:9.1' }, { name: 'mysql:5.5' }],
|
||||
stage: 'test',
|
||||
cache: { key: 'k', untracked: true, paths: ['public/'], policy: 'pull-push', when: 'on_success' },
|
||||
variables: { 'VAR' => 'root' },
|
||||
ignore: false,
|
||||
after_script: ['make clean'],
|
||||
only: { refs: %w[branches tags] },
|
||||
scheduling_type: :stage },
|
||||
script: %w[rspec ls],
|
||||
before_script: %w(ls pwd),
|
||||
image: { name: 'ruby:2.7' },
|
||||
services: [{ name: 'postgres:9.1' }, { name: 'mysql:5.5' }],
|
||||
stage: 'test',
|
||||
cache: [{ key: 'k', untracked: true, paths: ['public/'], policy: 'pull-push', when: 'on_success' }],
|
||||
variables: { 'VAR' => 'root' },
|
||||
ignore: false,
|
||||
after_script: ['make clean'],
|
||||
only: { refs: %w[branches tags] },
|
||||
scheduling_type: :stage },
|
||||
spinach: { name: :spinach,
|
||||
before_script: [],
|
||||
script: %w[spinach],
|
||||
image: { name: 'ruby:2.7' },
|
||||
services: [{ name: 'postgres:9.1' }, { name: 'mysql:5.5' }],
|
||||
stage: 'test',
|
||||
cache: { key: 'k', untracked: true, paths: ['public/'], policy: 'pull-push', when: 'on_success' },
|
||||
variables: { 'VAR' => 'job' },
|
||||
ignore: false,
|
||||
after_script: ['make clean'],
|
||||
only: { refs: %w[branches tags] },
|
||||
scheduling_type: :stage }
|
||||
before_script: [],
|
||||
script: %w[spinach],
|
||||
image: { name: 'ruby:2.7' },
|
||||
services: [{ name: 'postgres:9.1' }, { name: 'mysql:5.5' }],
|
||||
stage: 'test',
|
||||
cache: [{ key: 'k', untracked: true, paths: ['public/'], policy: 'pull-push', when: 'on_success' }],
|
||||
variables: { 'VAR' => 'job' },
|
||||
ignore: false,
|
||||
after_script: ['make clean'],
|
||||
only: { refs: %w[branches tags] },
|
||||
scheduling_type: :stage }
|
||||
)
|
||||
end
|
||||
end
|
||||
|
@ -265,7 +367,20 @@ RSpec.describe Gitlab::Ci::Config::Entry::Root do
|
|||
|
||||
describe '#cache_value' do
|
||||
it 'returns correct cache definition' do
|
||||
expect(root.cache_value).to eq(key: 'a', policy: 'pull-push', when: 'on_success')
|
||||
expect(root.cache_value).to eq([key: 'a', policy: 'pull-push', when: 'on_success'])
|
||||
end
|
||||
end
|
||||
|
||||
context 'with multiple_cache_per_job FF disabled' do
|
||||
before do
|
||||
stub_feature_flags(multiple_cache_per_job: false)
|
||||
root.compose!
|
||||
end
|
||||
|
||||
describe '#cache_value' do
|
||||
it 'returns correct cache definition' do
|
||||
expect(root.cache_value).to eq(key: 'a', policy: 'pull-push', when: 'on_success')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -9,8 +9,255 @@ RSpec.describe Gitlab::Ci::Pipeline::Seed::Build::Cache do
|
|||
|
||||
let(:processor) { described_class.new(pipeline, config) }
|
||||
|
||||
describe '#build_attributes' do
|
||||
subject { processor.build_attributes }
|
||||
context 'with multiple_cache_per_job ff disabled' do
|
||||
before do
|
||||
stub_feature_flags(multiple_cache_per_job: false)
|
||||
end
|
||||
|
||||
describe '#build_attributes' do
|
||||
subject { processor.build_attributes }
|
||||
|
||||
context 'with cache:key' do
|
||||
let(:config) do
|
||||
{
|
||||
key: 'a-key',
|
||||
paths: ['vendor/ruby']
|
||||
}
|
||||
end
|
||||
|
||||
it { is_expected.to include(options: { cache: config }) }
|
||||
end
|
||||
|
||||
context 'with cache:key as a symbol' do
|
||||
let(:config) do
|
||||
{
|
||||
key: :a_key,
|
||||
paths: ['vendor/ruby']
|
||||
}
|
||||
end
|
||||
|
||||
it { is_expected.to include(options: { cache: config.merge(key: "a_key") }) }
|
||||
end
|
||||
|
||||
context 'with cache:key:files' do
|
||||
shared_examples 'default key' do
|
||||
let(:config) do
|
||||
{ key: { files: files } }
|
||||
end
|
||||
|
||||
it 'uses default key' do
|
||||
expected = { options: { cache: { key: 'default' } } }
|
||||
|
||||
is_expected.to include(expected)
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples 'version and gemfile files' do
|
||||
let(:config) do
|
||||
{
|
||||
key: {
|
||||
files: files
|
||||
},
|
||||
paths: ['vendor/ruby']
|
||||
}
|
||||
end
|
||||
|
||||
it 'builds a string key' do
|
||||
expected = {
|
||||
options: {
|
||||
cache: {
|
||||
key: '703ecc8fef1635427a1f86a8a1a308831c122392',
|
||||
paths: ['vendor/ruby']
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
is_expected.to include(expected)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with existing files' do
|
||||
let(:files) { ['VERSION', 'Gemfile.zip'] }
|
||||
|
||||
it_behaves_like 'version and gemfile files'
|
||||
end
|
||||
|
||||
context 'with files starting with ./' do
|
||||
let(:files) { ['Gemfile.zip', './VERSION'] }
|
||||
|
||||
it_behaves_like 'version and gemfile files'
|
||||
end
|
||||
|
||||
context 'with files ending with /' do
|
||||
let(:files) { ['Gemfile.zip/'] }
|
||||
|
||||
it_behaves_like 'default key'
|
||||
end
|
||||
|
||||
context 'with new line in filenames' do
|
||||
let(:files) { ["Gemfile.zip\nVERSION"] }
|
||||
|
||||
it_behaves_like 'default key'
|
||||
end
|
||||
|
||||
context 'with missing files' do
|
||||
let(:files) { ['project-gemfile.lock', ''] }
|
||||
|
||||
it_behaves_like 'default key'
|
||||
end
|
||||
|
||||
context 'with directories' do
|
||||
shared_examples 'foo/bar directory key' do
|
||||
let(:config) do
|
||||
{
|
||||
key: {
|
||||
files: files
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it 'builds a string key' do
|
||||
expected = {
|
||||
options: {
|
||||
cache: { key: '74bf43fb1090f161bdd4e265802775dbda2f03d1' }
|
||||
}
|
||||
}
|
||||
|
||||
is_expected.to include(expected)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with directory' do
|
||||
let(:files) { ['foo/bar'] }
|
||||
|
||||
it_behaves_like 'foo/bar directory key'
|
||||
end
|
||||
|
||||
context 'with directory ending in slash' do
|
||||
let(:files) { ['foo/bar/'] }
|
||||
|
||||
it_behaves_like 'foo/bar directory key'
|
||||
end
|
||||
|
||||
context 'with directories ending in slash star' do
|
||||
let(:files) { ['foo/bar/*'] }
|
||||
|
||||
it_behaves_like 'foo/bar directory key'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with cache:key:prefix' do
|
||||
context 'without files' do
|
||||
let(:config) do
|
||||
{
|
||||
key: {
|
||||
prefix: 'a-prefix'
|
||||
},
|
||||
paths: ['vendor/ruby']
|
||||
}
|
||||
end
|
||||
|
||||
it 'adds prefix to default key' do
|
||||
expected = {
|
||||
options: {
|
||||
cache: {
|
||||
key: 'a-prefix-default',
|
||||
paths: ['vendor/ruby']
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
is_expected.to include(expected)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with existing files' do
|
||||
let(:config) do
|
||||
{
|
||||
key: {
|
||||
files: ['VERSION', 'Gemfile.zip'],
|
||||
prefix: 'a-prefix'
|
||||
},
|
||||
paths: ['vendor/ruby']
|
||||
}
|
||||
end
|
||||
|
||||
it 'adds prefix key' do
|
||||
expected = {
|
||||
options: {
|
||||
cache: {
|
||||
key: 'a-prefix-703ecc8fef1635427a1f86a8a1a308831c122392',
|
||||
paths: ['vendor/ruby']
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
is_expected.to include(expected)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with missing files' do
|
||||
let(:config) do
|
||||
{
|
||||
key: {
|
||||
files: ['project-gemfile.lock', ''],
|
||||
prefix: 'a-prefix'
|
||||
},
|
||||
paths: ['vendor/ruby']
|
||||
}
|
||||
end
|
||||
|
||||
it 'adds prefix to default key' do
|
||||
expected = {
|
||||
options: {
|
||||
cache: {
|
||||
key: 'a-prefix-default',
|
||||
paths: ['vendor/ruby']
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
is_expected.to include(expected)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with all cache option keys' do
|
||||
let(:config) do
|
||||
{
|
||||
key: 'a-key',
|
||||
paths: ['vendor/ruby'],
|
||||
untracked: true,
|
||||
policy: 'push',
|
||||
when: 'on_success'
|
||||
}
|
||||
end
|
||||
|
||||
it { is_expected.to include(options: { cache: config }) }
|
||||
end
|
||||
|
||||
context 'with unknown cache option keys' do
|
||||
let(:config) do
|
||||
{
|
||||
key: 'a-key',
|
||||
unknown_key: true
|
||||
}
|
||||
end
|
||||
|
||||
it { expect { subject }.to raise_error(ArgumentError, /unknown_key/) }
|
||||
end
|
||||
|
||||
context 'with empty config' do
|
||||
let(:config) { {} }
|
||||
|
||||
it { is_expected.to include(options: {}) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#attributes' do
|
||||
subject { processor.attributes }
|
||||
|
||||
context 'with cache:key' do
|
||||
let(:config) do
|
||||
|
@ -20,7 +267,7 @@ RSpec.describe Gitlab::Ci::Pipeline::Seed::Build::Cache do
|
|||
}
|
||||
end
|
||||
|
||||
it { is_expected.to include(options: { cache: config }) }
|
||||
it { is_expected.to include(config) }
|
||||
end
|
||||
|
||||
context 'with cache:key as a symbol' do
|
||||
|
@ -31,7 +278,7 @@ RSpec.describe Gitlab::Ci::Pipeline::Seed::Build::Cache do
|
|||
}
|
||||
end
|
||||
|
||||
it { is_expected.to include(options: { cache: config.merge(key: "a_key") }) }
|
||||
it { is_expected.to include(config.merge(key: "a_key")) }
|
||||
end
|
||||
|
||||
context 'with cache:key:files' do
|
||||
|
@ -41,7 +288,7 @@ RSpec.describe Gitlab::Ci::Pipeline::Seed::Build::Cache do
|
|||
end
|
||||
|
||||
it 'uses default key' do
|
||||
expected = { options: { cache: { key: 'default' } } }
|
||||
expected = { key: 'default' }
|
||||
|
||||
is_expected.to include(expected)
|
||||
end
|
||||
|
@ -59,13 +306,9 @@ RSpec.describe Gitlab::Ci::Pipeline::Seed::Build::Cache do
|
|||
|
||||
it 'builds a string key' do
|
||||
expected = {
|
||||
options: {
|
||||
cache: {
|
||||
key: '703ecc8fef1635427a1f86a8a1a308831c122392',
|
||||
paths: ['vendor/ruby']
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
is_expected.to include(expected)
|
||||
end
|
||||
|
@ -112,11 +355,7 @@ RSpec.describe Gitlab::Ci::Pipeline::Seed::Build::Cache do
|
|||
end
|
||||
|
||||
it 'builds a string key' do
|
||||
expected = {
|
||||
options: {
|
||||
cache: { key: '74bf43fb1090f161bdd4e265802775dbda2f03d1' }
|
||||
}
|
||||
}
|
||||
expected = { key: '74bf43fb1090f161bdd4e265802775dbda2f03d1' }
|
||||
|
||||
is_expected.to include(expected)
|
||||
end
|
||||
|
@ -155,13 +394,9 @@ RSpec.describe Gitlab::Ci::Pipeline::Seed::Build::Cache do
|
|||
|
||||
it 'adds prefix to default key' do
|
||||
expected = {
|
||||
options: {
|
||||
cache: {
|
||||
key: 'a-prefix-default',
|
||||
paths: ['vendor/ruby']
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
is_expected.to include(expected)
|
||||
end
|
||||
|
@ -180,13 +415,9 @@ RSpec.describe Gitlab::Ci::Pipeline::Seed::Build::Cache do
|
|||
|
||||
it 'adds prefix key' do
|
||||
expected = {
|
||||
options: {
|
||||
cache: {
|
||||
key: 'a-prefix-703ecc8fef1635427a1f86a8a1a308831c122392',
|
||||
paths: ['vendor/ruby']
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
is_expected.to include(expected)
|
||||
end
|
||||
|
@ -205,13 +436,9 @@ RSpec.describe Gitlab::Ci::Pipeline::Seed::Build::Cache do
|
|||
|
||||
it 'adds prefix to default key' do
|
||||
expected = {
|
||||
options: {
|
||||
cache: {
|
||||
key: 'a-prefix-default',
|
||||
paths: ['vendor/ruby']
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
is_expected.to include(expected)
|
||||
end
|
||||
|
@ -229,7 +456,7 @@ RSpec.describe Gitlab::Ci::Pipeline::Seed::Build::Cache do
|
|||
}
|
||||
end
|
||||
|
||||
it { is_expected.to include(options: { cache: config }) }
|
||||
it { is_expected.to include(config) }
|
||||
end
|
||||
|
||||
context 'with unknown cache option keys' do
|
||||
|
@ -242,11 +469,5 @@ RSpec.describe Gitlab::Ci::Pipeline::Seed::Build::Cache do
|
|||
|
||||
it { expect { subject }.to raise_error(ArgumentError, /unknown_key/) }
|
||||
end
|
||||
|
||||
context 'with empty config' do
|
||||
let(:config) { {} }
|
||||
|
||||
it { is_expected.to include(options: {}) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -87,86 +87,167 @@ RSpec.describe Gitlab::Ci::Pipeline::Seed::Build do
|
|||
end
|
||||
end
|
||||
|
||||
context 'with multiple_cache_per_job FF disabled' do
|
||||
before do
|
||||
stub_feature_flags(multiple_cache_per_job: false)
|
||||
end
|
||||
|
||||
context 'with cache:key' do
|
||||
let(:attributes) do
|
||||
{
|
||||
name: 'rspec',
|
||||
ref: 'master',
|
||||
cache: {
|
||||
key: 'a-value'
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it { is_expected.to include(options: { cache: { key: 'a-value' } }) }
|
||||
end
|
||||
|
||||
context 'with cache:key:files' do
|
||||
let(:attributes) do
|
||||
{
|
||||
name: 'rspec',
|
||||
ref: 'master',
|
||||
cache: {
|
||||
key: {
|
||||
files: ['VERSION']
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it 'includes cache options' do
|
||||
cache_options = {
|
||||
options: {
|
||||
cache: { key: 'f155568ad0933d8358f66b846133614f76dd0ca4' }
|
||||
}
|
||||
}
|
||||
|
||||
is_expected.to include(cache_options)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with cache:key:prefix' do
|
||||
let(:attributes) do
|
||||
{
|
||||
name: 'rspec',
|
||||
ref: 'master',
|
||||
cache: {
|
||||
key: {
|
||||
prefix: 'something'
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it { is_expected.to include(options: { cache: { key: 'something-default' } }) }
|
||||
end
|
||||
|
||||
context 'with cache:key:files and prefix' do
|
||||
let(:attributes) do
|
||||
{
|
||||
name: 'rspec',
|
||||
ref: 'master',
|
||||
cache: {
|
||||
key: {
|
||||
files: ['VERSION'],
|
||||
prefix: 'something'
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it 'includes cache options' do
|
||||
cache_options = {
|
||||
options: {
|
||||
cache: { key: 'something-f155568ad0933d8358f66b846133614f76dd0ca4' }
|
||||
}
|
||||
}
|
||||
|
||||
is_expected.to include(cache_options)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with cache:key' do
|
||||
let(:attributes) do
|
||||
{
|
||||
name: 'rspec',
|
||||
ref: 'master',
|
||||
cache: {
|
||||
cache: [{
|
||||
key: 'a-value'
|
||||
}
|
||||
}]
|
||||
}
|
||||
end
|
||||
|
||||
it { is_expected.to include(options: { cache: { key: 'a-value' } }) }
|
||||
end
|
||||
it { is_expected.to include(options: { cache: [a_hash_including(key: 'a-value')] }) }
|
||||
|
||||
context 'with cache:key:files' do
|
||||
let(:attributes) do
|
||||
{
|
||||
name: 'rspec',
|
||||
ref: 'master',
|
||||
cache: {
|
||||
key: {
|
||||
files: ['VERSION']
|
||||
context 'with cache:key:files' do
|
||||
let(:attributes) do
|
||||
{
|
||||
name: 'rspec',
|
||||
ref: 'master',
|
||||
cache: [{
|
||||
key: {
|
||||
files: ['VERSION']
|
||||
}
|
||||
}]
|
||||
}
|
||||
end
|
||||
|
||||
it 'includes cache options' do
|
||||
cache_options = {
|
||||
options: {
|
||||
cache: [a_hash_including(key: 'f155568ad0933d8358f66b846133614f76dd0ca4')]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
is_expected.to include(cache_options)
|
||||
end
|
||||
end
|
||||
|
||||
it 'includes cache options' do
|
||||
cache_options = {
|
||||
options: {
|
||||
cache: {
|
||||
key: 'f155568ad0933d8358f66b846133614f76dd0ca4'
|
||||
}
|
||||
context 'with cache:key:prefix' do
|
||||
let(:attributes) do
|
||||
{
|
||||
name: 'rspec',
|
||||
ref: 'master',
|
||||
cache: [{
|
||||
key: {
|
||||
prefix: 'something'
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
is_expected.to include(cache_options)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with cache:key:prefix' do
|
||||
let(:attributes) do
|
||||
{
|
||||
name: 'rspec',
|
||||
ref: 'master',
|
||||
cache: {
|
||||
key: {
|
||||
prefix: 'something'
|
||||
}
|
||||
}
|
||||
}
|
||||
it { is_expected.to include(options: { cache: [a_hash_including( key: 'something-default' )] }) }
|
||||
end
|
||||
|
||||
it { is_expected.to include(options: { cache: { key: 'something-default' } }) }
|
||||
end
|
||||
context 'with cache:key:files and prefix' do
|
||||
let(:attributes) do
|
||||
{
|
||||
name: 'rspec',
|
||||
ref: 'master',
|
||||
cache: [{
|
||||
key: {
|
||||
files: ['VERSION'],
|
||||
prefix: 'something'
|
||||
}
|
||||
}]
|
||||
}
|
||||
end
|
||||
|
||||
context 'with cache:key:files and prefix' do
|
||||
let(:attributes) do
|
||||
{
|
||||
name: 'rspec',
|
||||
ref: 'master',
|
||||
cache: {
|
||||
key: {
|
||||
files: ['VERSION'],
|
||||
prefix: 'something'
|
||||
it 'includes cache options' do
|
||||
cache_options = {
|
||||
options: {
|
||||
cache: [a_hash_including(key: 'something-f155568ad0933d8358f66b846133614f76dd0ca4')]
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it 'includes cache options' do
|
||||
cache_options = {
|
||||
options: {
|
||||
cache: {
|
||||
key: 'something-f155568ad0933d8358f66b846133614f76dd0ca4'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
is_expected.to include(cache_options)
|
||||
is_expected.to include(cache_options)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -179,7 +260,7 @@ RSpec.describe Gitlab::Ci::Pipeline::Seed::Build do
|
|||
}
|
||||
end
|
||||
|
||||
it { is_expected.to include(options: {}) }
|
||||
it { is_expected.to include({}) }
|
||||
end
|
||||
|
||||
context 'with allow_failure' do
|
||||
|
@ -296,7 +377,7 @@ RSpec.describe Gitlab::Ci::Pipeline::Seed::Build do
|
|||
it 'does not have environment' do
|
||||
expect(subject).not_to be_has_environment
|
||||
expect(subject.environment).to be_nil
|
||||
expect(subject.metadata.expanded_environment_name).to be_nil
|
||||
expect(subject.metadata).to be_nil
|
||||
expect(Environment.exists?(name: expected_environment_name)).to eq(false)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1368,6 +1368,155 @@ module Gitlab
|
|||
end
|
||||
end
|
||||
|
||||
context 'with multiple_cache_per_job FF disabled' do
|
||||
before do
|
||||
stub_feature_flags(multiple_cache_per_job: false)
|
||||
end
|
||||
describe 'cache' do
|
||||
context 'when cache definition has unknown keys' do
|
||||
let(:config) do
|
||||
YAML.dump(
|
||||
{ cache: { untracked: true, invalid: 'key' },
|
||||
rspec: { script: 'rspec' } })
|
||||
end
|
||||
|
||||
it_behaves_like 'returns errors', 'cache config contains unknown keys: invalid'
|
||||
end
|
||||
|
||||
it "returns cache when defined globally" do
|
||||
config = YAML.dump({
|
||||
cache: { paths: ["logs/", "binaries/"], untracked: true, key: 'key' },
|
||||
rspec: {
|
||||
script: "rspec"
|
||||
}
|
||||
})
|
||||
|
||||
config_processor = Gitlab::Ci::YamlProcessor.new(config).execute
|
||||
|
||||
expect(config_processor.stage_builds_attributes("test").size).to eq(1)
|
||||
expect(config_processor.stage_builds_attributes("test").first[:cache]).to eq(
|
||||
paths: ["logs/", "binaries/"],
|
||||
untracked: true,
|
||||
key: 'key',
|
||||
policy: 'pull-push',
|
||||
when: 'on_success'
|
||||
)
|
||||
end
|
||||
|
||||
it "returns cache when defined in default context" do
|
||||
config = YAML.dump(
|
||||
{
|
||||
default: {
|
||||
cache: { paths: ["logs/", "binaries/"], untracked: true, key: { files: ['file'] } }
|
||||
},
|
||||
rspec: {
|
||||
script: "rspec"
|
||||
}
|
||||
})
|
||||
|
||||
config_processor = Gitlab::Ci::YamlProcessor.new(config).execute
|
||||
|
||||
expect(config_processor.stage_builds_attributes("test").size).to eq(1)
|
||||
expect(config_processor.stage_builds_attributes("test").first[:cache]).to eq(
|
||||
paths: ["logs/", "binaries/"],
|
||||
untracked: true,
|
||||
key: { files: ['file'] },
|
||||
policy: 'pull-push',
|
||||
when: 'on_success'
|
||||
)
|
||||
end
|
||||
|
||||
it 'returns cache key when defined in a job' do
|
||||
config = YAML.dump({
|
||||
rspec: {
|
||||
cache: { paths: ['logs/', 'binaries/'], untracked: true, key: 'key' },
|
||||
script: 'rspec'
|
||||
}
|
||||
})
|
||||
|
||||
config_processor = Gitlab::Ci::YamlProcessor.new(config).execute
|
||||
|
||||
expect(config_processor.stage_builds_attributes('test').size).to eq(1)
|
||||
expect(config_processor.stage_builds_attributes('test').first[:cache]).to eq(
|
||||
paths: ['logs/', 'binaries/'],
|
||||
untracked: true,
|
||||
key: 'key',
|
||||
policy: 'pull-push',
|
||||
when: 'on_success'
|
||||
)
|
||||
end
|
||||
|
||||
it 'returns cache files' do
|
||||
config = YAML.dump(
|
||||
rspec: {
|
||||
cache: {
|
||||
paths: ['logs/', 'binaries/'],
|
||||
untracked: true,
|
||||
key: { files: ['file'] }
|
||||
},
|
||||
script: 'rspec'
|
||||
}
|
||||
)
|
||||
|
||||
config_processor = Gitlab::Ci::YamlProcessor.new(config).execute
|
||||
|
||||
expect(config_processor.stage_builds_attributes('test').size).to eq(1)
|
||||
expect(config_processor.stage_builds_attributes('test').first[:cache]).to eq(
|
||||
paths: ['logs/', 'binaries/'],
|
||||
untracked: true,
|
||||
key: { files: ['file'] },
|
||||
policy: 'pull-push',
|
||||
when: 'on_success'
|
||||
)
|
||||
end
|
||||
|
||||
it 'returns cache files with prefix' do
|
||||
config = YAML.dump(
|
||||
rspec: {
|
||||
cache: {
|
||||
paths: ['logs/', 'binaries/'],
|
||||
untracked: true,
|
||||
key: { files: ['file'], prefix: 'prefix' }
|
||||
},
|
||||
script: 'rspec'
|
||||
}
|
||||
)
|
||||
|
||||
config_processor = Gitlab::Ci::YamlProcessor.new(config).execute
|
||||
|
||||
expect(config_processor.stage_builds_attributes('test').size).to eq(1)
|
||||
expect(config_processor.stage_builds_attributes('test').first[:cache]).to eq(
|
||||
paths: ['logs/', 'binaries/'],
|
||||
untracked: true,
|
||||
key: { files: ['file'], prefix: 'prefix' },
|
||||
policy: 'pull-push',
|
||||
when: 'on_success'
|
||||
)
|
||||
end
|
||||
|
||||
it "overwrite cache when defined for a job and globally" do
|
||||
config = YAML.dump({
|
||||
cache: { paths: ["logs/", "binaries/"], untracked: true, key: 'global' },
|
||||
rspec: {
|
||||
script: "rspec",
|
||||
cache: { paths: ["test/"], untracked: false, key: 'local' }
|
||||
}
|
||||
})
|
||||
|
||||
config_processor = Gitlab::Ci::YamlProcessor.new(config).execute
|
||||
|
||||
expect(config_processor.stage_builds_attributes("test").size).to eq(1)
|
||||
expect(config_processor.stage_builds_attributes("test").first[:cache]).to eq(
|
||||
paths: ["test/"],
|
||||
untracked: false,
|
||||
key: 'local',
|
||||
policy: 'pull-push',
|
||||
when: 'on_success'
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'cache' do
|
||||
context 'when cache definition has unknown keys' do
|
||||
let(:config) do
|
||||
|
@ -1381,22 +1530,22 @@ module Gitlab
|
|||
|
||||
it "returns cache when defined globally" do
|
||||
config = YAML.dump({
|
||||
cache: { paths: ["logs/", "binaries/"], untracked: true, key: 'key' },
|
||||
rspec: {
|
||||
script: "rspec"
|
||||
}
|
||||
})
|
||||
cache: { paths: ["logs/", "binaries/"], untracked: true, key: 'key' },
|
||||
rspec: {
|
||||
script: "rspec"
|
||||
}
|
||||
})
|
||||
|
||||
config_processor = Gitlab::Ci::YamlProcessor.new(config).execute
|
||||
|
||||
expect(config_processor.stage_builds_attributes("test").size).to eq(1)
|
||||
expect(config_processor.stage_builds_attributes("test").first[:cache]).to eq(
|
||||
expect(config_processor.stage_builds_attributes("test").first[:cache]).to eq([
|
||||
paths: ["logs/", "binaries/"],
|
||||
untracked: true,
|
||||
key: 'key',
|
||||
policy: 'pull-push',
|
||||
when: 'on_success'
|
||||
)
|
||||
])
|
||||
end
|
||||
|
||||
it "returns cache when defined in default context" do
|
||||
|
@ -1413,32 +1562,46 @@ module Gitlab
|
|||
config_processor = Gitlab::Ci::YamlProcessor.new(config).execute
|
||||
|
||||
expect(config_processor.stage_builds_attributes("test").size).to eq(1)
|
||||
expect(config_processor.stage_builds_attributes("test").first[:cache]).to eq(
|
||||
expect(config_processor.stage_builds_attributes("test").first[:cache]).to eq([
|
||||
paths: ["logs/", "binaries/"],
|
||||
untracked: true,
|
||||
key: { files: ['file'] },
|
||||
policy: 'pull-push',
|
||||
when: 'on_success'
|
||||
)
|
||||
])
|
||||
end
|
||||
|
||||
it 'returns cache key when defined in a job' do
|
||||
it 'returns cache key/s when defined in a job' do
|
||||
config = YAML.dump({
|
||||
rspec: {
|
||||
cache: { paths: ['logs/', 'binaries/'], untracked: true, key: 'key' },
|
||||
script: 'rspec'
|
||||
}
|
||||
})
|
||||
rspec: {
|
||||
cache: [
|
||||
{ paths: ['binaries/'], untracked: true, key: 'keya' },
|
||||
{ paths: ['logs/', 'binaries/'], untracked: true, key: 'key' }
|
||||
],
|
||||
script: 'rspec'
|
||||
}
|
||||
})
|
||||
|
||||
config_processor = Gitlab::Ci::YamlProcessor.new(config).execute
|
||||
|
||||
expect(config_processor.stage_builds_attributes('test').size).to eq(1)
|
||||
expect(config_processor.stage_builds_attributes('test').first[:cache]).to eq(
|
||||
paths: ['logs/', 'binaries/'],
|
||||
untracked: true,
|
||||
key: 'key',
|
||||
policy: 'pull-push',
|
||||
when: 'on_success'
|
||||
[
|
||||
{
|
||||
paths: ['binaries/'],
|
||||
untracked: true,
|
||||
key: 'keya',
|
||||
policy: 'pull-push',
|
||||
when: 'on_success'
|
||||
},
|
||||
{
|
||||
paths: ['logs/', 'binaries/'],
|
||||
untracked: true,
|
||||
key: 'key',
|
||||
policy: 'pull-push',
|
||||
when: 'on_success'
|
||||
}
|
||||
]
|
||||
)
|
||||
end
|
||||
|
||||
|
@ -1446,10 +1609,10 @@ module Gitlab
|
|||
config = YAML.dump(
|
||||
rspec: {
|
||||
cache: {
|
||||
paths: ['logs/', 'binaries/'],
|
||||
untracked: true,
|
||||
key: { files: ['file'] }
|
||||
},
|
||||
paths: ['binaries/'],
|
||||
untracked: true,
|
||||
key: { files: ['file'] }
|
||||
},
|
||||
script: 'rspec'
|
||||
}
|
||||
)
|
||||
|
@ -1457,13 +1620,13 @@ module Gitlab
|
|||
config_processor = Gitlab::Ci::YamlProcessor.new(config).execute
|
||||
|
||||
expect(config_processor.stage_builds_attributes('test').size).to eq(1)
|
||||
expect(config_processor.stage_builds_attributes('test').first[:cache]).to eq(
|
||||
paths: ['logs/', 'binaries/'],
|
||||
expect(config_processor.stage_builds_attributes('test').first[:cache]).to eq([
|
||||
paths: ['binaries/'],
|
||||
untracked: true,
|
||||
key: { files: ['file'] },
|
||||
policy: 'pull-push',
|
||||
when: 'on_success'
|
||||
)
|
||||
])
|
||||
end
|
||||
|
||||
it 'returns cache files with prefix' do
|
||||
|
@ -1481,34 +1644,34 @@ module Gitlab
|
|||
config_processor = Gitlab::Ci::YamlProcessor.new(config).execute
|
||||
|
||||
expect(config_processor.stage_builds_attributes('test').size).to eq(1)
|
||||
expect(config_processor.stage_builds_attributes('test').first[:cache]).to eq(
|
||||
expect(config_processor.stage_builds_attributes('test').first[:cache]).to eq([
|
||||
paths: ['logs/', 'binaries/'],
|
||||
untracked: true,
|
||||
key: { files: ['file'], prefix: 'prefix' },
|
||||
policy: 'pull-push',
|
||||
when: 'on_success'
|
||||
)
|
||||
])
|
||||
end
|
||||
|
||||
it "overwrite cache when defined for a job and globally" do
|
||||
config = YAML.dump({
|
||||
cache: { paths: ["logs/", "binaries/"], untracked: true, key: 'global' },
|
||||
rspec: {
|
||||
script: "rspec",
|
||||
cache: { paths: ["test/"], untracked: false, key: 'local' }
|
||||
}
|
||||
})
|
||||
cache: { paths: ["logs/", "binaries/"], untracked: true, key: 'global' },
|
||||
rspec: {
|
||||
script: "rspec",
|
||||
cache: { paths: ["test/"], untracked: false, key: 'local' }
|
||||
}
|
||||
})
|
||||
|
||||
config_processor = Gitlab::Ci::YamlProcessor.new(config).execute
|
||||
|
||||
expect(config_processor.stage_builds_attributes("test").size).to eq(1)
|
||||
expect(config_processor.stage_builds_attributes("test").first[:cache]).to eq(
|
||||
expect(config_processor.stage_builds_attributes("test").first[:cache]).to eq([
|
||||
paths: ["test/"],
|
||||
untracked: false,
|
||||
key: 'local',
|
||||
policy: 'pull-push',
|
||||
when: 'on_success'
|
||||
)
|
||||
])
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ RSpec.describe Gitlab::Graphql::Docs::Renderer do
|
|||
|
||||
specify do
|
||||
expectation = <<~DOC
|
||||
### ArrayTest
|
||||
### `ArrayTest`
|
||||
|
||||
| Field | Type | Description |
|
||||
| ----- | ---- | ----------- |
|
||||
|
@ -53,7 +53,7 @@ RSpec.describe Gitlab::Graphql::Docs::Renderer do
|
|||
context 'query generation' do
|
||||
let(:expectation) do
|
||||
<<~DOC
|
||||
### foo
|
||||
### `foo`
|
||||
|
||||
List of objects.
|
||||
|
||||
|
@ -91,7 +91,7 @@ RSpec.describe Gitlab::Graphql::Docs::Renderer do
|
|||
|
||||
specify do
|
||||
expectation = <<~DOC
|
||||
### OrderingTest
|
||||
### `OrderingTest`
|
||||
|
||||
| Field | Type | Description |
|
||||
| ----- | ---- | ----------- |
|
||||
|
@ -114,7 +114,7 @@ RSpec.describe Gitlab::Graphql::Docs::Renderer do
|
|||
|
||||
specify do
|
||||
expectation = <<~DOC
|
||||
### DeprecatedTest
|
||||
### `DeprecatedTest`
|
||||
|
||||
| Field | Type | Description |
|
||||
| ----- | ---- | ----------- |
|
||||
|
@ -143,7 +143,7 @@ RSpec.describe Gitlab::Graphql::Docs::Renderer do
|
|||
|
||||
specify do
|
||||
expectation = <<~DOC
|
||||
### MyEnum
|
||||
### `MyEnum`
|
||||
|
||||
| Value | Description |
|
||||
| ----- | ----------- |
|
||||
|
|
|
@ -817,7 +817,48 @@ RSpec.describe Ci::Build do
|
|||
end
|
||||
|
||||
describe '#cache' do
|
||||
let(:options) { { cache: { key: "key", paths: ["public"], policy: "pull-push" } } }
|
||||
let(:options) do
|
||||
{ cache: [{ key: "key", paths: ["public"], policy: "pull-push" }] }
|
||||
end
|
||||
|
||||
context 'with multiple_cache_per_job FF disabled' do
|
||||
before do
|
||||
stub_feature_flags(multiple_cache_per_job: false)
|
||||
end
|
||||
let(:options) { { cache: { key: "key", paths: ["public"], policy: "pull-push" } } }
|
||||
|
||||
subject { build.cache }
|
||||
|
||||
context 'when build has cache' do
|
||||
before do
|
||||
allow(build).to receive(:options).and_return(options)
|
||||
end
|
||||
|
||||
context 'when project has jobs_cache_index' do
|
||||
before do
|
||||
allow_any_instance_of(Project).to receive(:jobs_cache_index).and_return(1)
|
||||
end
|
||||
|
||||
it { is_expected.to be_an(Array).and all(include(key: "key-1")) }
|
||||
end
|
||||
|
||||
context 'when project does not have jobs_cache_index' do
|
||||
before do
|
||||
allow_any_instance_of(Project).to receive(:jobs_cache_index).and_return(nil)
|
||||
end
|
||||
|
||||
it { is_expected.to eq([options[:cache]]) }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when build does not have cache' do
|
||||
before do
|
||||
allow(build).to receive(:options).and_return({})
|
||||
end
|
||||
|
||||
it { is_expected.to eq([]) }
|
||||
end
|
||||
end
|
||||
|
||||
subject { build.cache }
|
||||
|
||||
|
@ -826,6 +867,21 @@ RSpec.describe Ci::Build do
|
|||
allow(build).to receive(:options).and_return(options)
|
||||
end
|
||||
|
||||
context 'when build has multiple caches' do
|
||||
let(:options) do
|
||||
{ cache: [
|
||||
{ key: "key", paths: ["public"], policy: "pull-push" },
|
||||
{ key: "key2", paths: ["public"], policy: "pull-push" }
|
||||
] }
|
||||
end
|
||||
|
||||
before do
|
||||
allow_any_instance_of(Project).to receive(:jobs_cache_index).and_return(1)
|
||||
end
|
||||
|
||||
it { is_expected.to match([a_hash_including(key: "key-1"), a_hash_including(key: "key2-1")]) }
|
||||
end
|
||||
|
||||
context 'when project has jobs_cache_index' do
|
||||
before do
|
||||
allow_any_instance_of(Project).to receive(:jobs_cache_index).and_return(1)
|
||||
|
@ -839,7 +895,7 @@ RSpec.describe Ci::Build do
|
|||
allow_any_instance_of(Project).to receive(:jobs_cache_index).and_return(nil)
|
||||
end
|
||||
|
||||
it { is_expected.to eq([options[:cache]]) }
|
||||
it { is_expected.to eq(options[:cache]) }
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -848,7 +904,7 @@ RSpec.describe Ci::Build do
|
|||
allow(build).to receive(:options).and_return({})
|
||||
end
|
||||
|
||||
it { is_expected.to eq([nil]) }
|
||||
it { is_expected.to be_empty }
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ RSpec.describe 'container repository details' do
|
|||
graphql_query_for(
|
||||
'containerRepository',
|
||||
{ id: container_repository_global_id },
|
||||
all_graphql_fields_for('ContainerRepositoryDetails')
|
||||
all_graphql_fields_for('ContainerRepositoryDetails', excluded: ['pipeline'])
|
||||
)
|
||||
end
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ RSpec.describe 'getting container repositories in a group' do
|
|||
<<~GQL
|
||||
edges {
|
||||
node {
|
||||
#{all_graphql_fields_for('container_repositories'.classify)}
|
||||
#{all_graphql_fields_for('container_repositories'.classify, max_depth: 1)}
|
||||
}
|
||||
}
|
||||
GQL
|
||||
|
|
|
@ -23,7 +23,7 @@ RSpec.describe 'getting projects' do
|
|||
projects(includeSubgroups: #{include_subgroups}) {
|
||||
edges {
|
||||
node {
|
||||
#{all_graphql_fields_for('Project')}
|
||||
#{all_graphql_fields_for('Project', max_depth: 1)}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ RSpec.describe 'package details' do
|
|||
end
|
||||
|
||||
let(:depth) { 3 }
|
||||
let(:excluded) { %w[metadata apiFuzzingCiConfiguration] }
|
||||
let(:excluded) { %w[metadata apiFuzzingCiConfiguration pipeline] }
|
||||
|
||||
let(:query) do
|
||||
graphql_query_for(:package, { id: package_global_id }, <<~FIELDS)
|
||||
|
|
|
@ -16,7 +16,7 @@ RSpec.describe 'getting container repositories in a project' do
|
|||
<<~GQL
|
||||
edges {
|
||||
node {
|
||||
#{all_graphql_fields_for('container_repositories'.classify)}
|
||||
#{all_graphql_fields_for('container_repositories'.classify, excluded: ['pipeline'])}
|
||||
}
|
||||
}
|
||||
GQL
|
||||
|
|
|
@ -34,7 +34,7 @@ RSpec.describe 'getting notes for a merge request' do
|
|||
notes {
|
||||
edges {
|
||||
node {
|
||||
#{all_graphql_fields_for('Note')}
|
||||
#{all_graphql_fields_for('Note', excluded: ['pipeline'])}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ RSpec.describe 'getting merge request information nested in a project' do
|
|||
let(:current_user) { create(:user) }
|
||||
let(:merge_request_graphql_data) { graphql_data['project']['mergeRequest'] }
|
||||
let!(:merge_request) { create(:merge_request, source_project: project) }
|
||||
let(:mr_fields) { all_graphql_fields_for('MergeRequest') }
|
||||
let(:mr_fields) { all_graphql_fields_for('MergeRequest', excluded: ['pipeline']) }
|
||||
|
||||
let(:query) do
|
||||
graphql_query_for(
|
||||
|
|
|
@ -11,10 +11,14 @@ RSpec.describe 'getting pipeline information nested in a project' do
|
|||
let(:pipeline_graphql_data) { graphql_data['project']['pipeline'] }
|
||||
|
||||
let!(:query) do
|
||||
graphql_query_for(
|
||||
'project',
|
||||
{ 'fullPath' => project.full_path },
|
||||
query_graphql_field('pipeline', iid: pipeline.iid.to_s)
|
||||
%(
|
||||
query {
|
||||
project(fullPath: "#{project.full_path}") {
|
||||
pipeline(iid: "#{pipeline.iid}") {
|
||||
configSource
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
|
|
|
@ -192,7 +192,17 @@ module TestEnv
|
|||
end
|
||||
|
||||
def gitaly_dir
|
||||
File.dirname(gitaly_socket_path)
|
||||
socket_path = gitaly_socket_path
|
||||
socket_path = File.expand_path(gitaly_socket_path) if expand_path?
|
||||
|
||||
File.dirname(socket_path)
|
||||
end
|
||||
|
||||
# Linux fails with "bind: invalid argument" if a UNIX socket path exceeds 108 characters:
|
||||
# https://github.com/golang/go/issues/6895. We use absolute paths in CI to ensure
|
||||
# that changes in the current working directory don't affect GRPC reconnections.
|
||||
def expand_path?
|
||||
!!ENV['CI']
|
||||
end
|
||||
|
||||
def start_gitaly(gitaly_dir)
|
||||
|
|
|
@ -17,7 +17,7 @@ RSpec.shared_context 'exposing regular notes on a noteable in GraphQL' do
|
|||
notes {
|
||||
edges {
|
||||
node {
|
||||
#{all_graphql_fields_for('Note')}
|
||||
#{all_graphql_fields_for('Note', max_depth: 1)}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue