From 604af5f75a2c357c0788f82418f61cef13b39057 Mon Sep 17 00:00:00 2001
From: jurgenhaas <juergen@paragon-es.de>
Date: Thu, 21 Jan 2021 18:42:28 +0100
Subject: [PATCH] devops-tools/documentation#16 GitLab CI/CD for Drupal
 projects

---
 docs/gitlab/drupal/index.md | 306 +++++++++++++++++++++++++++++++++++-
 1 file changed, 303 insertions(+), 3 deletions(-)

diff --git a/docs/gitlab/drupal/index.md b/docs/gitlab/drupal/index.md
index 2546492..eb673a6 100644
--- a/docs/gitlab/drupal/index.md
+++ b/docs/gitlab/drupal/index.md
@@ -7,7 +7,307 @@ tags:
 - ci/cd
 - drupal
 ---
-## Usage for test and deploy
+# GitLab CI for Drupal pipelines
 
-* You can set the CI/CD variable `COMPOSER_DOWNGRADE` to `1` for using the composer version 1. Default is composer version 2.
-* For authenticating with the Gitlab package repository, you have to set the variable `GITLAB_ACCESS_TOKEN`, which you have to create for the user who runs the pipeline.
+This project contains a number of pre-configured tasks for GitLab CI/CD that
+allow to run very powerful pipelines which contain the following stages:
+
+- validation
+- build
+- prepare
+- test
+- deploy
+
+These pre-configured tasks can easily be included into your Drupal project.
+A GitLab runner on any host can then be configured to run those pipelines. The 
+following chapters describe the necessary steps and also all the options
+available for configuration.
+
+## Configuration
+
+### GitLab Runner
+
+To setup a GitLab runner, they need to be
+[installed first](https://docs.gitlab.com/runner/install) - see also our
+[Ansible role](/ansible/roles/gitlab-runner). Then go to the Drupal project
+on GitLab into **Settings / CI/CD / Runners** and follow the instructions
+there. Make sure that the runner gets tagged with `default` in GitLab.
+
+As a result, a file `/etc/gitlab-runner/config.toml` get created and this
+should be edited to look like this:
+
+```
+[[runners]]
+  name = "Name of runner"
+  url = "https://gitlab.lakedrops.com/"
+  token = "TOKEN"
+  executor = "docker"
+  [runners.cache]
+    [runners.cache.s3]
+    [runners.cache.gcs]
+  [runners.docker]
+    tls_verify = false
+    image = "registry.lakedrops.com/docker/gitlab-drupal-ci:php-7.4"
+    privileged = true
+    disable_entrypoint_overwrite = false
+    oom_kill_disable = false
+    disable_cache = false
+    volumes = ["/var/run/docker.sock:/var/run/docker.sock", "/cache"]
+    cache_dir = "/cache"
+    shm_size = 0
+```
+
+The image is tagged for the PHP version the project uses. For projects with
+different PHP versions a different GitLab runner should be configured or the
+image being overwritten for each task in the `.gitlab-ci.yml` of the respective
+project.
+
+### GitLab Variables
+
+Some variables are required for proper access control and you have to provide
+them in the project configuration by going to **Settings / CI/CD / Variables**
+and adding these variables:
+
+- `SSH_PRIVATE_KEY`: A private key being generated elsewhere just for this 
+  purpose. This is necessary for cloning private Git repositories.
+- `GITLAB_ACCESS_TOKEN`: For authenticating with the LakeDrops Gitlab package
+  repository, you have to create an access tokeb for the user who runs the
+  pipeline and provide it in this variable.
+
+### GitLab CI instructions in Drupal project
+
+The Drupal project should be setup with the
+[Drupal Development Environment](/composer/plugin/drupal-dev-environment)
+composer plugin and then get a `.gitlab-ci.yml` file for the pipeline
+configuration:
+
+```yaml
+variables:
+  COMPOSE_PROJECT_NAME: myproject_$CI_COMMIT_REF_SLUG
+  ENVIRONMENT_NAME: myproject/$CI_COMMIT_REF_NAME
+  THEME_CSS_PATH: web/themes/custom/mytheme/css
+
+include:
+  - project: 'gitlab-ci-cd/drupal'
+    ref: master
+    file: '/test-and-deploy.yml'
+
+Validate Environment:
+  extends: '.prerequisites'
+
+Build Site:
+  extends: '.build'
+
+Download DB:
+  stage: build
+  tags:
+    - default
+  variables:
+    GIT_STRATEGY: none
+  script: |
+    if [[ "$DBREQUIRED" == "yes" ]]; then
+      echo "Scripts have not been developed yet"
+    fi
+  cache: {}
+  dependencies:
+    - 'Validate Environment'
+  artifacts:
+    name: dbdump
+    when: always
+    paths:
+      - ${CI_PROJECT_NAME}.sql
+  except:
+    refs:
+      - tags
+    variables:
+      - $CI_COMMIT_MESSAGE =~ /^Merge tag /i
+      - $CAE
+      - $DISABLE_CI_TESTS
+
+Import DB:
+  extends: '.importdb'
+
+Update DB:
+  extends: '.updatedb'
+
+Build Theme:
+  extends: '.theme'
+  before_script:
+    - cd web/themes/custom/mytheme
+
+Test Code Style:
+  extends: '.codestyle'
+
+Test PHPUnit:
+  extends: '.phpunit'
+
+Test Behat:
+  extends: '.behat'
+
+Test Backstop:
+  extends: '.backstop'
+
+Deploy:
+  stage: deploy
+  tags:
+    - default
+  variables:
+    GIT_STRATEGY: none
+  environment:
+    name: ${ENVIRONMENT_NAME}
+  script:
+    - echo "Scripts have not been developed yet"
+  cache: {}
+  dependencies:
+    - 'Build Theme'
+  except:
+    refs:
+      - tags
+    variables:
+      - $CI_COMMIT_MESSAGE =~ /^Merge tag /i
+      - $CAE
+```
+
+The tasks for downloading the database dump and to deploy the site finally,
+depend on your hosting environment and have not been generalized, unless you're
+using our Ansible environment too, then please refer to
+[Using Ansible to Dump DB](#Using Ansible to Dump DB) and
+[Using Ansible for Deployment](#Using Ansible for Deployment) below. Otherwise,
+you have to write the scripts for those two tasks yourselves.
+
+#### Variables
+
+- `COMPOSE_PROJECT_NAME`
+- `ENVIRONMENT_NAME`
+- `THEME_CSS_PATH`
+- `COMPOSER_DOWNGRADE`: by default, composer 2 is being used. To use composer 1
+  instead, set this variable to 1.
+- `DISABLE_CI_TESTS`: if this variable is set to any value, the tasks in the
+  test stage will be skipped. This is useful e.g. in a development environment
+  where you push and run pipelines often but don't want to run the tests every
+  single time.
+- `CAE`: This variable is being used by the Drupal module 
+  [Config auto export](https://www.drupal.org/project/config_auto_export)
+
+#### Stages and Tasks
+
+It's important to use exactly these task names as most of them are also being
+used to define dependencies:
+
+- `validation`
+    - `Validate Environment`
+- `build`
+    - `Build Site`
+    - `Download DB`
+- `prepare`
+    - `Import DB`
+    - `Update DB`
+    - `Build Theme`
+- `test`
+    - `Test Code Style`
+    - `Test PHPUnit`
+    - `Test Behat`
+    - `Test Backstop`
+- `deploy`
+    - `Deploy`
+
+### Using Ansible
+
+If you also use an [Ansible inventory](/ansible) for your hosts, you can of
+course integrate them into the GitLab pipelines too. To make this work, you
+need a separate GitLab runner tagged with `ansible` and a configuration
+like this:
+
+```
+[[runners]]
+  name = "Name of ansible runner"
+  url = "https://gitlab.lakedrops.com/"
+  token = "TOKEN"
+  executor = "docker"
+  environment = ["DOCKER_AUTH_CONFIG={\"auths\":{\"registry.lakedrops.com\":{\"auth\":\"YOURAUTHTOKEN\"}}}"]
+  [runners.custom_build_dir]
+  [runners.cache]
+    [runners.cache.s3]
+    [runners.cache.gcs]
+  [runners.docker]
+    tls_verify = false
+    hostname = "Ansible-INVENTORYNAME"
+    image = "registry.lakedrops.com/ansible-inventories/INVENTORYNAME:latest"
+    privileged = true
+    disable_entrypoint_overwrite = false
+    oom_kill_disable = false
+    disable_cache = false
+    volumes = ["/home/gitlab-runner/.ssh/id_rsa:/root/.ssh/id_rsa", "/home/gitlab-runner/.a/variables.yml:/root/.ansible/secrets", "/home/gitlab-runner/.a/inventories/INVENTORYNAME:/root
+/.ansible", "/etc/ansible.yml:/etc/ansible.yml", "/var/log/ansible:/var/log/ansible"]
+    pull_policy = "always"
+    shm_size = 0
+```
+
+The used placeholders in this example are:
+
+- `TOKEN`: the token of the GitLab runner being generated during setup.
+- `YOURAUTHTOKEN`: your auth token to the LakeDrops GitLab Docker registry.
+- `INVENTORYNAME`: the name of the Ansible inventory to be used.
+
+To learn more about the Ansible imeages for an inventory and how to setup some
+of the configuration files, please have a look into
+[Docker for Ansible](/docker/ansible).
+
+Once you have the GitLab runner for Ansible setup for the Drupal project,
+you can adjust your GitLab CI configuration:
+
+#### Using Ansible to Dump DB
+
+You can replace the task above with this simple instruction:
+
+```yaml
+Download DB:
+  extends: '.dumpdb'
+```
+
+#### Using Ansible for Deployment
+
+You need a couple of additional variables and then you can replace the deploy
+task above with this simple instruction:
+
+```yaml
+variables:
+  HOST_NAME: myhostname
+  SITE_NAME: mysiteid
+
+Deploy:
+  extends: '.deploy'
+```
+
+The host name needs to be set to how the destination host is known in the
+Ansible inventory, and the site name needs to be set to the ID of the Drupal
+site in your inventory.
+
+## Usage
+
+This chapter is incomplete so far and needs more attention.
+
+### Handling of the database
+
+To build and test your Drupal site prior to deployment, a database with content
+for this project is required and this is handled by the pipeline pretty smart.
+
+First, it needs to be decided, if a fresh dump of the database needs to be
+collected or if the already existing database from the previous pipeline run
+can be re-used. Here is how the prepared pipelines make that decision:
+
+A fresh database is being pulled if one of the following conditions apply,
+tested in the given order:
+
+- if the pipeline run for the master branch
+- if the commit message contains the string `[PULL_DB]`
+- if the variable `PULL_DB` is set to `yes`
+- if no database container from a previous pipeline exists
+- if the database from the previous pipeline doesn't contain any user data yet
+
+If a new database is required, the task `Download DB` in the `build` stage will
+create a dump and make it available as an artifact for subsequent tasks. The 
+task `Import DB` will then import that dump in the `prepare` stage.
+
+Otherwise, those two tasks will be skipped and the task `Update DB` will be
+executed in the `prepare` stage instead.
-- 
GitLab