---
type: reference
---
# Pipeline Architecture
Pipelines are the fundamental building blocks for CI/CD in GitLab. This page documents
some of the important concepts related to them.
There are three main ways to structure your pipelines, each with their
own advantages. These methods can be mixed and matched if needed:
- [Basic](#basic-pipelines): Good for straightforward projects where all the configuration is in one easy to find place.
- [Directed Acylic Graph](#directed-acyclic-graph-pipelines): Good for large, complex projects that need efficient execution.
- [Child/Parent Pipelines](#child--parent-pipelines): Good for monorepos and projects with lots of independently defined components.
For more details about
any of the keywords used below, check out our [CI YAML reference](../yaml/) for details.
## Basic Pipelines
This is the simplest pipeline in GitLab. It will run everything in the build stage concurrently,
and once all of those finish, it will run everything in the test stage the same way, and so on.
It's not the most efficient, and if you have lots of steps it can grow quite complex, but it's
easier to maintain:
```mermaid
graph LR
subgraph deploy stage
deploy --> deploy_a
deploy --> deploy_b
end
subgraph test stage
test --> test_a
test --> test_b
end
subgraph build stage
build --> build_a
build --> build_b
end
build_a -.-> test
build_b -.-> test
test_a -.-> deploy
test_b -.-> deploy
```
Example basic `/.gitlab-ci.yml` pipeline configuration matching the diagram:
```yaml
stages:
- build
- test
- deploy
image: alpine
build_a:
stage: build
script:
- echo "This job builds something."
build_b:
stage: build
script:
- echo "This job builds something else."
test_a:
stage: test
script:
- echo "This job tests something. It will only run when all jobs in the"
- echo "build stage are complete."
test_b:
stage: test
script:
- echo "This job tests something else. It will only run when all jobs in the"
- echo "build stage are complete too. It will start at about the same time as test_a."
deploy_a:
stage: deploy
script:
- echo "This job deploys something. It will only run when all jobs in the"
- echo "test stage complete."
deploy_b:
stage: deploy
script:
- echo "This job deploys something else. It will only run when all jobs in the"
- echo "test stage complete. It will start at about the same time as deploy_a."
```
## Directed Acyclic Graph Pipelines
If efficiency is important to you and you want everything to run as quickly as possible,
you can use [Directed Acylic Graphs (DAG)](../directed_acyclic_graph/index.md). Use the
[`needs` keyword](../yaml/README.md#needs) to define dependency relationships between
your jobs. When GitLab knows the relationships between your jobs, it can run everything
as fast as possible, and even skips into subsequent stages when possible.
In the example below, if `build_a` and `test_a` are much faster than `build_b` and
`test_b`, GitLab will start `deploy_a` even if `build_b` is still running.
```mermaid
graph LR
subgraph Pipeline using DAG
build_a --> test_a --> deploy_a
build_b --> test_b --> deploy_b
end
```
Example DAG `/.gitlab-ci.yml` configuration matching the diagram:
```yaml
stages:
- build
- test
- deploy
image: alpine
build_a:
stage: build
script:
- echo "This job builds something quickly."
build_b:
stage: build
script:
- echo "This job builds something else slowly."
test_a:
stage: test
needs: build_a
script:
- echo "This test job will start as soon as build_a finishes."
- echo "It will not wait for build_b, or other jobs in the build stage, to finish."
test_b:
stage: test
needs: build_b
script:
- echo "This test job will start as soon as build_b finishes."
- echo "It will not wait for other jobs in the build stage to finish."
deploy_a:
stage: deploy
needs: test_a
script:
- echo "Since build_a and test_a run quickly, this deploy job can run much earlier."
- echo "It does not need to wait for build_b or test_b."
deploy_b:
stage: deploy
needs: test_b
script:
- echo "Since build_b and test_b run slowly, this deploy job will run much later."
```
## Child / Parent Pipelines
In the examples above, it's clear we've got two types of things that could be built independently.
This is an ideal case for using [Child / Parent Pipelines](../parent_child_pipelines.md)) via
the [`trigger` keyword](../yaml/README.md#trigger). It will separate out the configuration
into multiple files, keeping things very simple. You can also combine this with:
- The [`rules` keyword](../yaml/README.md#rules): For example, have the child pipelines triggered only
when there are changes to that area.
- The [`include` keyword](../yaml/README.md#include): Bring in common behaviors, ensuring
you are not repeating yourself.
- [DAG pipelines](#directed-acyclic-graph-pipelines) inside of child pipelines, achieving the benefits of both.
```mermaid
graph LR
subgraph Parent pipeline
trigger_a -.-> build_a
trigger_b -.-> build_b
subgraph child pipeline B
build_b --> test_b --> deploy_b
end
subgraph child pipeline A
build_a --> test_a --> deploy_a
end
end
```
Example `/.gitlab-ci.yml` configuration for the parent pipeline matching the diagram:
```yaml
stages:
- triggers
trigger_a:
stage: triggers
trigger:
include: a/.gitlab-ci.yml
rules:
- changes:
- a/*
trigger_b:
stage: triggers
trigger:
include: b/.gitlab-ci.yml
rules:
- changes:
- b/*
```
Example child `a` pipeline configuration, located in `/a/.gitlab-ci.yml`, making
use of the DAG `needs:` keyword:
```yaml
stages:
- build
- test
- deploy
image: alpine
build_a:
stage: build
script:
- echo "This job builds something."
test_a:
stage: test
needs: build_a
script:
- echo "This job tests something."
deploy_a:
stage: deploy
needs: test_a
script:
- echo "This job deploys something."
```
Example child `b` pipeline configuration, located in `/b/.gitlab-ci.yml`, making
use of the DAG `needs:` keyword:
```yaml
stages:
- build
- test
- deploy
image: alpine
build_b:
stage: build
script:
- echo "This job builds something else."
test_b:
stage: test
needs: build_b
script:
- echo "This job tests something else."
deploy_b:
stage: deploy
needs: test_b
script:
- echo "This job deploys something else."
```
It's also possible to set jobs to run before or after triggering child pipelines,
for example if you have common setup steps or a unified deployment at the end.
...@@ -17,6 +17,11 @@ NOTE: **Note:** ...@@ -17,6 +17,11 @@ NOTE: **Note:**
Coming over to GitLab from Jenkins? Check out our [reference](../jenkins/index.md) Coming over to GitLab from Jenkins? Check out our [reference](../jenkins/index.md)
for converting your pre-existing pipelines over to our format. for converting your pre-existing pipelines over to our format.
NOTE: **Note:**
There are a few different [basic pipeline architectures](../pipelines/pipeline_architectures.md)
that you can consider for use in your project. You may want to familiarize
yourself with these prior to getting started.
GitLab offers a [continuous integration](https://about.gitlab.com/stages-devops-lifecycle/continuous-integration/) service. For each commit or push to trigger your CI GitLab offers a [continuous integration](https://about.gitlab.com/stages-devops-lifecycle/continuous-integration/) service. For each commit or push to trigger your CI
[pipeline](../pipelines.md), you must: [pipeline](../pipelines.md), you must:
... ...
......
...@@ -17,12 +17,12 @@ First, in your `.gitlab-ci.yml` add: ...@@ -17,12 +17,12 @@ First, in your `.gitlab-ci.yml` add:
```yaml ```yaml
services: services:
- postgres:latest - postgres:12.2-alpine
variables: variables:
POSTGRES_DB: nice_marmot POSTGRES_DB: nice_marmot
POSTGRES_USER: runner POSTGRES_USER: runner
POSTGRES_PASSWORD: "" POSTGRES_PASSWORD: "runner-password"
``` ```
NOTE: **Note:** NOTE: **Note:**
...@@ -37,7 +37,7 @@ And then configure your application to use the database, for example: ...@@ -37,7 +37,7 @@ And then configure your application to use the database, for example:
```yaml ```yaml
Host: postgres Host: postgres
User: runner User: runner
Password: Password: runner-password
Database: nice_marmot Database: nice_marmot
``` ```
... ...
......
...@@ -7,7 +7,7 @@ check if a comment is still relevant and what needs to be done to address it. ...@@ -7,7 +7,7 @@ check if a comment is still relevant and what needs to be done to address it.
Examples: Examples:
```rb ```ruby
# Deprecated scope until code_owner column has been migrated to rule_type. # Deprecated scope until code_owner column has been migrated to rule_type.
# To be removed with https://gitlab.com/gitlab-org/gitlab/issues/11834. # To be removed with https://gitlab.com/gitlab-org/gitlab/issues/11834.
scope :code_owner, -> { where(code_owner: true).or(where(rule_type: :code_owner)) } scope :code_owner, -> { where(code_owner: true).or(where(rule_type: :code_owner)) }
... ...
......
...@@ -8,7 +8,7 @@ To use this type, add `limit: 2` to the migration that creates the column. ...@@ -8,7 +8,7 @@ To use this type, add `limit: 2` to the migration that creates the column.
Example: Example:
```rb ```ruby
def change def change
add_column :ci_job_artifacts, :file_format, :integer, limit: 2 add_column :ci_job_artifacts, :file_format, :integer, limit: 2
end end
... ...
......
...@@ -783,33 +783,64 @@ nicely on different mobile devices. ...@@ -783,33 +783,64 @@ nicely on different mobile devices.
- When providing a shell command and its output, prefix the shell command with `$` and - When providing a shell command and its output, prefix the shell command with `$` and
leave a blank line between the command and the output. leave a blank line between the command and the output.
- When providing a command without output, don't prefix the shell command with `$`. - When providing a command without output, don't prefix the shell command with `$`.
- If you need to include triple backticks inside a code block, use four backticks
for the codeblock fences instead of three.
- For regular code blocks, always use a highlighting class corresponding to the - For regular code blocks, always use a highlighting class corresponding to the
language for better readability. Examples: language for better readability. Examples:
~~~md ````markdown
```ruby ```ruby
Ruby code Ruby code
``` ```
```js ```javascript
JavaScript code JavaScript code
``` ```
```md ```markdown
[Markdown code example](example.md) [Markdown code example](example.md)
``` ```
```text ```plaintext
Code or text for which no specific highlighting class is available. Code or text for which no specific highlighting class is available.
``` ```
~~~ ````
- To display raw Markdown instead of rendered Markdown, you can use triple backticks Syntax highlighting is required for code blocks added to the GitLab documentation.
with `md`, like the `Markdown code` example above, unless you want to include triple Refer to the table below for the most common language classes, or check the
backticks in the code block as well. In that case, use triple tildes (`~~~`) instead. [complete list](https://github.com/rouge-ruby/rouge/wiki/List-of-supported-languages-and-lexers)
- [Syntax highlighting for code blocks](https://github.com/rouge-ruby/rouge/wiki/List-of-supported-languages-and-lexers) of language classes available.
is available for many languages. Use `shell` instead of `bash` or `sh` for shell output.
- For a complete reference on code blocks, check the [Kramdown guide](https://about.gitlab.com/handbook/product/technical-writing/markdown-guide/#code-blocks). | Preferred language tags | Language aliases and notes |
|-------------------------|------------------------------------------------------------------------------|
| `asciidoc` | |
| `dockerfile` | Alias: `docker`. |
| `elixir` | |
| `erb` | |
| `golang` | Alias: `go`. |
| `graphql` | |
| `haml` | |
| `html` | |
| `ini` | For some simple config files that are not in TOML format. |
| `javascript` | Alias `js`. |
| `json` | |
| `markdown` | Alias: `md`. |
| `mermaid` | |
| `nginx` | |
| `perl` | |
| `php` | |
| `plaintext` | Examples with no defined language, such as output from shell commands or API calls. If a codeblock has no language, it defaults to `plaintext`. Alias: `text`. |
| `prometheus` | Prometheus configuration examples. |
| `python` | |
| `ruby` | Alias: `rb`. |
| `shell` | Aliases: `bash` or `sh`. |
| `sql` | |
| `toml` | Runner configuration examples, and other toml formatted configuration files. |
| `typescript` | Alias: `ts`. |
| `xml` | |
| `yaml` | Alias: `yml`. |
For a complete reference on code blocks, check the [Kramdown guide](https://about.gitlab.com/handbook/product/technical-writing/markdown-guide/#code-blocks).
## GitLab SVG icons ## GitLab SVG icons
... ...
......
...@@ -240,13 +240,13 @@ Here are the steps to gate a new feature in Gitaly behind a feature flag. ...@@ -240,13 +240,13 @@ Here are the steps to gate a new feature in Gitaly behind a feature flag.
1. Create a package scoped flag name: 1. Create a package scoped flag name:
```go ```golang
var findAllTagsFeatureFlag = "go-find-all-tags" var findAllTagsFeatureFlag = "go-find-all-tags"
``` ```
1. Create a switch in the code using the `featureflag` package: 1. Create a switch in the code using the `featureflag` package:
```go ```golang
if featureflag.IsEnabled(ctx, findAllTagsFeatureFlag) { if featureflag.IsEnabled(ctx, findAllTagsFeatureFlag) {
// go implementation // go implementation
} else { } else {
...@@ -256,7 +256,7 @@ Here are the steps to gate a new feature in Gitaly behind a feature flag. ...@@ -256,7 +256,7 @@ Here are the steps to gate a new feature in Gitaly behind a feature flag.
1. Create Prometheus metrics: 1. Create Prometheus metrics:
```go ```golang
var findAllTagsRequests = prometheus.NewCounterVec( var findAllTagsRequests = prometheus.NewCounterVec(
prometheus.CounterOpts{ prometheus.CounterOpts{
Name: "gitaly_find_all_tags_requests_total", Name: "gitaly_find_all_tags_requests_total",
...@@ -280,7 +280,7 @@ Here are the steps to gate a new feature in Gitaly behind a feature flag. ...@@ -280,7 +280,7 @@ Here are the steps to gate a new feature in Gitaly behind a feature flag.
1. Set headers in tests: 1. Set headers in tests:
```go ```golang
import ( import (
"google.golang.org/grpc/metadata" "google.golang.org/grpc/metadata"
... ...
......
...@@ -195,7 +195,7 @@ When comparing expected and actual values in tests, use ...@@ -195,7 +195,7 @@ When comparing expected and actual values in tests, use
and others to improve readability when comparing structs, errors, and others to improve readability when comparing structs, errors,
large portions of text, or JSON documents: large portions of text, or JSON documents:
```go ```golang
type TestData struct { type TestData struct {
// ... // ...
} }
... ...
......
...@@ -918,7 +918,7 @@ instead of the default `ruby:latest`: ...@@ -918,7 +918,7 @@ instead of the default `ruby:latest`:
1. Set `AUTO_DEVOPS_BUILD_IMAGE_EXTRA_ARGS` to `--build-arg=RUBY_VERSION=alpine`. 1. Set `AUTO_DEVOPS_BUILD_IMAGE_EXTRA_ARGS` to `--build-arg=RUBY_VERSION=alpine`.
1. Add the following to a custom `Dockerfile`: 1. Add the following to a custom `Dockerfile`:
```docker ```dockerfile
ARG RUBY_VERSION=latest ARG RUBY_VERSION=latest
FROM ruby:$RUBY_VERSION FROM ruby:$RUBY_VERSION
...@@ -955,14 +955,14 @@ In projects: ...@@ -955,14 +955,14 @@ In projects:
1. Activate the experimental `Dockerfile` syntax by adding the following 1. Activate the experimental `Dockerfile` syntax by adding the following
to the top of the file: to the top of the file:
```docker ```dockerfile
# syntax = docker/dockerfile:experimental # syntax = docker/dockerfile:experimental
``` ```
1. To make secrets available in any `RUN $COMMAND` in the `Dockerfile`, mount 1. To make secrets available in any `RUN $COMMAND` in the `Dockerfile`, mount
the secret file and source it prior to running `$COMMAND`: the secret file and source it prior to running `$COMMAND`:
```docker ```dockerfile
RUN --mount=type=secret,id=auto-devops-build-secrets . /run/secrets/auto-devops-build-secrets && $COMMAND RUN --mount=type=secret,id=auto-devops-build-secrets . /run/secrets/auto-devops-build-secrets && $COMMAND
``` ```
... ...
......
...@@ -182,7 +182,7 @@ your cluster either using [Cloud Shell](https://cloud.google.com/shell/) or the ...@@ -182,7 +182,7 @@ your cluster either using [Cloud Shell](https://cloud.google.com/shell/) or the
This is done by running the following commands: This is done by running the following commands:
```bash ```shell
$ kubectl get pods -n gitlab-managed-apps | grep 'ingress-controller' $ kubectl get pods -n gitlab-managed-apps | grep 'ingress-controller'
ingress-nginx-ingress-controller-55f9cf6584-dxljn 2/2 Running ingress-nginx-ingress-controller-55f9cf6584-dxljn 2/2 Running
...@@ -192,7 +192,7 @@ your cluster either using [Cloud Shell](https://cloud.google.com/shell/) or the ...@@ -192,7 +192,7 @@ your cluster either using [Cloud Shell](https://cloud.google.com/shell/) or the
1. Verify the Rails application has been installed properly. 1. Verify the Rails application has been installed properly.
```bash ```shell
$ kubectl get ns $ kubectl get ns
auto-devv-2-16730183-production Active auto-devv-2-16730183-production Active
...@@ -204,7 +204,7 @@ your cluster either using [Cloud Shell](https://cloud.google.com/shell/) or the ...@@ -204,7 +204,7 @@ your cluster either using [Cloud Shell](https://cloud.google.com/shell/) or the
1. To make sure the Rails application is responding, send a request to it by running: 1. To make sure the Rails application is responding, send a request to it by running:
```bash ```shell
$ kubectl get ing -n auto-devv-2-16730183-production $ kubectl get ing -n auto-devv-2-16730183-production
NAME HOSTS PORTS NAME HOSTS PORTS
production-auto-deploy fjdiaz-auto-devv-2.34.68.60.207.nip.io,le-16730183.34.68.60.207.nip.io 80, 443 production-auto-deploy fjdiaz-auto-devv-2.34.68.60.207.nip.io,le-16730183.34.68.60.207.nip.io 80, 443
...@@ -223,7 +223,7 @@ the WAF with OWASP CRS! ...@@ -223,7 +223,7 @@ the WAF with OWASP CRS!
Now let's send a potentially malicious request, as if we were a scanner, Now let's send a potentially malicious request, as if we were a scanner,
checking for vulnerabilities within our application and examine the modsecurity logs: checking for vulnerabilities within our application and examine the modsecurity logs:
```bash ```shell
$ curl --location --insecure fjdiaz-auto-devv-2.34.68.60.207.nip.io --header "User-Agent: absinthe" | grep 'Rails!' --after 2 --before 2 $ curl --location --insecure fjdiaz-auto-devv-2.34.68.60.207.nip.io --header "User-Agent: absinthe" | grep 'Rails!' --after 2 --before 2
<body> <body>
<p>You're on Rails!</p> <p>You're on Rails!</p>
... ...
......
doc/user/project/integrations/img/prometheus_dashboard_environments_v12_8.png

7.25 KiB

doc/user/project/integrations/img/prometheus_monitoring_dashboard_v12_8.png

29 KiB

...@@ -55,6 +55,17 @@ will help you to quickly create a deployment: ...@@ -55,6 +55,17 @@ will help you to quickly create a deployment:
1. Navigate to your project's **CI/CD > Pipelines** page, and run a pipeline on any branch. 1. Navigate to your project's **CI/CD > Pipelines** page, and run a pipeline on any branch.
1. When the pipeline has run successfully, graphs will be available on the **Operations > Metrics** page. 1. When the pipeline has run successfully, graphs will be available on the **Operations > Metrics** page.
![Monitoring Dashboard](img/prometheus_monitoring_dashboard_v12_8.png)
#### Using the Metrics Dashboard
##### Select an environment
The **Environment** dropdown box above the dashboard displays the list of all [environments](#monitoring-cicd-environments).
It enables you to search as you type through all environments and select the one you're looking for.
![Monitoring Dashboard Environments](img/prometheus_dashboard_environments_v12_8.png)
#### About managed Prometheus deployments #### About managed Prometheus deployments
Prometheus is deployed into the `gitlab-managed-apps` namespace, using the [official Helm chart](https://github.com/helm/charts/tree/master/stable/prometheus). Prometheus is only accessible within the cluster, with GitLab communicating through the [Kubernetes API](https://kubernetes.io/docs/concepts/overview/kubernetes-api/). Prometheus is deployed into the `gitlab-managed-apps` namespace, using the [official Helm chart](https://github.com/helm/charts/tree/master/stable/prometheus). Prometheus is only accessible within the cluster, with GitLab communicating through the [Kubernetes API](https://kubernetes.io/docs/concepts/overview/kubernetes-api/).
...@@ -428,6 +439,29 @@ Note the following properties: ...@@ -428,6 +439,29 @@ Note the following properties:
![single stat panel type](img/prometheus_dashboard_single_stat_panel_type.png) ![single stat panel type](img/prometheus_dashboard_single_stat_panel_type.png)
###### Percentile based results
> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/201946) in GitLab 12.8.
Query results sometimes need to be represented as a percentage value out of 100. You can use the `max_value` property at the root of the panel definition:
```yaml
dashboard: 'Dashboard Title'
panel_groups:
- group: 'Group Title'
panels:
- title: "Single Stat"
type: "single-stat"
max_value: 100
metrics:
- id: 10
query: 'max(go_memstats_alloc_bytes{job="prometheus"})'
unit: '%'
label: "Total"
```
For example, if you have a query value of `53.6`, adding `%` as the unit results in a single stat value of `53.6%`, but if the maximum expected value of the query is `120`, the value would be `44.6%`. Adding the `max_value` causes the correct percentage value to display.
##### Heatmaps ##### Heatmaps
> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/30581) in GitLab 12.5. > [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/30581) in GitLab 12.5.
... ...
......
performance: performance:
stage: performance stage: performance
# pin to a version matching the dind service, just to be safe
image: docker:19.03.5 image: docker:19.03.5
allow_failure: true allow_failure: true
variables: variables:
DOCKER_TLS_CERTDIR: "" DOCKER_TLS_CERTDIR: ""
services: services:
# pin to a known working version until https://gitlab.com/gitlab-org/gitlab-runner/issues/6697 is fixed
- docker:19.03.5-dind - docker:19.03.5-dind
script: script:
- | - |
... ...
......
...@@ -4,7 +4,6 @@ build: ...@@ -4,7 +4,6 @@ build:
variables: variables:
DOCKER_TLS_CERTDIR: "" DOCKER_TLS_CERTDIR: ""
services: services:
# pin to a known working version until https://gitlab.com/gitlab-org/gitlab-runner/issues/6697 is fixed
- docker:19.03.5-dind - docker:19.03.5-dind
script: script:
- | - |
... ...
......
code_quality: code_quality:
stage: test stage: test
# pin to a version matching the dind service, just to be safe
image: docker:19.03.5 image: docker:19.03.5
allow_failure: true allow_failure: true
services: services:
# pin to a known working version until https://gitlab.com/gitlab-org/gitlab-runner/issues/6697 is fixed
- docker:19.03.5-dind - docker:19.03.5-dind
variables: variables:
DOCKER_DRIVER: overlay2 DOCKER_DRIVER: overlay2
... ...
......
...@@ -48,7 +48,8 @@ module Quality ...@@ -48,7 +48,8 @@ module Quality
resource_names = raw_resource_names resource_names = raw_resource_names
command = [ command = [
'delete', 'delete',
%(--namespace "#{namespace}") %(--namespace "#{namespace}"),
'--ignore-not-found'
] ]
Array(release_name).each do |release| Array(release_name).each do |release|
... ...
......
...@@ -534,6 +534,9 @@ msgstr "" ...@@ -534,6 +534,9 @@ msgstr ""
msgid "(removed)" msgid "(removed)"
msgstr "" msgstr ""
msgid "*"
msgstr ""
msgid "+ %{amount} more" msgid "+ %{amount} more"
msgstr "" msgstr ""
...@@ -1544,6 +1547,9 @@ msgstr "" ...@@ -1544,6 +1547,9 @@ msgstr ""
msgid "All email addresses will be used to identify your commits." msgid "All email addresses will be used to identify your commits."
msgstr "" msgstr ""
msgid "All environments"
msgstr ""
msgid "All features are enabled for blank projects, from templates, or when importing, but you can disable them afterward in the project settings." msgid "All features are enabled for blank projects, from templates, or when importing, but you can disable them afterward in the project settings."
msgstr "" msgstr ""
...@@ -8385,6 +8391,9 @@ msgstr "" ...@@ -8385,6 +8391,9 @@ msgstr ""
msgid "Fetching licenses failed. You are not permitted to perform this action." msgid "Fetching licenses failed. You are not permitted to perform this action."
msgstr "" msgstr ""
msgid "File"
msgstr ""
msgid "File Hooks" msgid "File Hooks"
msgstr "" msgstr ""
...@@ -19425,6 +19434,12 @@ msgstr "" ...@@ -19425,6 +19434,12 @@ msgstr ""
msgid "There was an error fetching the Designs" msgid "There was an error fetching the Designs"
msgstr "" msgstr ""
msgid "There was an error fetching the environments information."
msgstr ""
msgid "There was an error fetching the variables."
msgstr ""
msgid "There was an error fetching value stream analytics stages." msgid "There was an error fetching value stream analytics stages."
msgstr "" msgstr ""
...@@ -21367,6 +21382,9 @@ msgstr "" ...@@ -21367,6 +21382,9 @@ msgstr ""
msgid "Value Stream Analytics gives an overview of how much time it takes to go from idea to production in your project." msgid "Value Stream Analytics gives an overview of how much time it takes to go from idea to production in your project."
msgstr "" msgstr ""
msgid "Variable"
msgstr ""
msgid "Variables" msgid "Variables"
msgstr "" msgstr ""
... ...
......
export default {
mockVariables: [
{
environment_scope: 'All environments',
id: 113,
key: 'test_var',
masked: false,
protected: false,
value: 'test_val',
variable_type: 'Variable',
},
{
environment_scope: 'All environments',
id: 114,
key: 'test_var_2',
masked: false,
protected: false,
value: 'test_val_2',
variable_type: 'Variable',
},
{
environment_scope: 'All environments',
id: 115,
key: 'test_var_3',
masked: false,
protected: false,
value: 'test_val_3',
variable_type: 'Variable',
},
],
mockVariablesApi: [
{
environment_scope: '*',
id: 113,
key: 'test_var',
masked: false,
protected: false,
value: 'test_val',
variable_type: 'env_var',
},
{
environment_scope: '*',
id: 114,
key: 'test_var_2',
masked: false,
protected: false,
value: 'test_val_2',
variable_type: 'file',
},
],
mockVariablesDisplay: [
{
environment_scope: 'All environments',
id: 113,
key: 'test_var',
masked: false,
protected: false,
value: 'test_val',
variable_type: 'Variable',
},
{
environment_scope: 'All environments',
id: 114,
key: 'test_var_2',
masked: false,
protected: false,
value: 'test_val_2',
variable_type: 'File',
},
],
mockEnvironments: [
{
id: 28,
name: 'staging',
slug: 'staging',
external_url: 'https://staging.example.com',
state: 'available',
},
{
id: 29,
name: 'production',
slug: 'production',
external_url: 'https://production.example.com',
state: 'available',
},
],
};
import Api from '~/api';
import MockAdapter from 'axios-mock-adapter';
import testAction from 'helpers/vuex_action_helper';
import axios from '~/lib/utils/axios_utils';
import createFlash from '~/flash';
import getInitialState from '~/ci_variable_list/store/state';
import * as actions from '~/ci_variable_list/store/actions';
import * as types from '~/ci_variable_list/store/mutation_types';
import mockData from '../services/mock_data';
import { prepareDataForDisplay, prepareEnvironments } from '~/ci_variable_list/store/utils';
jest.mock('~/api.js');
jest.mock('~/flash.js');
describe('CI variable list store actions', () => {
let mock;
let state;
const mockVariable = {
environment_scope: '*',
id: 63,
key: 'test_var',
masked: false,
protected: false,
value: 'test_val',
variable_type: 'env_var',
_destory: true,
};
const payloadError = new Error('Request failed with status code 500');
beforeEach(() => {
mock = new MockAdapter(axios);
state = getInitialState();
state.endpoint = '/variables';
});
afterEach(() => {
mock.restore();
});
describe('toggleValues', () => {
const valuesHidden = false;
it('commits TOGGLE_VALUES mutation', () => {
testAction(actions.toggleValues, valuesHidden, {}, [
{
type: types.TOGGLE_VALUES,
payload: valuesHidden,
},
]);
});
});
describe('clearModal', () => {
it('commits CLEAR_MODAL mutation', () => {
testAction(actions.clearModal, {}, {}, [
{
type: types.CLEAR_MODAL,
},
]);
});
});
describe('resetEditing', () => {
it('commits RESET_EDITING mutation', () => {
testAction(
actions.resetEditing,
{},
{},
[
{
type: types.RESET_EDITING,
},
],
[{ type: 'fetchVariables' }],
);
});
});
describe('deleteVariable', () => {
it('dispatch correct actions on successful deleted variable', done => {
mock.onPatch(state.endpoint).reply(200);
testAction(
actions.deleteVariable,
mockVariable,
state,
[],
[
{ type: 'requestDeleteVariable' },
{ type: 'receiveDeleteVariableSuccess' },
{ type: 'fetchVariables' },
],
() => {
done();
},
);
});
it('should show flash error and set error in state on delete failure', done => {
mock.onPatch(state.endpoint).reply(500, '');
testAction(
actions.deleteVariable,
mockVariable,
state,
[],
[
{ type: 'requestDeleteVariable' },
{
type: 'receiveDeleteVariableError',
payload: payloadError,
},
],
() => {
expect(createFlash).toHaveBeenCalled();
done();
},
);
});
});
describe('updateVariable', () => {
it('dispatch correct actions on successful updated variable', done => {
mock.onPatch(state.endpoint).reply(200);
testAction(
actions.updateVariable,
mockVariable,
state,
[],
[
{ type: 'requestUpdateVariable' },
{ type: 'receiveUpdateVariableSuccess' },
{ type: 'fetchVariables' },
],
() => {
done();
},
);
});
it('should show flash error and set error in state on update failure', done => {
mock.onPatch(state.endpoint).reply(500, '');
testAction(
actions.updateVariable,
mockVariable,
state,
[],
[
{ type: 'requestUpdateVariable' },
{
type: 'receiveUpdateVariableError',
payload: payloadError,
},
],
() => {
expect(createFlash).toHaveBeenCalled();
done();
},
);
});
});
describe('addVariable', () => {
it('dispatch correct actions on successful added variable', done => {
mock.onPatch(state.endpoint).reply(200);
testAction(
actions.addVariable,
{},
state,
[],
[
{ type: 'requestAddVariable' },
{ type: 'receiveAddVariableSuccess' },
{ type: 'fetchVariables' },
],
() => {
done();
},
);
});
it('should show flash error and set error in state on add failure', done => {
mock.onPatch(state.endpoint).reply(500, '');
testAction(
actions.addVariable,
{},
state,
[],
[
{ type: 'requestAddVariable' },
{
type: 'receiveAddVariableError',
payload: payloadError,
},
],
() => {
expect(createFlash).toHaveBeenCalled();
done();
},
);
});
});
describe('fetchVariables', () => {
it('dispatch correct actions on fetchVariables', done => {
mock.onGet(state.endpoint).reply(200, { variables: mockData.mockVariables });
testAction(
actions.fetchVariables,
{},
state,
[],
[
{ type: 'requestVariables' },
{
type: 'receiveVariablesSuccess',
payload: prepareDataForDisplay(mockData.mockVariables),
},
],
() => {
done();
},
);
});
it('should show flash error and set error in state on fetch variables failure', done => {
mock.onGet(state.endpoint).reply(500);
testAction(actions.fetchVariables, {}, state, [], [{ type: 'requestVariables' }], () => {
expect(createFlash).toHaveBeenCalledWith('There was an error fetching the variables.');
done();
});
});
});
describe('fetchEnvironments', () => {
it('dispatch correct actions on fetchEnvironments', done => {
Api.environments = jest.fn().mockResolvedValue({ data: mockData.mockEnvironments });
testAction(
actions.fetchEnvironments,
{},
state,
[],
[
{ type: 'requestEnvironments' },
{
type: 'receiveEnvironmentsSuccess',
payload: prepareEnvironments(mockData.mockEnvironments),
},
],
() => {
done();
},
);
});
it('should show flash error and set error in state on fetch environments failure', done => {
Api.environments = jest.fn().mockRejectedValue();
testAction(
actions.fetchEnvironments,
{},
state,
[],
[{ type: 'requestEnvironments' }],
() => {
expect(createFlash).toHaveBeenCalledWith(
'There was an error fetching the environments information.',
);
done();
},
);
});
});
});