Commit 4021233b authored by Pierre Smeyers's avatar Pierre Smeyers
Browse files

chore: skeleton for an acceptance template

parent a7a0fb70
Loading
Loading
Loading
Loading
+23 −83
Original line number Diff line number Diff line
# GitLab CI template for XXX

This project implements a generic GitLab CI template for [XXX](https://link.to.tool.com/).
This project implements a generic GitLab CI template for running [XXX](https://link.to.tool.com/)  automated tests.

It provides several features, usable in different modes (by configuration).

@@ -15,98 +15,38 @@ include:
    file: '/templates/gitlab-ci-xxx.yml'
```

## Global configuration
:warning: depending on your needs and environment, you might have to use [one of the template variants](#variants).

The XXX template uses some global configuration used throughout all jobs.
## `xxx` job

| Name                  | description                            | default value     |
| --------------------- | -------------------------------------- | ----------------- |
| `XXX_IMAGE`           | The Docker image used to run XXX       | `xxx:latest` |

## Jobs

### `xxx-build` job

This job performs **build and tests** at once.
This job starts [XXX](https://link.to.tool.com/) tests.

It uses the following variable:

| Name                  | description                               | default value     |
| --------------------- | ---------------------------------------- | ----------------- |
| `XXX_BUILD_ARGS`      | Arguments used by the build job          | `build --with-default-args` |

### SonarQube analysis

If you're using the SonarQube template to analyse your XXX code, here are 2 sample `sonar-project.properties` files.

```properties
# see: https://docs.sonarqube.org/latest/analysis/languages/xxx/
# set your source directory(ies) here (relative to the sonar-project.properties file)
sonar.sources=.
# exclude unwanted directories and files from being analysed
sonar.exclusions=output/**,**/*_test.xxx

# set your tests directory(ies) here (relative to the sonar-project.properties file)
sonar.tests=.
sonar.test.inclusions=**/*_test.xxx

# tests report (TODO)
sonar.xxx.testExecutionReportPaths=reports/sonar_test_report.xml
# coverage report (TODO)
sonar.xxx.coverage.reportPaths=reports/coverage.cov
```

More info:

* [XXX language support](https://docs.sonarqube.org/latest/analysis/languages/xxx/)
* [test coverage & execution parameters](https://docs.sonarqube.org/latest/analysis/coverage/)
* [third-party issues](https://docs.sonarqube.org/latest/analysis/external-issues/)

### `xxx-lint` job

This job performs a [lint](link-to-the-tool) analysis of your code, mapped to the `build` stage.

It uses the following variables:
| --------------------- | ----------------------------------------- | ----------------- |
| `XXX_IMAGE`           | The Docker image used to run XXX          | `xxx:latest`      |
| `XXX_ROOT_DIR`        | The root XXX project directory            | `.`               |
| `XXX_EXTRA_ARGS`      | XXX extra [options](link-to-ref-doc-here) | _none_            |
| `REVIEW_ENABLED`      | Set to enable XXX tests on review environments (dynamic environments instantiated on development branches) | _none_ (disabled) |

| Name                  | description                                | default value     |
| --------------------- | ------------------------------------------ | ----------------- |
| `XXX_LINT_IMAGE`      | The Docker image used to run the lint tool | `xxx-lint:latest` |
| `XXX_LINT_ARGS`       | Lint [options and arguments](link-to-the-cli-options) | `--serevity=medium` |
### Unit tests report integration

### `xxx-depcheck` job
XXX test reports are [integrated to GitLab by generating JUnit reports](https://docs.gitlab.com/ee/ci/junit_test_reports.html).

This job enables a manual [dependency check](link-to-the-tool) analysis of your code, mapped to the `test` stage.
This is done using the following CLI options: `--junit --output=reports/`  

It uses the following variables:
### Base URL auto evaluation

| Name                  | description                                | default value     |
| --------------------- | ------------------------------------------ | ----------------- |
| `XXX_DEPCHECK_IMAGE`  | The Docker image used to run the dependency check tool | `xxx-depcheck:latest` |
| `XXX_DEPCHECK_ARGS`   | Dependency check [options and arguments](link-to-the-cli-options) | _none_ |
By default, the XXX template tries to auto-evaluate the 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.

### `xxx-publish` job
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 XXX test will automatically be run on this server.

This job is **disabled by default** and performs a publish of your built binaries.
:warning: all our deployment templates implement this design. Therefore even purely dynamic environments (such as review
environments) will automatically be propagated to your XXX tests.

It uses the following variables:

| Name                  | description                            | default value     |
| --------------------- | -------------------------------------- | ----------------- |
| `XXX_PUBLISH_ENABLED` | Variable to enable the publish job     | _none_ (disabled) |
| `XXX_PUBLISH_ARGS`    | Arguments used by the publish job      | `publish --with-default-args` |
| :lock: `XXX_PUBLISH_LOGIN` | Login to use to publish           | **has to be defined** |
| :lock: `XXX_PUBLISH_PASSWORD` | Password to use to publish     | **has to be defined** |

### Secrets management

Here are some advices about your **secrets** (variables marked with a :lock:):

1. Manage them as [project or group CI/CD variables](https://docs.gitlab.com/ee/ci/variables/#create-a-custom-variable-in-the-ui):
    * [**masked**](https://docs.gitlab.com/ee/ci/variables/#mask-a-custom-variable) to prevent them from being inadvertently
      displayed in your job logs,
    * [**protected**](https://docs.gitlab.com/ee/ci/variables/#protect-a-custom-variable) if you want to secure some secrets
      you don't want everyone in the project to have access to (for instance production secrets).
2. In case a secret contains [characters that prevent it from being masked](https://docs.gitlab.com/ee/ci/variables/#masked-variable-requirements), 
  simply define its value as the [Base64](https://en.wikipedia.org/wiki/Base64) encoded value prefixed with `@b64@`:
  it will then be possible to mask it and the template will automatically decode it prior to using it.
3. Don't forget to escape special characters (ex: `$` -> `$$`).
If you're not using a smart deployment job, you may still explicitly declare the `XXX_BASE_URL` variable (but that
will be unfortunately hardcoded to a single server).
+13 −65
Original line number Diff line number Diff line
{
  "name": "XXX",
  "description": "GitLab CI template for XXX",
  "description": "GitLab CI template for running [XXX](https://link.to.tool.com/)  automated tests.",
  "template_path": "templates/gitlab-ci-xxx.yml",
  "kind": "build",
  "kind": "acceptance",
  "variables": [
    {
      "name": "XXX_IMAGE",
      "description": "The Docker image used to run XXX",
      "default": "xxx:1.2.3"
      "description": "The Docker image used to run XXX CLI.",
      "default": "xxx:latest"
    },
    {
      "name": "XXX_BUILD_ARGS",
      "description": "Arguments used by the build job",
      "default": "build --with-default-args",
      "advanced": true
    }
  ],
  "features": [
    {
      "id": "lint",
      "name": "XXX lint",
      "description": "[XXX lint](link-to-the-tool) analysis",
      "variables": [
        {
          "name": "XXX_LINT_IMAGE",
          "description": "The Docker image used to run the lint tool",
          "default": "xxx-lint:latest"
      "name": "XXX_ROOT_DIR",
      "description": "The root XXX project directory",
      "default": "."
    },
    {
          "name": "XXX_LINT_ARGS",
          "description": "Lint [options and arguments](link-to-the-cli-options)",
          "default": "--serevity=medium",
      "name": "XXX_EXTRA_ARGS",
      "description": "XXX extra [options](link-to-ref-doc-here)",
      "advanced": true
        }
      ]
    },
    {
      "id": "depcheck",
      "name": "XXX dependency check",
      "description": "[XXX dependency check](link-to-the-tool) analysis",
      "variables": [
        {
          "name": "XXX_DEPCHECK_IMAGE",
          "description": "The Docker image used to run the dependency check tool",
          "default": "xxx-depcheck:latest"
        },
        {
          "name": "XXX_DEPCHECK_ARGS",
          "description": "Dependency check [options and arguments](link-to-the-cli-options)",
          "advanced": true
        }
      ]
    },
    {
      "id": "publish",
      "name": "Publish",
      "description": "Publish your package to a repository",
      "enable_with": "XXX_PUBLISH_ENABLED",
      "variables": [
        {
          "name": "XXX_PUBLISH_ARGS",
          "description": "Arguments used by the publish job",
          "default": "publish --with-default-args",
          "advanced": true
        },
        {
          "name": "XXX_PUBLISH_LOGIN",
          "description": "Login to use to publish",
          "secret": true
        },
        {
          "name": "XXX_PUBLISH_PASSWORD",
          "description": "Password to use to publish",
          "secret": true
        }
      ]
      "name": "REVIEW_ENABLED",
      "description": "Set to enable XXX tests on review environments (dynamic environments instantiated on development branches)",
      "type": "boolean"
    }
  ]
}
+49 −119
Original line number Diff line number Diff line
@@ -14,19 +14,11 @@
# Floor, Boston, MA  02110-1301, USA.
# =========================================================================================
variables:
  # Default Docker image (use a public image - can be overridden)
  # Default Docker image (can be overriden)
  XXX_IMAGE: "xxx:latest"

  # Default arguments for 'build' command
  XXX_BUILD_ARGS: "build --with-default-args"

  # Default arguments for 'publish' command
  XXX_PUBLISH_ARGS: "publish --with-default-args"

  XXX_LINT_IMAGE: "xxx-lint:latest"
  XXX_LINT_ARGS: "--serevity=medium"

  XXX_DEPCHECK_IMAGE: "xxx-depcheck:latest"
  # Directory where XXX tests are implemented
  XXX_ROOT_DIR: "."

  # default production ref name (pattern)
  PROD_REF: '/^master$/'
@@ -35,9 +27,7 @@ variables:

# allowed stages depend on your template type (see: orange-opensource.gitlab.io/tbc/doc/dev-guidelines/#stages)
stages:
  - build
  - test
  - publish
  - acceptance

.xxx-scripts: &xxx-scripts |
  # BEGSCRIPT
@@ -175,9 +165,22 @@ stages:
    done
  }

  function output_coverage() {
    echo "[TODO]: compute and output global coverage result"
    echo "11% covered"
  # retrieve server url to test from upstream artifacts ($environment_url variable or 'environment_url.txt' file)
  function eval_env_url() {
    # shellcheck disable=SC2154
    if [[ -n "$environment_url" ]]
    then
      XXX_BASE_URL="$environment_url"
      export XXX_BASE_URL
      log_info "Upstream \$environment_url variable set: use base url \\e[33;1m$XXX_BASE_URL\\e[0m"
    elif [[ -f environment_url.txt ]]
    then
      XXX_BASE_URL=$(cat environment_url.txt)
      export XXX_BASE_URL
      log_info "Upstream environment_url.txt file found: use base url \\e[33;1m$XXX_BASE_URL\\e[0m"
    else
      log_info "No upstream environment url found: leave default"
    fi
  }

  function get_latest_template_version() {
@@ -203,125 +206,52 @@ stages:

  # ENDSCRIPT

# job prototype
# defines default Docker image, tracking probe, cache policy and tags
.xxx-base:
# The main job that starts acceptance tests tool
# on master branch: automatically started after staging deployment
# on non-master branch: manually started after review env deployment (requires $REVIEW_ENABLED to be set)
xxx:
  image: $XXX_IMAGE
  services:
    - name: "$CI_REGISTRY/orange-opensource/tbc/tools/tracking:master"
      command: ["--service", "xxx", "1.0.0"]
  before_script:
    - *xxx-scripts
    - install_ca_certs "${CUSTOM_CA_CERTS:-$DEFAULT_CA_CERTS}"
  # Cache downloaded dependencies and plugins between builds.
  # To keep cache across branches add 'key: "$CI_JOB_NAME"'
  stage: acceptance
  # TODO (if necessary): define cache policy here
  cache:
    # cache shall be per branch per template
    key: "$CI_COMMIT_REF_SLUG-xxx"
    key: "${CI_COMMIT_REF_SLUG}-xxx"
    paths:
      - .cache/

# (example) build & test job
xxx-build:
  extends: .xxx-base
  stage: build
  before_script:
    - *xxx-scripts
    - install_ca_certs "${CUSTOM_CA_CERTS:-$DEFAULT_CA_CERTS}"
    - eval_env_url
    - cd "$XXX_ROOT_DIR"
    # TODO (if necessary): do setup stuff here
  script:
    # TODO: run xxx tests
    # TODO (if possible): $TRACE set enables debug logs on the tool
    # TODO (if possible): force test tool to produce JUnit report(s)
    # TODO (if possible): force test tool to compute code coverage with report
    - xxx ${TRACE+--verbose} --coverage --junit --output=reports/ $XXX_BUILD_ARGS
    - output_coverage
  # TODO: code coverage support and GitLab integration (see: https://docs.gitlab.com/ee/ci/yaml/#coverage)
  coverage: '/^(\d+.\d+\%) covered$/'
  # keep build artifacts and test reports (see: https://docs.gitlab.com/ee/ci/yaml/#artifactsreportsjunit)
    - mkdir reports
    - xxx run ${TRACE+--verbose} --env BASE_URL=$XXX_BASE_URL --junit --output=reports/ $XXX_EXTRA_ARGS
  artifacts:
    name: "$CI_JOB_NAME artifacts from $CI_PROJECT_NAME on $CI_COMMIT_REF_SLUG"
    expire_in: 1 day
    reports:
      # TODO: Unit tests use JUnit format and GitLab integration (see: https://docs.gitlab.com/ee/ci/yaml/#artifactsreports)
      junit:
        - reports/TEST-*.xml
    paths:
        - build/
        - reports/
  rules:
    # exclude merge requests
    - if: '$CI_MERGE_REQUEST_ID == null'

# (example) linter job
xxx-lint:
  extends: .xxx-base
  stage: build
  image: $XXX_LINT_IMAGE
  # force no dependency
  dependencies: []
  script:
    - xxx_lint ${TRACE+--verbose} --output=reports/ $XXX_LINT_ARGS
  artifacts:
    name: "$CI_JOB_NAME artifacts from $CI_PROJECT_NAME on $CI_COMMIT_REF_SLUG"
    expire_in: 1 day
    when: always
    paths:
      - reports/
  rules:
    # exclude merge requests
    - if: $CI_MERGE_REQUEST_ID
      when: never
    # on production or integration branches: auto
    - if: '$CI_COMMIT_REF_NAME =~ $PROD_REF || $CI_COMMIT_REF_NAME =~ $INTEG_REF'
    # else (development branches): manual & non-blocking
    - when: manual
      allow_failure: true

# (example) dependency check job
xxx-depcheck:
  extends: .xxx-base
  stage: test
  image: $XXX_DEPCHECK_IMAGE
  # force no dependency
  dependencies: []
  script:
    - xxx_depcheck ${TRACE+--verbose} --output=reports/ $XXX_DEPCHECK_ARGS
  artifacts:
    name: "$CI_JOB_NAME artifacts from $CI_PROJECT_NAME on $CI_COMMIT_REF_SLUG"
      - $XXX_ROOT_DIR/reports/
    reports:
      # TODO (if possible): Acceptance tests use JUnit format and GitLab integration (see: https://docs.gitlab.com/ee/ci/yaml/#artifactsreports)
      junit:
        - $XXX_ROOT_DIR/reports/tests-report.xml
    expire_in: 1 day
    when: always
    paths:
      - reports/
  rules:
    # exclude merge requests
    - if: $CI_MERGE_REQUEST_ID
      when: never
    # on schedule: auto
    - if: '$CI_PIPELINE_SOURCE == "schedule"'
      allow_failure: true
      when: always
    # all other cases: manual & non-blocking
    - when: manual
      allow_failure: true

# (example) publish job activated on env ($XXX_PUBLISH_ENABLED), with required $XXX_PUBLISH_LOGIN and $XXX_PUBLISH_PASSWORD env verification
xxx-publish:
  extends: .xxx-base
  stage: publish
  before_script:
    - *xxx-scripts
    # verify $XXX_PUBLISH_LOGIN and $XXX_PUBLISH_PASSWORD are set
    - assert_defined "$XXX_PUBLISH_LOGIN" 'Missing required env $XXX_PUBLISH_LOGIN'
    - assert_defined "$XXX_PUBLISH_PASSWORD" 'Missing required env $XXX_PUBLISH_PASSWORD'
    - xxx login --login=$XXX_PUBLISH_LOGIN --password=$XXX_PUBLISH_PASSWORD
  script:
    - xxx $XXX_PUBLISH_ARGS
  rules:
    # exclude merge requests
    - if: $CI_MERGE_REQUEST_ID
    # exclude tags
    - if: $CI_COMMIT_TAG
      when: never
    # on production branch(es): manual & non-blocking if $XXX_PUBLISH_ENABLED is set
    - if: '$XXX_PUBLISH_ENABLED && $CI_COMMIT_REF_NAME =~ $PROD_REF'
      when: manual
      allow_failure: true
    # on integration branch(es): manual & non-blocking if $XXX_PUBLISH_ENABLED is set
    - if: '$XXX_PUBLISH_ENABLED && $CI_COMMIT_REF_NAME =~ $INTEG_REF'
    # on production and integration branch(es): auto (on_success)
    - if: '$CI_COMMIT_REF_NAME =~ $PROD_REF || $CI_COMMIT_REF_NAME =~ $INTEG_REF'
    # on other branch(es): manual & non-blocking if $REVIEW_ENABLED set
    - if: $REVIEW_ENABLED
      when: manual
      allow_failure: true
 No newline at end of file