Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2021-03-04 00:11:19 +00:00
parent 63b3a14f15
commit b3930fc34f
48 changed files with 690 additions and 1483 deletions

View file

@ -160,7 +160,7 @@ gem 'wikicloth', '0.8.1'
gem 'asciidoctor', '~> 2.0.10'
gem 'asciidoctor-include-ext', '~> 0.3.1', require: false
gem 'asciidoctor-plantuml', '~> 0.0.12'
gem 'asciidoctor-kroki', '~> 0.3.0', require: false
gem 'asciidoctor-kroki', '~> 0.4.0', require: false
gem 'rouge', '~> 3.26.0'
gem 'truncato', '~> 0.7.11'
gem 'bootstrap_form', '~> 4.2.0'

View file

@ -84,7 +84,7 @@ GEM
asciidoctor (2.0.12)
asciidoctor-include-ext (0.3.1)
asciidoctor (>= 1.5.6, < 3.0.0)
asciidoctor-kroki (0.3.0)
asciidoctor-kroki (0.4.0)
asciidoctor (~> 2.0)
asciidoctor-plantuml (0.0.12)
asciidoctor (>= 1.5.6, < 3.0.0)
@ -1334,7 +1334,7 @@ DEPENDENCIES
asana (~> 0.10.3)
asciidoctor (~> 2.0.10)
asciidoctor-include-ext (~> 0.3.1)
asciidoctor-kroki (~> 0.3.0)
asciidoctor-kroki (~> 0.4.0)
asciidoctor-plantuml (~> 0.0.12)
atlassian-jwt (~> 0.2.0)
attr_encrypted (~> 3.1.0)

View file

