Commit a23f7aa5 authored by Pierre Smeyers's avatar Pierre Smeyers
Browse files

feat: initial template implem

parent e0ea65d9
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -21,3 +21,4 @@
/nbdist/
/.nb-gradle/
.DS_Store
triggers-ex-1.json
+2 −2
Original line number Diff line number Diff line
@@ -8,8 +8,8 @@ Closes #999
## Checklist

* General:
    * [ ] use [rules](https://docs.gitlab.com/ee/ci/yaml/#rules) instead of [only/except](https://docs.gitlab.com/ee/ci/yaml/#onlyexcept-advanced)
    * [ ] optimized [cache](https://docs.gitlab.com/ee/ci/caching/) configuration (wherever applicable)
    * [ ] use [rules](https://docs.gitlab.com/ci/yaml/#rules) instead of [only/except](https://docs.gitlab.com/ci/yaml/#onlyexcept-advanced)
    * [ ] optimized [cache](https://docs.gitlab.com/ci/caching/) configuration (wherever applicable)
* Publicly usable:
    * [ ] untagged runners
    * [ ] no proxy configuration but support `http_proxy`/`https_proxy`/`no_proxy`
+1 −1
Original line number Diff line number Diff line
@@ -61,7 +61,7 @@ To contribute:

1. Create an issue describing the bug or enhancement you want to propose (select the right issue template).
2. Make sure the issue has been reviewed and agreed.
3. Create a Merge Request, from your **own** fork (see [forking workflow](https://docs.gitlab.com/ee/user/project/repository/forking_workflow.html) documentation).
3. Create a Merge Request, from your **own** fork (see [forking workflow](https://docs.gitlab.com/user/project/repository/forking_workflow/) documentation).
   Don't hesitate to mark your MR as `Draft` as long as you think it's not ready to be reviewed.

### Git Commit Conventions
+1 −2
Original line number Diff line number Diff line
@@ -3,10 +3,9 @@ files:
    documentation: ./README.md
    changelog: ./CHANGELOG.md
data:
    description: "Run your automated tests with GitOps"
    description: "Trigger a GitOps deployment from your GitLab CI/CD pipelines"
    labels:
    - to be continuous
    - Test
    - GitOps
    public: true
    license: LGPL v3
+115 −44
Original line number Diff line number Diff line
# GitLab CI template for GitOps

This project implements a GitLab CI/CD template to run your automated tests with [GitOps](https://doc.acme-tech.com).
This project implements a template to integrate GitOps deployment strategy with your GitLab CI/CD pipelines.

More specifically, this template allows you to trigger a change to a JSON or YAML file in a remote Git repository from your project pipeline.

For example, it will allow you to automatically update an image tag in a [Helm Values file](https://helm.sh/docs/chart_template_guide/values_files/) as soon as a new version of the container image is produced.

> [!important]
> This technique is certainly not the only nor the best way to implement a GitOps deployment strategy but in some cases it might help.
>
> Whenever possible, we recommend using dedicated tools, such as:
>
> - [Auto image update](https://fluxcd.io/flux/guides/image-update/) with FluxCD,
> - [Argo CD Image Updater](https://argocd-image-updater.readthedocs.io/) with ArgoCD,
> - even [Renovate](https://docs.renovatebot.com/) can help you implement the same very smartly.

## Usage
**component: $CI_SERVER_FQDN**
This template can be used both as a [CI/CD component](https://docs.gitlab.com/ee/ci/components/#use-a-component) 
or using the legacy [`include:project`](https://docs.gitlab.com/ee/ci/yaml/index.html#includeproject) syntax.

This template can be used both as a [CI/CD component](https://docs.gitlab.com/ci/components/#use-a-component)
or using the legacy [`include:project`](https://docs.gitlab.com/ci/yaml/#includeproject) syntax.

### Use as a CI/CD component

@@ -15,9 +28,8 @@ Add the following to your `.gitlab-ci.yml`:
include:
  # 1: include the component
  - component: $CI_SERVER_FQDN/to-be-continuous/gitops/gitlab-ci-gitops@1.0.0
    # 2: set/override component inputs
    inputs:
      review-enabled: true # ⚠ this is only an example

# 2: GITOPS_TRIGGER_XXX variables are defined as project CI/CD variables
```

### Use as a CI/CD template (legacy)
@@ -27,50 +39,109 @@ Add the following to your `.gitlab-ci.yml`:
```yaml
include:
  # 1: include the template
  - project: 'to-be-continuous/gitops'
    ref: '1.0.0'
    file: '/templates/gitlab-ci-gitops.yml'
  - project: "to-be-continuous/gitops"
    ref: "1.0.0"
    file: "/templates/gitlab-ci-gitops.yml"

variables:
  # 2: set/override template variables
  REVIEW_ENABLED: "true" # ⚠ this is only an example
# 2: GITOPS_TRIGGER_XXX variables are defined as project CI/CD variables
```

## `gitops` job
## `gitops-trigger` job

This job starts [GitOps](https://doc.acme-tech.com) (functional) tests.
This job triggers a change to a JSON or YAML file in a remote Git repository.

It uses the following variable:

| Input / Variable                  | Description                                                                                               | Default value |
| --------------------- | ---------------------------------------- | ----------------- |
| `image` / `GITOPS_IMAGE`       | The Docker image used to run GitOps. | `docker.io/gitops:latest`<br/>[![Trivy Badge](https://to-be-continuous.gitlab.io/doc/secu/trivy-badge-GITOPS_IMAGE.svg)](https://to-be-continuous.gitlab.io/doc/secu/trivy-GITOPS_IMAGE) |
| `project-dir` / `GITOPS_PROJECT_DIR` | The GitOps project directory (containing test scripts) | `.` |
| `extra-args` / `GITOPS_EXTRA_ARGS`  | GitOps extra [run options](link-to-cli-options-ref) | _none_ |
| `review-enabled` / `REVIEW_ENABLED`      | Set to `true` to enable GitOps tests on review environments (dynamic environments instantiated on development branches) | _none_ (disabled) |

In addition to a textual report in the console, this job produces the following reports, kept for one day:

| Report         | Format                                                                       | Usage             |
| -------------- | ---------------------------------------------------------------------------- | ----------------- |
| `$GITOPS_PROJECT_DIR/reports/gitops.xunit.xml` | [xUnit](https://github.com/jest-community/jest-junit#readme) test report(s) | [GitLab integration](https://docs.gitlab.com/ee/ci/yaml/artifacts_reports.html#artifactsreportsjunit) |

### base url auto evaluation

By default, the GitOps template tries to auto-evaluate its base url
(i.e. the variable pointing at server under test) by looking either for a `$environment_url` variable or for an 
`environment_url.txt` file.

Therefore if an upstream job in the pipeline deployed your code to a server and propagated the deployed server url,
either through a [dotenv](https://docs.gitlab.com/ee/ci/pipelines/job_artifacts.html#artifactsreportsdotenv) variable `$environment_url` 
or through a basic `environment_url.txt` file, then the GitOps test will automatically be run on this server.

:warning: all our deployment templates implement this design. Therefore even purely dynamic environments (such as review
environments) will automatically be propagated to your GitOps tests.
| --------------------------------- | --------------------------------------------------------------------------------------------------------- | ------------- |
| `image` / `GITOPS_IMAGE`          | The Docker image used to run GitOps (`git` + `yq`)                                                        | `docker.io/alpine/git:latest`<br/>[![Trivy Badge](https://to-be-continuous.gitlab.io/doc/secu/trivy-badge-GITOPS_IMAGE.svg)](https://to-be-continuous.gitlab.io/doc/secu/trivy-GITOPS_IMAGE) |
| :lock: `GITOPS_TRIGGER_ONPROD`    | The GitOps changes to trigger on the production branch (JSON) - [see below](#triggers-definition-json)    | _none_ (disabled) |
| :lock: `GITOPS_TRIGGER_ONINTEG`   | The GitOps changes to trigger on the integration branch (JSON) - [see below](#triggers-definition-json)   | _none_ (disabled) |
| :lock: `GITOPS_TRIGGER_ONDEV`     | The GitOps changes to trigger on the development branches (JSON) - [see below](#triggers-definition-json) | _none_ (disabled) |
| :lock: `GITOPS_TRIGGER_ONRELEASE` | The GitOps changes to trigger on release tags (JSON) - [see below](#triggers-definition-json)             | _none_ (disabled) |

### Triggers definition (JSON)

The GitOps changes to trigger must be defined as a JSON structure, defining:

- whether to trigger automatically or manually,
- the target Git repositories and branch,
- the files to modify,
- the [`yq eval` command](https://mikefarah.gitbook.io/yq/operators/eval) to apply (supports late variable expansion).

:warning: the triggers definition MUST be managed as a project CI/CD variable (outside of the project `.gitlab-ci.yaml` then) for two reasons:

- target repository URL bears their own authentication credentials,
- allows a loose coupling between the source project and the target repositories to trigger (you don't necessarilly want to update the source project `.gitlab-ci.yaml` every time you change the triggers).

The triggers definition is formatted as follows:

```json
{
  "when": "<whether to trigger changes manually or automatically (one of 'manual' or 'on_success')>",
  "commit_message": "<optional /The commit message template to use for GitOps trigger (supports late variable expansion)>",
  "triggers": [
    {
      "url": "<The target repository URL to push changes, including credentials>",
      "branch": "<The target repository branch to push changes to>",
      "commit_message": "<optional / The repo specific commit message template to use (supports late variable expansion)>",
      "dry_run": "<optional / true or false>",
      "changes": [
        {
          "file": "<The target file to apply the 'yq eval' command>",
          "yq_eval": "<The 'yq eval' command to apply (supports late variable expansion) - see https://mikefarah.gitbook.io/yq/operators/eval>"
        },
        ...
      ]
    },
    ...
  ]
}
```

### Hook scripts
:information_source: The triggers definition must respect [this JSON schema](./triggers-schema-1.json).

### Example

```json
{
  "when": "manual",
  "commit_message": "chore(gitops): update deployment values triggered from commit #$CI_COMMIT_SHA (see $CI_PIPELINE_URL)",
  "triggers": [
    {
      "url": "https://token:$MY_RW_ACCESS_TOKEN@$CI_SERVER_FQDN/path/to/values/project.git",
      "branch": "main",
      "changes": [
        {
          "file": "values_preprod.yml",
          "yq_eval": ".myapp.image.tag = \"$${docker_tag}@$${docker_digest}\""
        }
      ]
    }
  ]
}
```

The GitOps template supports _optional_ **hook scripts** from your project, located in the `$GITOPS_PROJECT_DIR` directory to perform additional project-specific logic:

* `pre-gitops.sh` is executed **before** running GitOps,
* `post-gitops.sh` is executed **after** running GitOps (whichever the tests status).
> [!important] Late variable expansion mechanism
>
> The template supports a **late variable expansion mechanism** for the `commit_message` and `yq_eval` JSON fields.
>
> It allows you to inject dynamically evaluated variables (coming from the pipeline execution context), using the `%{somevar}` (or `$${somevar}`) syntax.
> 
> The above example makes use of it to inject `$docker_tag` and `$docker_digest` variables, propagated by the Docker template.
> 
> :bulb: on the other hand, the here-above `commit_message` field doesn't need to use this technique here as `$CI_COMMIT_SHA` and `$CI_PIPELINE_URL` are not _late evaluated_.

> [!important] Target repository URL bears authentication
> 
> This template doesn't support any fancy mechanism to provide authentication, but instead assumes the target Git repository URL bears its own authentication credentials.
> 
> Example: `https://user:suP3rpA55w0rd@gitlab.acme.corp/path/to/values/project`
> 
> :warning: make sure to manage those credentials safely, as any other secret:
> 
> - never store them directly in your source code,
> - manage them as [project or group CI/CD variables](https://docs.gitlab.com/ci/variables/#for-a-project):
>    * [**masked**](https://docs.gitlab.com/ci/variables/#mask-a-cicd-variable) to prevent them from being inadvertently displayed in your job logs,
>    * [**protected**](https://docs.gitlab.com/ci/variables/#protected-cicd-variables) if you want to secure some secrets you don't want everyone in the project to have access to (for instance production secrets).
Loading