@ -2,7 +2,6 @@
import {
GlDropdown,
GlDropdownDivider,
GlDropdownSectionHeader,
GlSearchBoxByType,
GlSprintf,
GlIcon,
@ -27,7 +26,6 @@ export default {
components: {
GlDropdown,
GlDropdownDivider,
GlDropdownSectionHeader,
GlSearchBoxByType,
GlSprintf,
GlIcon,
@ -161,8 +159,13 @@ export default {
</script>
<template>
<gl-dropdown v-bind="$attrs" class="ref-selector" @shown="focusSearchBox">
<template slot="button-content">
<gl-dropdown
v-bind="$attrs"
:header-text="i18n.dropdownHeader"
class="ref-selector"
@shown="focusSearchBox"
>
<template #button-content>
<span class="gl-flex-grow-1 gl-ml-2 gl-text-gray-400" data-testid="button-content">
<span v-if="selectedRef" class="gl-font-monospace">{{ selectedRef }}</span>
<span v-else>{{ i18n.noRefSelected }}</span>
@ -170,13 +173,7 @@ export default {
<gl-icon name="chevron-down" />
</template>
<div class="gl-display-flex gl-flex-direction-column ref-selector-dropdown-content">
<gl-dropdown-section-header>
<span class="gl-text-center gl-display-block">{{ i18n.dropdownHeader }}</span>
</gl-dropdown-section-header>
<gl-dropdown-divider />
<template #header>
<gl-search-box-by-type
ref="searchBox"
v-model.trim="query"
@ -184,15 +181,11 @@ export default {
@input="onSearchBoxInput"
@keydown.enter.prevent="onSearchBoxEnter"
/>
</template>
<div class="gl-flex-grow-1 gl-overflow-y-auto">
<gl-loading-icon v-if="isLoading" size="lg" class="gl-my-3" />
<div
v-else-if="showNoResults"
class="gl-text-center gl-mx-3 gl-py-3"
data-testid="no-results"
>
<div v-else-if="showNoResults" class="gl-text-center gl-mx-3 gl-py-3" data-testid="no-results">
<gl-sprintf v-if="lastQuery" :message="i18n.noResultsWithQuery">
<template #query>
<b class="gl-word-break-all">{{ lastQuery }}</b>
@ -249,7 +242,5 @@ export default {
/>
</template>
</template>
</div>
</div>
</gl-dropdown>
</template>

View file

@ -1,13 +1,4 @@
.ref-selector {
& &-dropdown-content {
// Setting a max height is necessary to allow the dropdown's content
// to control where and how scrollbars appear.
// This content is limited to the max-height of the dropdown
// ($dropdown-max-height-lg) minus the additional padding
// on the top and bottom (2 * $gl-padding-8)
max-height: $dropdown-max-height-lg - 2 * $gl-padding-8;
}
.dropdown-menu.show {
// Make the dropdown a little wider and longer than usual
// since it contains quite a bit of content.

View file

@ -12,7 +12,7 @@
module Security
class LicenseComplianceJobsFinder < JobsFinder
def self.allowed_job_types
[:license_management, :license_scanning]
[:license_scanning]
end
end
end

View file

@ -17,15 +17,21 @@ module Resolvers
default_value: nil,
description: 'Sort projects by this criteria.'
argument :ids, [GraphQL::ID_TYPE],
required: false,
default_value: nil,
description: 'Filter projects by IDs.'
type Types::ProjectType, null: true
def resolve(include_subgroups:, sort:, search:)
def resolve(include_subgroups:, sort:, search:, ids:)
# The namespace could have been loaded in batch by `BatchLoader`.
# At this point we need the `id` or the `full_path` of the namespace
# to query for projects, so make sure it's loaded and not `nil` before continuing.
return Project.none if namespace.nil?
query = include_subgroups ? namespace.all_projects.with_route : namespace.projects.with_route
query = ids ? query.merge(Project.where(id: parse_gids(ids))) : query # rubocop: disable CodeReuse/ActiveRecord
return query unless search.present?
@ -48,6 +54,10 @@ module Resolvers
object.respond_to?(:sync) ? object.sync : object
end
end
def parse_gids(gids)
gids&.map { |gid| GitlabSchema.parse_gid(gid, expected_type: ::Project).model_id }
end
end
end

View file

@ -92,7 +92,7 @@ module Users
# remove - The IDs of the authorization rows to remove.
# add - Rows to insert in the form `[user id, project id, access level]`
def update_authorizations(remove = [], add = [])
log_refresh_details(remove.length, add.length)
log_refresh_details(remove, add)
User.transaction do
user.remove_project_authorizations(remove) unless remove.empty?
@ -104,11 +104,16 @@ module Users
user.reset
end
def log_refresh_details(rows_deleted, rows_added)
def log_refresh_details(remove, add)
Gitlab::AppJsonLogger.info(event: 'authorized_projects_refresh',
user_id: user.id,
'authorized_projects_refresh.source': source,
'authorized_projects_refresh.rows_deleted': rows_deleted,
'authorized_projects_refresh.rows_added': rows_added)
'authorized_projects_refresh.rows_deleted_count': remove.length,
'authorized_projects_refresh.rows_added_count': add.length,
# most often there's only a few entries in remove and add, but limit it to the first 5
# entries to avoid flooding the logs
'authorized_projects_refresh.rows_deleted_slice': remove.first(5),
'authorized_projects_refresh.rows_added_slice': add.first(5))
end
def fresh_access_levels_per_project

View file

@ -0,0 +1,5 @@
---
title: Update Kroki to fix Wavedrom graphs
merge_request: 55659
author:
type: fixed

View file

@ -0,0 +1,5 @@
---
title: Query group projects by ids with GraphQL
merge_request: 55383
author:
type: added

View file

@ -0,0 +1,5 @@
---
title: Small visual updates to Git ref selector dropdown on New/Edit Release page
merge_request: 55121
author:
type: changed

View file

@ -1,5 +0,0 @@
---
title: Add rake task to cleanup description templates cache in batches
merge_request: 54706
author:
type: added

View file

@ -1,5 +0,0 @@
---
title: Do not expose user name if user is project bot
merge_request: 54022
author:
type: changed

View file

@ -13,13 +13,13 @@ GitLab provides Rake tasks for general maintenance.
This command gathers information about your GitLab installation and the system it runs on.
These may be useful when asking for help or reporting issues.
**For Omnibus installations**
**Omnibus Installation**
```shell
sudo gitlab-rake gitlab:env:info
```
**For installations from source**
**Source Installation**
```shell
bundle exec rake gitlab:env:info RAILS_ENV=production
@ -76,13 +76,13 @@ installations: a license cannot be installed into GitLab Community Edition.
These may be useful when raising tickets with Support, or for programmatically
checking your license parameters.
**For Omnibus installations**
**Omnibus Installation**
```shell
sudo gitlab-rake gitlab:license:info
```
**For installations from source**
**Source Installation**
```shell
bundle exec rake gitlab:license:info RAILS_ENV=production
@ -119,13 +119,13 @@ You may also have a look at our troubleshooting guides for:
To run `gitlab:check`, run:
**For Omnibus installations**
**Omnibus Installation**
```shell
sudo gitlab-rake gitlab:check
```
**For installations from source**
**Source Installation**
```shell
bundle exec rake gitlab:check RAILS_ENV=production
@ -182,13 +182,13 @@ Checking GitLab ... Finished
In some case it is necessary to rebuild the `authorized_keys` file. To do this, run:
**For Omnibus installations**
**Omnibus Installation**
```shell
sudo gitlab-rake gitlab:shell:setup
```
**For installations from source**
**Source Installation**
```shell
cd /home/git/gitlab
@ -203,64 +203,18 @@ You will lose any data stored in authorized_keys file.
Do you want to continue (yes/no)? yes
```
## Clear issue and merge request description template names cache
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/54706) in GitLab 13.10.
If the issue or merge request description template names in the dropdown
do not reflect the actual description template names in the repository, consider clearing
the Redis cache that stores the template names information.
You can clear the cache of
[all issues and merge request templates in the installation](#clear-cache-for-all-issue-and-merge-request-template-names)
or [in a specific project](#clear-cache-for-issue-and-merge-request-template-names-in-specific-projects).
### Clear cache for all issue and merge request template names
If you want to refresh issue and merge request templates for all projects:
**For Omnibus installations**
```shell
sudo gitlab-rake cache:clear:description_templates
```
**For installations from source**
```shell
cd /home/git/gitlab
sudo -u git -H bundle exec rake cache:clear:description_templates RAILS_ENV=production
```
### Clear cache for issue and merge request template names in specific projects
If you want to refresh issue and merge request templates for specific projects,
provide a comma-separated list of IDs as the `project_ids` parameter to the Rake task.
**For Omnibus installations**
```shell
sudo gitlab-rake cache:clear:description_templates project_ids=10,25,35
```
**For installations from source**
```shell
cd /home/git/gitlab
sudo -u git -H bundle exec rake cache:clear:description_templates project_ids=10,25,35 RAILS_ENV=production
```
## Clear Redis cache
If for some reason the dashboard displays the wrong information, you might want to
clear Redis' cache. To do this, run:
**For Omnibus installations**
**Omnibus Installation**
```shell
sudo gitlab-rake cache:clear
```
**For installations from source**
**Source Installation**
```shell
cd /home/git/gitlab
@ -275,7 +229,7 @@ missing some icons. In that case, try to precompile the assets again.
This only applies to source installations and does NOT apply to
Omnibus packages.
**For installations from source**
**Source Installation**
```shell
cd /home/git/gitlab
@ -295,13 +249,13 @@ Sometimes you need to know if your GitLab installation can connect to a TCP
service on another machine - perhaps a PostgreSQL or HTTPS server. A Rake task
is included to help you with this:
**For Omnibus installations**
**Omnibus Installation**
```shell
sudo gitlab-rake gitlab:tcp_check[example.com,80]
```
**For installations from source**
**Source Installation**
```shell
cd /home/git/gitlab

View file

@ -22,7 +22,7 @@ GET /projects/:id/deployments
| `sort` | string | no | Return deployments sorted in `asc` or `desc` order. Default is `asc` |
| `updated_after` | datetime | no | Return deployments updated after the specified date. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`) |
| `updated_before` | datetime | no | Return deployments updated before the specified date. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`) |
| `environment` | string | no | The [name of the environment](../ci/environments/index.md#defining-environments) to filter deployments by |
| `environment` | string | no | The [name of the environment](../ci/environments/index.md) to filter deployments by |
| `status` | string | no | The status to filter deployments by |
The status attribute can be one of the following values:
@ -281,7 +281,7 @@ POST /projects/:id/deployments
| Attribute | Type | Required | Description |
|---------------|----------------|----------|-----------------------------------------------------------------------------------------------------------------|
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
| `environment` | string | yes | The [name of the environment](../ci/environments/index.md#defining-environments) to create the deployment for |
| `environment` | string | yes | The [name of the environment](../ci/environments/index.md) to create the deployment for |
| `sha` | string | yes | The SHA of the commit that is deployed |
| `ref` | string | yes | The name of the branch or tag that is deployed |
| `tag` | boolean | yes | A boolean that indicates if the deployed ref is a tag (true) or not (false) |

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

View file

@ -25,49 +25,51 @@ If you have a deployment service like [Kubernetes](../../user/project/clusters/i
associated with your project, you can use it to assist with your deployments.
You can even access a [web terminal](#web-terminals) for your environment from within GitLab.
## Configuring environments
## View environments and deployments
Configuring environments involves:
Prerequisites:
1. Understanding how [pipelines](../pipelines/index.md) work.
1. Defining environments in your project's [`.gitlab-ci.yml`](../yaml/README.md) file.
1. Creating a job configured to deploy your application. For example, a deploy job configured with [`environment`](../yaml/README.md#environment) to deploy your application to a [Kubernetes cluster](../../user/project/clusters/index.md).
- You must have a minimum of [Reporter permission](../../user/permissions.md#project-members-permissions).
The rest of this section illustrates how to configure environments and deployments using
an example scenario. It assumes you have already:
To view a list of environments and deployments:
- Created a [project](../../user/project/working_with_projects.md#create-a-project) in GitLab.
- Set up [a runner](../runners/README.md).
1. Go to the project's **Operations > Environments** page.
The environments are displayed.
In the scenario:
![Environments list](img/environments_list.png)
- We are developing an application.
- We want to run tests and build our app on all branches.
- Our default branch is `master`.
- We deploy the app only when a pipeline on `master` branch is run.
1. To view a list of deployments for an environment, select the environment name,
for example, `staging`.
### Defining environments
![Deployments list](img/deployments_list.png)
You can create environments manually in the web interface, but we recommend
that you define your environments in the `.gitlab-ci.yml` file. After the first
deploy, the environments are automatically created.
Deployments show up in this list only after a deployment job has created them.
Let's consider the following `.gitlab-ci.yml` example:
## Types of environments
There are two types of environments:
- Static environments have static names, like `staging` or `production`.
- Dynamic environments have dynamic names. Dynamic environments
are a fundamental part of [Review apps](../review_apps/index.md).
### Create a static environment
You can create an environment and deployment in the UI or in your `.gitlab-ci.yml` file.
In the UI:
1. Go to the project's **Operations > Environments** page.
1. Select **New environment**.
1. Enter a name and external URL.
1. Select **Save**.
In your `.gitlab-ci.yml` file:
1. Specify a name for the environment and optionally, a URL, which determines the deployment URL.
For example:
```yaml
stages:
- test
- build
- deploy
test:
stage: test
script: echo "Running tests"
build:
stage: build
script: echo "Building the app"
deploy_staging:
stage: deploy
script:
@ -75,245 +77,21 @@ deploy_staging:
environment:
name: staging
url: https://staging.example.com
only:
- master
```
We have defined three [stages](../yaml/README.md#stages):
1. Trigger a deployment. (For example, by creating and pushing a commit.)
- `test`
- `build`
- `deploy`
When the job runs, the environment and deployment are created.
The jobs assigned to these stages run in this order. If any job fails, then
the pipeline fails and jobs that are assigned to the next stage don't run.
NOTE:
Some characters cannot be used in environment names.
For more information about the `environment` keywords, see
[the `.gitlab-ci.yml` keyword reference](../yaml/README.md#environment).
In our case:
### Create a dynamic environment
- The `test` job runs first.
- Then the `build` job.
- Lastly the `deploy_staging` job.
With this configuration, we:
- Check that the tests pass.
- Ensure that our app is able to be built successfully.
- Lastly we deploy to the staging server.
Note that the `environment` keyword defines where the app is deployed. The environment `name` and
`url` is exposed in various places within GitLab. Each time a job that has an environment specified
succeeds, a deployment is recorded along with the Git SHA and environment name.
WARNING:
Some characters are not allowed in environment names. Use only letters,
numbers, spaces, and `-`, `_`, `/`, `{`, `}`, or `.`. Also, it must not start nor end with `/`.
In summary, with the above `.gitlab-ci.yml` we have achieved the following:
- All branches run the `test` and `build` jobs.
- The `deploy_staging` job runs [only](../yaml/README.md#onlyexcept-basic) on the `master`
branch, which means all merge requests that are created from branches don't
get deployed to the staging server.
- When a merge request is merged, all jobs run and the `deploy_staging`
job deploys our code to a staging server while the deployment
is recorded in an environment named `staging`.
#### CI/CD variables and runners
Starting with GitLab 8.15, the environment name is exposed to the runner in
two forms:
- `$CI_ENVIRONMENT_NAME`. The name given in `.gitlab-ci.yml` (with any CI/CD variables
expanded).
- `$CI_ENVIRONMENT_SLUG`. A "cleaned-up" version of the name, suitable for use in URLs,
DNS, etc.
If you change the name of an existing environment, the:
- `$CI_ENVIRONMENT_NAME` variable is updated with the new environment name.
- `$CI_ENVIRONMENT_SLUG` variable remains unchanged to prevent unintended side
effects.
Starting with GitLab 9.3, the environment URL is exposed to the runner via
`$CI_ENVIRONMENT_URL`. The URL is expanded from either:
- `.gitlab-ci.yml`.
- The external URL from the environment if not defined in `.gitlab-ci.yml`.
#### Set dynamic environment URLs after a job finishes
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/17066) in GitLab 12.9.
In a job script, you can specify a static [environment URL](#using-the-environment-url).
However, there may be times when you want a dynamic URL. For example,
if you deploy a Review App to an external hosting
service that generates a random URL per deployment, like `https://94dd65b.amazonaws.com/qa-lambda-1234567`,
you don't know the URL before the deployment script finishes.
If you want to use the environment URL in GitLab, you would have to update it manually.
To address this problem, you can configure a deployment job to report back a set of
variables, including the URL that was dynamically-generated by the external service.
GitLab supports the [dotenv (`.env`)](https://github.com/bkeepers/dotenv) file format,
and expands the `environment:url` value with variables defined in the `.env` file.
To use this feature, specify the
[`artifacts:reports:dotenv`](../pipelines/job_artifacts.md#artifactsreportsdotenv) keyword in `.gitlab-ci.yml`.
<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
For an overview, see [Set dynamic URLs after a job finished](https://youtu.be/70jDXtOf4Ig).
##### Example of setting dynamic environment URLs
The following example shows a Review App that creates a new environment
per merge request. The `review` job is triggered by every push, and
creates or updates an environment named `review/your-branch-name`.
The environment URL is set to `$DYNAMIC_ENVIRONMENT_URL`:
```yaml
review:
script:
- DYNAMIC_ENVIRONMENT_URL=$(deploy-script) # In script, get the environment URL.
- echo "DYNAMIC_ENVIRONMENT_URL=$DYNAMIC_ENVIRONMENT_URL" >> deploy.env # Add the value to a dotenv file.
artifacts:
reports:
dotenv: deploy.env # Report back dotenv file to rails.
environment:
name: review/$CI_COMMIT_REF_SLUG
url: $DYNAMIC_ENVIRONMENT_URL # and set the variable produced in script to `environment:url`
on_stop: stop_review
stop_review:
script:
- ./teardown-environment
when: manual
environment:
name: review/$CI_COMMIT_REF_SLUG
action: stop
```
As soon as the `review` job finishes, GitLab updates the `review/your-branch-name`
environment's URL.
It parses the `deploy.env` report artifact, registers a list of variables as runtime-created,
uses it for expanding `environment:url: $DYNAMIC_ENVIRONMENT_URL` and sets it to the environment URL.
You can also specify a static part of the URL at `environment:url:`, such as
`https://$DYNAMIC_ENVIRONMENT_URL`. If the value of `DYNAMIC_ENVIRONMENT_URL` is
`example.com`, the final result is `https://example.com`.
The assigned URL for the `review/your-branch-name` environment is [visible in the UI](#using-the-environment-url).
Note the following:
- `stop_review` doesn't generate a dotenv report artifact, so it doesn't recognize the
`DYNAMIC_ENVIRONMENT_URL` environment variable. Therefore you shouldn't set `environment:url:` in the
`stop_review` job.
- If the environment URL isn't valid (for example, the URL is malformed), the system doesn't update
the environment URL.
- If the script that runs in `stop_review` exists only in your repository and therefore can't use
`GIT_STRATEGY: none`, configure [pipelines for merge requests](../../ci/merge_request_pipelines/index.md)
for these jobs. This ensures that runners can fetch the repository even after a feature branch is
deleted. For more information, see [Ref Specs for Runners](../pipelines/index.md#ref-specs-for-runners).
### Configuring manual deployments
Adding `when: manual` to an automatically executed job's configuration converts it to
a job requiring manual action.
To expand on the [previous example](#defining-environments), the following includes
another job that deploys our app to a production server and is
tracked by a `production` environment.
The `.gitlab-ci.yml` file for this is as follows:
```yaml
stages:
- test
- build
- deploy
test:
stage: test
script: echo "Running tests"
build:
stage: build
script: echo "Building the app"
deploy_staging:
stage: deploy
script:
- echo "Deploy to staging server"
environment:
name: staging
url: https://staging.example.com
only:
- master
deploy_prod:
stage: deploy
script:
- echo "Deploy to production server"
environment:
name: production
url: https://example.com
when: manual
only:
- master
```
The `when: manual` action:
- Exposes a "play" button in the GitLab UI for that job.
- Means the `deploy_prod` job is only triggered when the "play" button is clicked.
You can find the "play" button in the pipelines, environments, deployments, and jobs views.
| View | Screenshot |
|:----------------|:-------------------------------------------------------------------------------|
| Pipelines | ![Pipelines manual action](../img/environments_manual_action_pipelines.png) |
| Single pipeline | ![Pipelines manual action](../img/environments_manual_action_single_pipeline.png) |
| Environments | ![Environments manual action](../img/environments_manual_action_environments.png) |
| Deployments | ![Deployments manual action](../img/environments_manual_action_deployments.png) |
| Jobs | ![Builds manual action](../img/environments_manual_action_jobs.png) |
Clicking the play button in any view triggers the `deploy_prod` job. The deployment is recorded as a
new environment named `production`.
If your environment's name is `production` (all lowercase), it's recorded in
[Value Stream Analytics](../../user/analytics/value_stream_analytics.md).
### Configuring dynamic environments
Regular environments are good when deploying to "stable" environments like staging or production.
However, for environments for branches other than `master`, dynamic environments
can be used. Dynamic environments make it possible to create environments on the fly by
declaring their names dynamically in `.gitlab-ci.yml`.
Dynamic environments are a fundamental part of [Review apps](../review_apps/index.md).
#### Allowed variables
The `name` and `url` keywords for dynamic environments can use most available CI/CD variables,
including:
- [Predefined CI/CD variables](../variables/README.md#predefined-cicd-variables)
- [Project and group CI/CD variables](../variables/README.md)
- [`.gitlab-ci.yml` CI/CD variables](../yaml/README.md#variables)
However, you cannot use variables defined:
- Under `script`.
- On the runner's side.
There are also other variables that are unsupported in the context of `environment:name`.
For more information, see [Where variables can be used](../variables/where_variables_can_be_used.md).
#### Example configuration
Runners expose various [predefined CI/CD variables](../variables/predefined_variables.md) when a job runs, so
you can use them as environment names.
In the following example, the job deploys to all branches except `master`:
To create a dynamic name and URL for an environment, you can use
[predefined CI/CD variables](../variables/predefined_variables.md). For example:
```yaml
deploy_review:
@ -331,37 +109,47 @@ deploy_review:
In this example:
- The job's name is `deploy_review` and it runs on the `deploy` stage.
- We set the `environment` with the `environment:name` as `review/$CI_COMMIT_REF_NAME`.
Since the [environment name](../yaml/README.md#environmentname) can contain slashes (`/`), we can
use this pattern to distinguish between dynamic and regular environments.
- We tell the job to run [`only`](../yaml/README.md#onlyexcept-basic) on branches,
[`except`](../yaml/README.md#onlyexcept-basic) `master`.
- The `name` is `review/$CI_COMMIT_REF_NAME`. Because the [environment name](../yaml/README.md#environmentname)
can contain slashes (`/`), you can use this pattern to distinguish between dynamic and static environments.
- For the `url`, you could use `$CI_COMMIT_REF_NAME`, but because this value
may contain a `/` or other characters that would not be valid in a domain name or URL,
use `$CI_ENVIRONMENT_SLUG` instead. The `$CI_ENVIRONMENT_SLUG` variable is guaranteed to be unique.
For the value of:
- `environment:name`, the first part is `review`, followed by a `/` and then `$CI_COMMIT_REF_NAME`,
which receives the value of the branch name.
- `environment:url`, we want a specific and distinct URL for each branch. `$CI_COMMIT_REF_NAME`
may contain a `/` or other characters that would be invalid in a domain name or URL,
so we use `$CI_ENVIRONMENT_SLUG` to guarantee that we get a valid URL.
For example, given a `$CI_COMMIT_REF_NAME` of `100-Do-The-Thing`, the URL is something
like `https://100-do-the-4f99a2.example.com`. Again, the way you set up
the web server to serve these requests is based on your setup.
We have used `$CI_ENVIRONMENT_SLUG` here because it is guaranteed to be unique. If
you're using a workflow like [GitLab Flow](../../topics/gitlab_flow.md), collisions
are unlikely and you may prefer environment names to be more closely based on the
branch name. In that case, you could use `$CI_COMMIT_REF_NAME` in `environment:url` in
the example above: `https://$CI_COMMIT_REF_NAME.example.com`, which would give a URL
of `https://100-do-the-thing.example.com`.
You aren't required to use the same prefix or only slashes (`/`) in the dynamic environments' names.
However, using this format enables the [grouping similar environments](#grouping-similar-environments)
You do not have to use the same prefix or only slashes (`/`) in the dynamic environment name.
However, when you use this format, you can use the [grouping similar environments](#grouping-similar-environments)
feature.
### Configuring Kubernetes deployments
NOTE:
Some variables cannot be used as environment names or URLs.
For more information about the `environment` keywords, see
[the `.gitlab-ci.yml` keyword reference](../yaml/README.md#environment).
## Configure manual deployments
You can create a job that requires someone to manually start the deployment.
For example:
```yaml
deploy_prod:
stage: deploy
script:
- echo "Deploy to production server"
environment:
name: production
url: https://example.com
when: manual
only:
- master
```
The `when: manual` action:
- Exposes a play button for the job in the GitLab UI.
- Means the `deploy_prod` job is only triggered when the play button is clicked.
You can find the play button in the pipelines, environments, deployments, and jobs views.
## Configure Kubernetes deployments
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/27630) in GitLab 12.6.
@ -402,132 +190,114 @@ trace on the deployment job page:
![Deployment cluster information](../img/environments_deployment_cluster_v12_8.png)
#### Configuring incremental rollouts
### Configure incremental rollouts
Learn how to release production changes to only a portion of your Kubernetes pods with
[incremental rollouts](../environments/incremental_rollouts.md).
### Deployment safety
## CI/CD variables for environments and deployments
When you create an environment, you specify the name and URL.
If you want to use the name or URL in another job, you can use:
- `$CI_ENVIRONMENT_NAME`. The name defined in the `.gitlab-ci.yml` file.
- `$CI_ENVIRONMENT_SLUG`. A "cleaned-up" version of the name, suitable for use in URLs,
DNS, etc. This variable is guaranteed to be unique.
- `$CI_ENVIRONMENT_URL`. The environment's URL, which was specified in the
`.gitlab-ci.yml` file or automatically assigned.
If you change the name of an existing environment, the:
- `$CI_ENVIRONMENT_NAME` variable is updated with the new environment name.
- `$CI_ENVIRONMENT_SLUG` variable remains unchanged to prevent unintended side
effects.
## Set dynamic environment URLs after a job finishes
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/17066) in GitLab 12.9.
In a job script, you can specify a static environment URL.
However, there may be times when you want a dynamic URL. For example,
if you deploy a Review App to an external hosting
service that generates a random URL per deployment, like `https://94dd65b.amazonaws.com/qa-lambda-1234567`,
you don't know the URL before the deployment script finishes.
If you want to use the environment URL in GitLab, you would have to update it manually.
To address this problem, you can configure a deployment job to report back a set of
variables, including the URL that was dynamically-generated by the external service.
GitLab supports the [dotenv (`.env`)](https://github.com/bkeepers/dotenv) file format,
and expands the `environment:url` value with variables defined in the `.env` file.
To use this feature, specify the
[`artifacts:reports:dotenv`](../pipelines/job_artifacts.md#artifactsreportsdotenv) keyword in `.gitlab-ci.yml`.
<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
For an overview, see [Set dynamic URLs after a job finished](https://youtu.be/70jDXtOf4Ig).
### Example of setting dynamic environment URLs
The following example shows a Review App that creates a new environment
per merge request. The `review` job is triggered by every push, and
creates or updates an environment named `review/your-branch-name`.
The environment URL is set to `$DYNAMIC_ENVIRONMENT_URL`:
```yaml
review:
script:
- DYNAMIC_ENVIRONMENT_URL=$(deploy-script) # In script, get the environment URL.
- echo "DYNAMIC_ENVIRONMENT_URL=$DYNAMIC_ENVIRONMENT_URL" >> deploy.env # Add the value to a dotenv file.
artifacts:
reports:
dotenv: deploy.env # Report back dotenv file to rails.
environment:
name: review/$CI_COMMIT_REF_SLUG
url: $DYNAMIC_ENVIRONMENT_URL # and set the variable produced in script to `environment:url`
on_stop: stop_review
stop_review:
script:
- ./teardown-environment
when: manual
environment:
name: review/$CI_COMMIT_REF_SLUG
action: stop
```
As soon as the `review` job finishes, GitLab updates the `review/your-branch-name`
environment's URL.
It parses the `deploy.env` report artifact, registers a list of variables as runtime-created,
uses it for expanding `environment:url: $DYNAMIC_ENVIRONMENT_URL` and sets it to the environment URL.
You can also specify a static part of the URL at `environment:url:`, such as
`https://$DYNAMIC_ENVIRONMENT_URL`. If the value of `DYNAMIC_ENVIRONMENT_URL` is
`example.com`, the final result is `https://example.com`.
The assigned URL for the `review/your-branch-name` environment is visible in the UI.
Note the following:
- `stop_review` doesn't generate a dotenv report artifact, so it doesn't recognize the
`DYNAMIC_ENVIRONMENT_URL` environment variable. Therefore you shouldn't set `environment:url:` in the
`stop_review` job.
- If the environment URL isn't valid (for example, the URL is malformed), the system doesn't update
the environment URL.
- If the script that runs in `stop_review` exists only in your repository and therefore can't use
`GIT_STRATEGY: none`, configure [pipelines for merge requests](../../ci/merge_request_pipelines/index.md)
for these jobs. This ensures that runners can fetch the repository even after a feature branch is
deleted. For more information, see [Ref Specs for Runners](../pipelines/index.md#ref-specs-for-runners).
## Deployment safety
Deployment jobs can be more sensitive than other jobs in a pipeline,
and might need to be treated with an extra care. There are multiple features
in GitLab that helps maintain deployment security and stability.
in GitLab that help maintain deployment security and stability.
- [Restrict write-access to a critical environment](deployment_safety.md#restrict-write-access-to-a-critical-environment)
- [Limit the job-concurrency for deployment jobs](deployment_safety.md#ensure-only-one-deployment-job-runs-at-a-time)
- [Skip outdated deployment jobs](deployment_safety.md#skip-outdated-deployment-jobs)
- [Prevent deployments during deploy freeze windows](deployment_safety.md#prevent-deployments-during-deploy-freeze-windows)
### Complete example
The configuration in this section provides a full development workflow where your app is:
- Tested.
- Built.
- Deployed as a Review App.
- Deployed to a staging server after the merge request is merged.
- Finally, able to be manually deployed to the production server.
The following combines the previous configuration examples, including:
- Defining [simple environments](#defining-environments) for testing, building, and deployment to staging.
- Adding [manual actions](#configuring-manual-deployments) for deployment to production.
- Creating [dynamic environments](#configuring-dynamic-environments) for deployments for reviewing.
```yaml
stages:
- test
- build
- deploy
test:
stage: test
script: echo "Running tests"
build:
stage: build
script: echo "Building the app"
deploy_review:
stage: deploy
script:
- echo "Deploy a review app"
environment:
name: review/$CI_COMMIT_REF_NAME
url: https://$CI_ENVIRONMENT_SLUG.example.com
only:
- branches
except:
- master
deploy_staging:
stage: deploy
script:
- echo "Deploy to staging server"
environment:
name: staging
url: https://staging.example.com
only:
- master
deploy_prod:
stage: deploy
script:
- echo "Deploy to production server"
environment:
name: production
url: https://example.com
when: manual
only:
- master
```
A more realistic example would also include copying files to a location where a
webserver (for example, NGINX) could then access and serve them.
The example below copies the `public` directory to `/srv/nginx/$CI_COMMIT_REF_SLUG/public`:
```yaml
review_app:
stage: deploy
script:
- rsync -av --delete public /srv/nginx/$CI_COMMIT_REF_SLUG
environment:
name: review/$CI_COMMIT_REF_NAME
url: https://$CI_COMMIT_REF_SLUG.example.com
```
This example requires that NGINX and GitLab Runner are set up on the server this job runs on.
See the [limitations](#limitations) section for some edge cases regarding the naming of your
branches and Review Apps.
The complete example provides the following workflow to developers:
- Create a branch locally.
- Make changes and commit them.
- Push the branch to GitLab.
- Create a merge request.
Behind the scenes, the runner:
- Picks up the changes and starts running the jobs.
- Runs the jobs sequentially as defined in `stages`:
- First, run the tests.
- If the tests succeed, build the app.
- If the build succeeds, the app is deployed to an environment with a name specific to the
branch.
So now, every branch:
- Gets its own environment.
- Is deployed to its own unique location, with the added benefit of:
- Having a [history of deployments](#view-the-deployment-history).
- Being able to [roll back changes](#retry-or-roll-back-a-deployment) if needed.
For more information, see [Using the environment URL](#using-the-environment-url).
### Protected environments
## Protected environments
Environments can be "protected", restricting access to them.
@ -538,36 +308,16 @@ For more information, see [Protected environments](protected_environments.md).
Once environments are configured, GitLab provides many features for working with them,
as documented below.
### View environments and deployments
### Environment rollback
Prerequisites:
When you roll back a deployment on a specific commit,
a _new_ deployment is created. This deployment has its own unique job ID.
It points to the commit you're rolling back to.
- You must have a minimum of [Reporter permission](../../user/permissions.md#project-members-permissions).
For the rollback to succeed, the deployment process must be defined in
the job's `script`.
To view a list of environments and deployment statuses:
- Go to the project's **Operations > Environments** page.
The **Environments** page shows the latest deployments.
- An environment can have multiple deployments. Some deployments may not be listed on the page.
- Only deploys that happen after your `.gitlab-ci.yml` is properly configured
show up in the **Environment** and **Last deployment** lists.
### View the deployment history
GitLab tracks your deployments, so you:
- Always know what is currently deployed on your servers.
- Have the full history of your deployments for every environment.
- Go to the project's **Operations > Environments** page.
![Deployments](../img/deployments_view.png)
This view is similar to the **Environments** page, but all deployments are shown.
### Retry or roll back a deployment
#### Retry or roll back a deployment
If there is a problem with a deployment, you can retry it or roll it back.
@ -575,32 +325,23 @@ To retry or rollback a deployment:
1. Go to the project's **Operations > Environments**.
1. Select the environment.
1. In the deployment history list for the environment:
- To retry a deployment, select **Retry**.
- to roll back to a deployment, next to a previously successful deployment, select **Rollback**.
1. To the right of the deployment name:
- To retry a deployment, select **Re-deploy to environment**.
- To roll back to a deployment, next to a previously successful deployment, select **Rollback environment**.
#### What to expect with a rollback
Pressing the **Rollback** button on a specific commit triggers a _new_ deployment with its own
unique job ID. This new deployment points to the commit you're
rolling back to.
Note that the defined deployment process in the job's `script` determines whether the rollback
succeeds.
### Using the environment URL
### Environment URL
The [environment URL](../yaml/README.md#environmenturl) is exposed in a few
places within GitLab:
- In a merge request widget as a link:
- In a merge request as a link:
![Environment URL in merge request](../img/environments_mr_review_app.png)
- In the Environments view as a button:
![Environment URL in environments](../img/environments_available_13_7.png)
![Environment URL in environments](../img/environments_available_13_10.png)
- In the Deployments view as a button:
![Environment URL in deployments](../img/deployments_view.png)
You can see this information in a merge request itself if:
You can see this information in a merge request if:
- The merge request is eventually merged to the default branch (usually `master`).
- That branch also deploys to an environment (for example, `staging` or `production`).
@ -616,19 +357,16 @@ from source files to public pages in the environment set for Review Apps.
### Stopping an environment
Stopping an environment:
When you stop an environment:
- Moves it from the list of **Available** environments to the list of **Stopped**
- It moves from the list of **Available** environments to the list of **Stopped**
environments on the [**Environments** page](#view-environments-and-deployments).
- Executes an [`on_stop` action](../yaml/README.md#environmenton_stop), if defined.
- An [`on_stop` action](../yaml/README.md#environmenton_stop), if defined, is executed.
This is often used when multiple developers are working on a project at the same time,
each of them pushing to their own branches, causing many dynamic environments to be created.
Starting with GitLab 8.14, dynamic environments stop automatically when their associated branch is
Dynamic environments stop automatically when their associated branch is
deleted.
#### Automatically stopping an environment
#### Stop an environment when a branch is deleted
Environments can be stopped automatically using special configuration.
@ -678,7 +416,7 @@ possible to trigger `action: stop` to stop the environment automatically.
You can read more in the [`.gitlab-ci.yml` reference](../yaml/README.md#environmenton_stop).
#### Environments auto-stop
#### Stop an environment after a certain time period
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/20956) in GitLab 12.8.
@ -763,7 +501,7 @@ environment name to see its details and **Delete** it from there.
You can also delete environments by viewing the details for a
stopped environment:
1. Navigate to **Operations > Environments**.
1. Go to the project's **Operations > Environments** page.
1. Click on the name of an environment within the **Stopped** environments list.
1. Click on the **Delete** button that appears at the top for all stopped environments.
1. Finally, confirm your chosen environment in the modal that appears to delete it.
@ -776,7 +514,7 @@ Environments can also be deleted by using the [Environments API](../../api/envir
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/208655) in GitLab 13.2.
By default, GitLab creates a [deployment](#view-the-deployment-history) every time a
By default, GitLab creates a deployment every time a
build with the specified environment runs. Newer deployments can also
[cancel older ones](deployment_safety.md#skip-outdated-deployment-jobs).
@ -801,15 +539,15 @@ build:
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/7015) in GitLab 8.14.
As documented in [Configuring dynamic environments](#configuring-dynamic-environments), you can
As documented in [Create a dynamic environment](#create-a-dynamic-environment), you can
prepend environment name with a word, followed by a `/`, and finally the branch
name, which is automatically defined by the `CI_COMMIT_REF_NAME` predefined CI/CD variable.
In short, environments that are named like `type/foo` are all presented under the same
group, named `type`.
In our [minimal example](#example-configuration), we named the environments `review/$CI_COMMIT_REF_NAME`
where `$CI_COMMIT_REF_NAME` is the branch name. Here is a snippet of the example:
If you name the environments `review/$CI_COMMIT_REF_NAME`
where `$CI_COMMIT_REF_NAME` is the branch name:
```yaml
deploy_review:
@ -820,7 +558,7 @@ deploy_review:
name: review/$CI_COMMIT_REF_NAME
```
In this case, if you visit the **Environments** page and the branches
If you visit the **Environments** page and the branches
exist, you should see something like:
![Environment groups](../img/environments_dynamic_groups.png)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

View file

@ -103,7 +103,7 @@ Feature.enable(:ci_config_visualization_tab)
## View expanded configuration
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/246801) in GitLab 13.9.
> - It is [deployed behind a feature flag](../../user/feature_flags.md), disabled by default.
> - It is [deployed behind a feature flag](../../user/feature_flags.md), enabled by default.
> - To use it in GitLab self-managed instances, ask a GitLab administrator to [enable it](#enable-or-disable-expanded-configuration). **(FREE SELF)**
To view the fully expanded CI/CD configuration as one combined file, go to the
@ -118,20 +118,20 @@ where:
### Enable or disable expanded configuration **(FREE SELF)**
Expanded CI/CD configuration is under development and not ready for production use.
It is deployed behind a feature flag that is **disabled by default**.
It is deployed behind a feature flag that is **enabled by default**.
[GitLab administrators with access to the GitLab Rails console](../../administration/feature_flags.md)
can opt to enable it.
To enable it:
```ruby
Feature.enable(:ci_config_visualization_tab)
```
To disable it:
```ruby
Feature.disable(:ci_config_visualization_tab)
Feature.disable(:ci_config_merged_tab)
```
To enable it:
```ruby
Feature.enable(:ci_config_merged_tab)
```
## Commit changes to CI configuration

View file

@ -96,7 +96,7 @@ This table lists the refspecs injected for each pipeline type:
The refs `refs/heads/<name>` and `refs/tags/<name>` exist in your
project repository. GitLab generates the special ref `refs/pipelines/<id>` during a
running pipeline job. This ref can be created even after the associated branch or tag has been
deleted. It's therefore useful in some features such as [automatically stopping an environment](../environments/index.md#automatically-stopping-an-environment),
deleted. It's therefore useful in some features such as [automatically stopping an environment](../environments/index.md#stopping-an-environment),
and [merge trains](../merge_request_pipelines/pipelines_for_merged_results/merge_trains/index.md)
that might run pipelines after branch deletion.
@ -208,7 +208,7 @@ You can do this straight from the pipeline graph. Just click the play button
to execute that particular job.
For example, your pipeline might start automatically, but it requires manual action to
[deploy to production](../environments/index.md#configuring-manual-deployments). In the example below, the `production`
[deploy to production](../environments/index.md#configure-manual-deployments). In the example below, the `production`
stage has a job with a manual action.
![Pipelines example](img/pipelines.png)

View file

@ -56,7 +56,7 @@ After adding Review Apps to your workflow, you follow the branched Git flow. Tha
## Configuring Review Apps
Review Apps are built on [dynamic environments](../environments/index.md#configuring-dynamic-environments), which allow you to dynamically create a new environment for each branch.
Review Apps are built on [dynamic environments](../environments/index.md#create-a-dynamic-environment), which allow you to dynamically create a new environment for each branch.
The process of configuring Review Apps is as follows:
@ -89,7 +89,7 @@ you can copy and paste into `.gitlab-ci.yml` as a starting point. To do so:
## Review Apps auto-stop
See how to [configure Review Apps environments to expire and auto-stop](../environments/index.md#environments-auto-stop)
See how to [configure Review Apps environments to expire and auto-stop](../environments/index.md#stop-an-environment-after-a-certain-time-period)
after a given period of time.
## Review Apps examples

View file

@ -2322,7 +2322,7 @@ started by a user. You might want to use manual jobs for things like deploying t
To make a job manual, add `when: manual` to its configuration.
Manual jobs can be started from the pipeline, job, [environment](../environments/index.md#configuring-manual-deployments),
Manual jobs can be started from the pipeline, job, [environment](../environments/index.md#configure-manual-deployments),
and deployment views.
Manual jobs can be either optional or blocking:
@ -2562,7 +2562,7 @@ it is set to `manual`, so it needs a [manual action](#whenmanual) from
the GitLab UI to run.
Also in the example, `GIT_STRATEGY` is set to `none`. If the
`stop_review_app` job is [automatically triggered](../environments/index.md#automatically-stopping-an-environment),
`stop_review_app` job is [automatically triggered](../environments/index.md#stopping-an-environment),
the runner wont try to check out the code after the branch is deleted.
The example also overwrites global variables. If your `stop` `environment` job depends
@ -2608,7 +2608,7 @@ When the environment for `review_app` is created, the environment's lifetime is
Every time the review app is deployed, that lifetime is also reset to `1 day`.
For more information, see
[the environments auto-stop documentation](../environments/index.md#environments-auto-stop)
[the environments auto-stop documentation](../environments/index.md#stop-an-environment-after-a-certain-time-period)
#### `environment:kubernetes`
@ -2634,7 +2634,7 @@ environment, using the `production`
[Kubernetes namespace](https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/).
For more information, see
[Available settings for `kubernetes`](../environments/index.md#configuring-kubernetes-deployments).
[Available settings for `kubernetes`](../environments/index.md#configure-kubernetes-deployments).
NOTE:
Kubernetes configuration is not supported for Kubernetes clusters

View file

@ -109,7 +109,7 @@ subgraph "CNG-mirror pipeline"
### Auto-stopping of Review Apps
Review Apps are automatically stopped 2 days after the last deployment thanks to
the [Environment auto-stop](../../ci/environments/index.md#environments-auto-stop) feature.
the [Environment auto-stop](../../ci/environments/index.md#stop-an-environment-after-a-certain-time-period) feature.
If you need your Review App to stay up for a longer time, you can
[pin its environment](../../ci/environments/index.md#auto-stop-example) or retry the

View file

@ -204,7 +204,7 @@ into your project and edit it as needed.
For clusters not managed by GitLab, you can customize the namespace in
`.gitlab-ci.yml` by specifying
[`environment:kubernetes:namespace`](../../ci/environments/index.md#configuring-kubernetes-deployments).
[`environment:kubernetes:namespace`](../../ci/environments/index.md#configure-kubernetes-deployments).
For example, the following configuration overrides the namespace used for
`production` deployments:

View file

@ -312,7 +312,7 @@ following command in your deployment job script, for Kubernetes to access the re
The Kubernetes cluster integration exposes these
[deployment variables](../../../ci/variables/README.md#deployment-variables) in the
GitLab CI/CD build environment to deployment jobs. Deployment jobs have
[defined a target environment](../../../ci/environments/index.md#defining-environments).
[defined a target environment](../../../ci/environments/index.md).
| Deployment Variable | Description |
|----------------------------|-------------|
@ -345,7 +345,7 @@ You can customize the deployment namespace in a few ways:
- For **non-managed** clusters, the auto-generated namespace is set in the `KUBECONFIG`,
but the user is responsible for ensuring its existence. You can fully customize
this value using
[`environment:kubernetes:namespace`](../../../ci/environments/index.md#configuring-kubernetes-deployments)
[`environment:kubernetes:namespace`](../../../ci/environments/index.md#configure-kubernetes-deployments)
in `.gitlab-ci.yml`.
When you customize the namespace, existing environments remain linked to their current
@ -432,7 +432,7 @@ Reasons for failure include:
- The token you gave GitLab does not have [`cluster-admin`](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#user-facing-roles)
privileges required by GitLab.
- Missing `KUBECONFIG` or `KUBE_TOKEN` deployment variables. To be passed to your job, they must have a matching
[`environment:name`](../../../ci/environments/index.md#defining-environments). If your job has no
[`environment:name`](../../../ci/environments/index.md). If your job has no
`environment:name` set, the Kubernetes credentials are not passed to it.
NOTE:

View file

@ -75,7 +75,7 @@ specific environment, there are a lot of use cases. To name a few:
To display the Deploy Boards for a specific [environment](../../ci/environments/index.md) you should:
1. Have [defined an environment](../../ci/environments/index.md#defining-environments) with a deploy stage.
1. Have [defined an environment](../../ci/environments/index.md) with a deploy stage.
1. Have a Kubernetes cluster up and running.

View file

@ -3,8 +3,7 @@
module API
module Entities
class UserSafe < Grape::Entity
expose :id, :username
expose :name, unless: ->(user) { user.project_bot? && !options[:current_user].admin?}
expose :id, :name, :username
end
end
end

View file

@ -9,8 +9,6 @@ module Gitlab
class ProjectPipelineStatus
include Gitlab::Utils::StrongMemoize
ALL_PIPELINES_STATUS_PATTERN = 'projects/*/pipeline_status'
attr_accessor :sha, :status, :ref, :project, :loaded
def self.load_for_project(project)

View file

@ -7,11 +7,14 @@ module Gitlab
class Item
include Gitlab::Utils::StrongMemoize
def initialize(key:, value:, public: true, file: false, masked: false)
attr_reader :raw
def initialize(key:, value:, public: true, file: false, masked: false, raw: false)
raise ArgumentError, "`#{key}` must be of type String or nil value, while it was: #{value.class}" unless
value.is_a?(String) || value.nil?
@variable = { key: key, value: value, public: public, file: file, masked: masked }
@raw = raw
end
def value
@ -28,6 +31,8 @@ module Gitlab
def depends_on
strong_memoize(:depends_on) do
next if raw
next unless ExpandVariables.possible_var_reference?(value)
value.scan(ExpandVariables::VARIABLES_REGEXP).map(&:first)

View file

@ -1,49 +0,0 @@
# frozen_string_literal: true
module Gitlab
module Cleanup
module Redis
class BatchDeleteByPattern
REDIS_CLEAR_BATCH_SIZE = 1000 # There seems to be no speedup when pushing beyond 1,000
REDIS_SCAN_START_STOP = '0'.freeze # Magic value, see http://redis.io/commands/scan
attr_reader :patterns
def initialize(patterns)
raise ArgumentError.new('Argument should be an Array of patterns') unless patterns.is_a?(Array)
@patterns = patterns
end
def execute
return if patterns.blank?
batch_delete_cache_keys
end
private
def batch_delete_cache_keys
Gitlab::Redis::Cache.with do |redis|
patterns.each do |match|
cursor = REDIS_SCAN_START_STOP
loop do
cursor, keys = redis.scan(
cursor,
match: match,
count: REDIS_CLEAR_BATCH_SIZE
)
Gitlab::Instrumentation::RedisClusterValidator.allow_cross_slot_commands do
redis.del(*keys) if keys.any?
end
break if cursor == REDIS_SCAN_START_STOP
end
end
end
end
end
end
end
end

View file

@ -1,88 +0,0 @@
# frozen_string_literal: true
module Gitlab
module Cleanup
module Redis
class DescriptionTemplatesCacheKeysPatternBuilder
# project_ids - a list of project_ids for which to compute description templates cache keys or `:all` to compute
# a pattern that cover all description templates cache keys.
#
# Example
# * ::Gitlab::Cleanup::Redis::BatchDeleteDescriptionTemplates.new(:all).execute - to get 2
# patterns for all issue and merge request description templates cache keys.
#
# * ::Gitlab::Cleanup::Redis::BatchDeleteDescriptionTemplates.new([1,2,3,4]).execute - to get an array of
# patterns for each project's issue and merge request description templates cache keys.
def initialize(project_ids)
raise ArgumentError.new('project_ids can either be an array of project IDs or :all') if project_ids != :all && !project_ids.is_a?(Array)
@project_ids = parse_project_ids(project_ids)
end
def execute
case project_ids
when :all
all_instance_patterns
else
project_patterns
end
end
private
attr_reader :project_ids
def parse_project_ids(project_ids)
return project_ids if project_ids == :all
project_ids.map { |id| Integer(id) }
rescue ArgumentError
raise ArgumentError.new('Invalid Project ID. Please ensure all passed in project ids values are valid integer project ids.')
end
def project_patterns
cache_key_patterns = []
Project.id_in(project_ids).each_batch do |batch|
cache_key_patterns << batch.map do |pr|
next unless pr.repository.exists?
cache = Gitlab::RepositoryCache.new(pr.repository)
[repo_issue_templates_cache_key(cache), repo_merge_request_templates_cache_key(cache)]
end
end
cache_key_patterns.flatten.compact
end
def all_instance_patterns
[all_issue_templates_cache_key, all_merge_request_templates_cache_key]
end
def issue_templates_cache_key
Repository::METHOD_CACHES_FOR_FILE_TYPES[:issue_template]
end
def merge_request_templates_cache_key
Repository::METHOD_CACHES_FOR_FILE_TYPES[:merge_request_template]
end
def all_issue_templates_cache_key
"#{Gitlab::Redis::Cache::CACHE_NAMESPACE}:#{issue_templates_cache_key}:*"
end
def all_merge_request_templates_cache_key
"#{Gitlab::Redis::Cache::CACHE_NAMESPACE}:#{merge_request_templates_cache_key}:*"
end
def repo_issue_templates_cache_key(cache)
"#{Gitlab::Redis::Cache::CACHE_NAMESPACE}:#{cache.cache_key(issue_templates_cache_key)}"
end
def repo_merge_request_templates_cache_key(cache)
"#{Gitlab::Redis::Cache::CACHE_NAMESPACE}:#{cache.cache_key(merge_request_templates_cache_key)}"
end
end
end
end
end

View file

@ -2,22 +2,32 @@
namespace :cache do
namespace :clear do
REDIS_CLEAR_BATCH_SIZE = 1000 # There seems to be no speedup when pushing beyond 1,000
REDIS_SCAN_START_STOP = '0'.freeze # Magic value, see http://redis.io/commands/scan
desc "GitLab | Cache | Clear redis cache"
task redis: :environment do
cache_key_patterns = %W[
#{Gitlab::Redis::Cache::CACHE_NAMESPACE}*
#{Gitlab::Cache::Ci::ProjectPipelineStatus::ALL_PIPELINES_STATUS_PATTERN}
]
Gitlab::Redis::Cache.with do |redis|
cache_key_pattern = %W[#{Gitlab::Redis::Cache::CACHE_NAMESPACE}*
projects/*/pipeline_status]
::Gitlab::Cleanup::Redis::BatchDeleteByPattern.new(cache_key_patterns).execute
cache_key_pattern.each do |match|
cursor = REDIS_SCAN_START_STOP
loop do
cursor, keys = redis.scan(
cursor,
match: match,
count: REDIS_CLEAR_BATCH_SIZE
)
Gitlab::Instrumentation::RedisClusterValidator.allow_cross_slot_commands do
redis.del(*keys) if keys.any?
end
desc "GitLab | Cache | Clear description templates redis cache"
task description_templates: :environment do
project_ids = Array(ENV['project_ids']&.split(',')).map!(&:squish)
cache_key_patterns = ::Gitlab::Cleanup::Redis::DescriptionTemplatesCacheKeysPatternBuilder.new(project_ids).execute
::Gitlab::Cleanup::Redis::BatchDeleteByPattern.new(cache_key_patterns).execute
break if cursor == REDIS_SCAN_START_STOP
end
end
end
end
task all: [:redis]

View file

@ -62,6 +62,7 @@ module DeprecationToolkitEnv
carrierwave-1.3.1/lib/carrierwave/sanitized_file.rb
activerecord-6.0.3.4/lib/active_record/relation.rb
selenium-webdriver-3.142.7/lib/selenium/webdriver/firefox/driver.rb
asciidoctor-2.0.12/lib/asciidoctor/extensions.rb
]
end

View file

@ -475,7 +475,7 @@ FactoryBot.define do
trait :license_scanning do
options do
{
artifacts: { reports: { license_management: 'gl-license-scanning-report.json' } }
artifacts: { reports: { license_scanning: 'gl-license-scanning-report.json' } }
}
end
end

File diff suppressed because it is too large Load diff

View file

@ -127,7 +127,7 @@ RSpec.describe 'Project members list' do
it 'does not show form used to change roles and "Expiration date" or the remove user button' do
visit_members_page
page.within find_username_row(project_bot) do
page.within find_member_row(project_bot) do
expect(page).not_to have_button('Maintainer')
expect(page).to have_field('Expiration date', disabled: true)
expect(page).not_to have_button('Remove member')

View file

@ -15,10 +15,9 @@ RSpec.describe Security::LicenseComplianceJobsFinder do
let!(:container_scanning_build) { create(:ci_build, :container_scanning, pipeline: pipeline) }
let!(:dast_build) { create(:ci_build, :dast, pipeline: pipeline) }
let!(:license_scanning_build) { create(:ci_build, :license_scanning, pipeline: pipeline) }
let!(:license_management_build) { create(:ci_build, :license_management, pipeline: pipeline) }
it 'returns only the license_scanning jobs' do
is_expected.to contain_exactly(license_scanning_build, license_management_build)
it 'returns only the license_scanning job' do
is_expected.to contain_exactly(license_scanning_build)
end
end
end

View file

@ -6,6 +6,18 @@ RSpec.describe Resolvers::NamespaceProjectsResolver do
include GraphqlHelpers
let(:current_user) { create(:user) }
let(:include_subgroups) { true }
let(:sort) { nil }
let(:search) { nil }
let(:ids) { nil }
let(:args) do
{
include_subgroups: include_subgroups,
sort: sort,
search: search,
ids: ids
}
end
context "with a group" do
let(:group) { create(:group) }
@ -27,7 +39,7 @@ RSpec.describe Resolvers::NamespaceProjectsResolver do
end
it 'finds all projects including the subgroups' do
expect(resolve_projects(include_subgroups: true, sort: nil, search: nil)).to contain_exactly(project1, project2, nested_project)
expect(resolve_projects(args)).to contain_exactly(project1, project2, nested_project)
end
context 'with an user namespace' do
@ -38,7 +50,7 @@ RSpec.describe Resolvers::NamespaceProjectsResolver do
end
it 'finds all projects including the subgroups' do
expect(resolve_projects(include_subgroups: true, sort: nil, search: nil)).to contain_exactly(project1, project2)
expect(resolve_projects(args)).to contain_exactly(project1, project2)
end
end
end
@ -48,6 +60,9 @@ RSpec.describe Resolvers::NamespaceProjectsResolver do
let(:project_2) { create(:project, name: 'Test Project', path: 'test-project', namespace: namespace) }
let(:project_3) { create(:project, name: 'Test', path: 'test', namespace: namespace) }
let(:sort) { :similarity }
let(:search) { 'test' }
before do
project_1.add_developer(current_user)
project_2.add_developer(current_user)
@ -55,7 +70,7 @@ RSpec.describe Resolvers::NamespaceProjectsResolver do
end
it 'returns projects ordered by similarity to the search input' do
projects = resolve_projects(include_subgroups: true, sort: :similarity, search: 'test')
projects = resolve_projects(args)
project_names = projects.map { |proj| proj['name'] }
expect(project_names.first).to eq('Test')
@ -63,15 +78,17 @@ RSpec.describe Resolvers::NamespaceProjectsResolver do
end
it 'filters out result that do not match the search input' do
projects = resolve_projects(include_subgroups: true, sort: :similarity, search: 'test')
projects = resolve_projects(args)
project_names = projects.map { |proj| proj['name'] }
expect(project_names).not_to include('Project')
end
context 'when `search` parameter is not given' do
let(:search) { nil }
it 'returns projects not ordered by similarity' do
projects = resolve_projects(include_subgroups: true, sort: :similarity, search: nil)
projects = resolve_projects(args)
project_names = projects.map { |proj| proj['name'] }
expect(project_names.first).not_to eq('Test')
@ -79,14 +96,40 @@ RSpec.describe Resolvers::NamespaceProjectsResolver do
end
context 'when only search term is given' do
let(:sort) { nil }
let(:search) { 'test' }
it 'filters out result that do not match the search input, but does not sort them' do
projects = resolve_projects(include_subgroups: true, sort: :nil, search: 'test')
projects = resolve_projects(args)
project_names = projects.map { |proj| proj['name'] }
expect(project_names).to contain_exactly('Test', 'Test Project')
end
end
end
context 'ids filtering' do
subject(:projects) { resolve_projects(args) }
let(:include_subgroups) { false }
let(:project_3) { create(:project, name: 'Project', path: 'project', namespace: namespace) }
context 'when ids is provided' do
let(:ids) { [project_3.to_global_id.to_s] }
it 'returns matching project' do
expect(projects).to contain_exactly(project_3)
end
end
context 'when ids is nil' do
let(:ids) { nil }
it 'returns all projects' do
expect(projects).to contain_exactly(project1, project2, project_3)
end
end
end
end
context "when passing a non existent, batch loaded namespace" do
@ -108,7 +151,7 @@ RSpec.describe Resolvers::NamespaceProjectsResolver do
expect(field.to_graphql.complexity.call({}, { include_subgroups: true }, 1)).to eq 24
end
def resolve_projects(args = { include_subgroups: false, sort: nil, search: nil }, context = { current_user: current_user })
def resolve_projects(args = { include_subgroups: false, sort: nil, search: nil, ids: nil }, context = { current_user: current_user })
resolve(described_class, obj: namespace, args: args, ctx: context)
end
end

View file

@ -35,22 +35,4 @@ RSpec.describe API::Entities::User do
expect(subject[:bot]).to eq(true)
end
end
context 'with project bot user' do
let(:user) { create(:user, :project_bot) }
context 'when the requester is not an admin' do
it 'does not expose project bot user name' do
expect(subject).not_to include(:name)
end
end
context 'when the requester is an admin' do
let(:current_user) { create(:user, :admin) }
it 'exposes project bot user name' do
expect(subject).to include(:name)
end
end
end
end

View file

@ -92,6 +92,10 @@ RSpec.describe Gitlab::Ci::Variables::Collection::Item do
variable: { key: 'VAR', value: 'something_${VAR2}_$VAR3' },
expected_depends_on: %w(VAR2 VAR3)
},
"complex expansion in raw variable": {
variable: { key: 'VAR', value: 'something_${VAR2}_$VAR3', raw: true },
expected_depends_on: nil
},
"complex expansions for Windows": {
variable: { key: 'variable3', value: 'key%variable%%variable2%' },
expected_depends_on: %w(variable variable2)
@ -156,6 +160,26 @@ RSpec.describe Gitlab::Ci::Variables::Collection::Item do
end
end
describe '#raw' do
it 'returns false when :raw is not specified' do
item = described_class.new(**variable)
expect(item.raw).to eq false
end
context 'when :raw is specified as true' do
let(:variable) do
{ key: variable_key, value: variable_value, public: true, masked: false, raw: true }
end
it 'returns true' do
item = described_class.new(**variable)
expect(item.raw).to eq true
end
end
end
describe '#to_runner_variable' do
context 'when variable is not a file-related' do
it 'returns a runner-compatible hash representation' do
@ -185,5 +209,19 @@ RSpec.describe Gitlab::Ci::Variables::Collection::Item do
expect(runner_variable.depends_on).to eq(%w(CI_VAR_2 CI_VAR_3))
end
end
context 'when assigned the raw attribute' do
it 'retains a true raw attribute' do
runner_variable = described_class.new(key: 'CI_VAR', value: '123', raw: true)
expect(runner_variable).to eq(key: 'CI_VAR', value: '123', public: true, masked: false, raw: true)
end
it 'does not retain a false raw attribute' do
runner_variable = described_class.new(key: 'CI_VAR', value: '123', raw: false)
expect(runner_variable).to eq(key: 'CI_VAR', value: '123', public: true, masked: false)
end
end
end
end

View file

@ -76,6 +76,13 @@ RSpec.describe Gitlab::Ci::Variables::Collection::Sort do
{ key: 'variable2', value: '$variable3' },
{ key: 'variable3', value: 'key$variable$variable2' }
]
},
"array with raw variable": {
variables: [
{ key: 'variable', value: '$variable2' },
{ key: 'variable2', value: '$variable3' },
{ key: 'variable3', value: 'key$variable$variable2', raw: true }
]
}
}
end
@ -128,6 +135,14 @@ RSpec.describe Gitlab::Ci::Variables::Collection::Sort do
{ key: 'variable3', value: 'key$variable$variable2' }
],
validation_result: 'circular variable reference detected: ["variable", "variable2", "variable3"]'
},
"array with raw variable": {
variables: [
{ key: 'variable', value: '$variable2' },
{ key: 'variable2', value: '$variable3' },
{ key: 'variable3', value: 'key$variable$variable2', raw: true }
],
validation_result: nil
}
}
end
@ -271,6 +286,22 @@ RSpec.describe Gitlab::Ci::Variables::Collection::Sort do
{ key: 'variable', value: '$variable2' }
],
result: %w[variable2 variable3 variable]
},
"raw variable does not get resolved": {
variables: [
{ key: 'variable', value: '$variable2' },
{ key: 'variable2', value: '$variable3' },
{ key: 'variable3', value: 'key$variable$variable2', raw: true }
],
result: %w[variable3 variable2 variable]
},
"variable containing escaped variable reference": {
variables: [
{ key: 'variable_c', value: '$variable_b' },
{ key: 'variable_b', value: '$$variable_a' },
{ key: 'variable_a', value: 'value' }
],
result: %w[variable_a variable_b variable_c]
}
}
end

View file

@ -1,91 +0,0 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::Cleanup::Redis::BatchDeleteByPattern, :clean_gitlab_redis_cache do
subject { described_class.new(patterns) }
describe 'execute' do
context 'when no patterns are passed' do
before do
expect(Gitlab::Redis::Cache).not_to receive(:with)
end
context 'with nil patterns' do
let(:patterns) { nil }
specify { expect { subject }.to raise_error(ArgumentError, 'Argument should be an Array of patterns') }
end
context 'with empty array patterns' do
let(:patterns) { [] }
specify { subject.execute }
end
end
context 'with patterns' do
context 'when key is not found' do
let(:patterns) { ['key'] }
before do
expect_any_instance_of(Redis).not_to receive(:del) # rubocop:disable RSpec/AnyInstanceOf
end
specify { subject.execute }
end
context 'with cache data' do
let(:cache_keys) { %w[key-test1 key-test2 key-test3 key-test4] }
before do
stub_const("#{described_class}::REDIS_CLEAR_BATCH_SIZE", 2)
write_to_cache
end
context 'with one key' do
let(:patterns) { ['key-test1'] }
it 'deletes the key' do
expect_any_instance_of(Redis).to receive(:del).with(patterns.first).once # rubocop:disable RSpec/AnyInstanceOf
subject.execute
end
end
context 'with many keys' do
let(:patterns) { %w[key-test1 key-test2] }
it 'deletes keys for each pattern separatelly' do
expect_any_instance_of(Redis).to receive(:del).with(patterns.first).once # rubocop:disable RSpec/AnyInstanceOf
expect_any_instance_of(Redis).to receive(:del).with(patterns.last).once # rubocop:disable RSpec/AnyInstanceOf
subject.execute
end
end
context 'with cache_keys over batch size' do
let(:patterns) { %w[key-test*] }
it 'deletes matched keys in batches' do
# redis scan returns the values in random order so just checking it is being called twice meaning
# scan returned results in 2 batches, which is what we expect
key_like = start_with('key-test')
expect_any_instance_of(Redis).to receive(:del).with(key_like, key_like).twice # rubocop:disable RSpec/AnyInstanceOf
subject.execute
end
end
end
end
end
end
def write_to_cache
Gitlab::Redis::Cache.with do |redis|
cache_keys.each_with_index do |cache_key, index|
redis.set(cache_key, index)
end
end
end

View file

@ -1,94 +0,0 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::Cleanup::Redis::DescriptionTemplatesCacheKeysPatternBuilder, :clean_gitlab_redis_cache do
subject { described_class.new(project_ids).execute }
describe 'execute' do
context 'when build pattern for all description templates' do
RSpec.shared_examples 'all issue and merge request templates pattern' do
it 'builds pattern to remove all issue and merge request templates keys' do
expect(subject.count).to eq(2)
expect(subject).to match_array(%W[
#{Gitlab::Redis::Cache::CACHE_NAMESPACE}:issue_template_names_hash:*
#{Gitlab::Redis::Cache::CACHE_NAMESPACE}:merge_request_template_names_hash:*
])
end
end
context 'with project_ids == :all' do
let(:project_ids) { :all }
it_behaves_like 'all issue and merge request templates pattern'
end
end
context 'with project_ids' do
let_it_be(:project1) { create(:project, :repository) }
let_it_be(:project2) { create(:project, :repository) }
context 'with nil project_ids' do
let(:project_ids) { nil }
specify { expect { subject }.to raise_error(ArgumentError, 'project_ids can either be an array of project IDs or :all') }
end
context 'with project_ids as string' do
let(:project_ids) { '1' }
specify { expect { subject }.to raise_error(ArgumentError, 'project_ids can either be an array of project IDs or :all') }
end
context 'with invalid project_ids as array of strings' do
let(:project_ids) { %w[a b] }
specify { expect { subject }.to raise_error(ArgumentError, 'Invalid Project ID. Please ensure all passed in project ids values are valid integer project ids.') }
end
context 'with non existent project id' do
let(:project_ids) { [non_existing_record_id] }
it 'no patterns are built' do
expect(subject.count).to eq(0)
end
end
context 'with one project_id' do
let(:project_ids) { [project1.id] }
it 'builds patterns for the project' do
expect(subject.count).to eq(2)
expect(subject).to match_array(%W[
#{Gitlab::Redis::Cache::CACHE_NAMESPACE}:issue_template_names_hash:#{project1.full_path}:#{project1.id}
#{Gitlab::Redis::Cache::CACHE_NAMESPACE}:merge_request_template_names_hash:#{project1.full_path}:#{project1.id}
])
end
end
context 'with many project_ids' do
let(:project_ids) { [project1.id, project2.id] }
RSpec.shared_examples 'builds patterns for the given projects' do
it 'builds patterns for the given projects' do
expect(subject.count).to eq(4)
expect(subject).to match_array(%W[
#{Gitlab::Redis::Cache::CACHE_NAMESPACE}:issue_template_names_hash:#{project1.full_path}:#{project1.id}
#{Gitlab::Redis::Cache::CACHE_NAMESPACE}:merge_request_template_names_hash:#{project1.full_path}:#{project1.id}
#{Gitlab::Redis::Cache::CACHE_NAMESPACE}:issue_template_names_hash:#{project2.full_path}:#{project2.id}
#{Gitlab::Redis::Cache::CACHE_NAMESPACE}:merge_request_template_names_hash:#{project2.full_path}:#{project2.id}
])
end
end
it_behaves_like 'builds patterns for the given projects'
context 'with project_ids as string' do
let(:project_ids) { [project1.id.to_s, project2.id.to_s] }
it_behaves_like 'builds patterns for the given projects'
end
end
end
end
end

View file

@ -152,9 +152,13 @@ RSpec.describe Users::RefreshAuthorizedProjectsService do
expect(Gitlab::AppJsonLogger).to(
receive(:info)
.with(event: 'authorized_projects_refresh',
user_id: user.id,
'authorized_projects_refresh.source': source,
'authorized_projects_refresh.rows_deleted': 0,
'authorized_projects_refresh.rows_added': 1))
'authorized_projects_refresh.rows_deleted_count': 0,
'authorized_projects_refresh.rows_added_count': 1,
'authorized_projects_refresh.rows_deleted_slice': [],
'authorized_projects_refresh.rows_added_slice': [[user.id, project.id, Gitlab::Access::MAINTAINER]])
)
service.update_authorizations([], [[user.id, project.id, Gitlab::Access::MAINTAINER]])
end

View file

@ -41,10 +41,6 @@ module Spec
find_row(user.name)
end
def find_username_row(user)
find_row(user.username)
end
def find_invited_member_row(email)
find_row(email)
end

View file

@ -2,7 +2,7 @@
require 'rake_helper'
RSpec.describe 'clearing redis cache', :clean_gitlab_redis_cache do
RSpec.describe 'clearing redis cache' do
before do
Rake.application.rake_require 'tasks/cache'
end
@ -21,27 +21,4 @@ RSpec.describe 'clearing redis cache', :clean_gitlab_redis_cache do
expect { run_rake_task('cache:clear:redis') }.to change { pipeline_status.has_cache? }
end
end
describe 'invoking clear description templates cache rake task' do
using RSpec::Parameterized::TableSyntax
before do
stub_env('project_ids', project_ids) if project_ids
service = double(:service, execute: true)
expect(Gitlab::Cleanup::Redis::DescriptionTemplatesCacheKeysPatternBuilder).to receive(:new).with(expected_project_ids).and_return(service)
expect(Gitlab::Cleanup::Redis::BatchDeleteByPattern).to receive(:new).and_return(service)
end
where(:project_ids, :expected_project_ids) do
nil | [] # this acts as no argument is being passed
'1' | %w[1]
'1, 2, 3' | %w[1 2 3]
'1, 2, some-string, 3' | %w[1 2 some-string 3]
end
with_them do
specify { run_rake_task('cache:clear:description_templates') }
end
end
end