Skip to content

Database, Build, Test and Deploy #169

Database, Build, Test and Deploy

Database, Build, Test and Deploy #169

# GitHub Actions configuration file.
#
# This configuration file uses a custom "container" executor to run the
# Docker stack to speed up the build process.
#;
#; Comments starting with '#;<' and '#;>' are internal Vortex comments
#; and will be removed during installation or update of Vortex.
name: Database, Build, Test and Deploy
on:
# Pushes to the following branches will trigger the workflow.
push:
branches:
- production
- main
- master
- develop
- release/**
- hotfix/**
- project/**
# Pull requests to the following branches will trigger the workflow.
pull_request:
types:
- opened
- synchronize
- reopened
branches:
- production
- main
- master
- develop
- release/**
- hotfix/**
- project/**
workflow_dispatch:
inputs:
enable_terminal:
type: boolean
description: 'Enable terminal session.'
required: false
default: false
#;< !PROVISION_USE_PROFILE
schedule:
- cron: '0 18 * * *'
#;> !PROVISION_USE_PROFILE
defaults:
run:
shell: bash
jobs:
#;< !PROVISION_USE_PROFILE
database:
runs-on: ubuntu-latest
container:
image: drevops/ci-runner:24.10.0
env:
TZ: Australia/Melbourne
TERM: xterm-256color
VORTEX_CONTAINER_REGISTRY_USER: ${{ secrets.VORTEX_CONTAINER_REGISTRY_USER }}
VORTEX_CONTAINER_REGISTRY_PASS: ${{ secrets.VORTEX_CONTAINER_REGISTRY_PASS }}
VORTEX_DEBUG: ${{ vars.VORTEX_DEBUG }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# How often to refresh the cache of the DB dump. Refer to `date` command.
VORTEX_CI_DB_CACHE_TIMESTAMP: +%Y%m%d
# Use previous database caches on this branch as a fallback if the above cache
# does not match (for example, the cache is available only from the previous
# day). If "no" is set, the cache will be rebuilt from scratch.
VORTEX_CI_DB_CACHE_FALLBACK: "yes"
# Which branch to use as a source of DB caches.
VORTEX_CI_DB_CACHE_BRANCH: "develop"
steps:
- name: Preserve $HOME set in the container
run: echo HOME=/root >> "$GITHUB_ENV" # @see https://github.com/actions/runner/issues/863
- name: Check out code
uses: actions/checkout@v4
- name: Process the codebase to run in CI
run: find . -name "docker-compose.yml" -print0 | xargs -0 -I {} sh -c "sed -i -e '/###/d' {} && sed -i -e 's/##//' {}"
- name: Create cache keys files for database caching
run: |
echo "${VORTEX_CI_DB_CACHE_BRANCH}" | tee db_cache_branch
echo "${VORTEX_CI_DB_CACHE_FALLBACK/no/"${GITHUB_RUN_NUMBER}"}" | tee db_cache_fallback
echo "yes" | tee db_cache_fallback_yes
date "${VORTEX_CI_DB_CACHE_TIMESTAMP}" | tee db_cache_timestamp
# Restore DB cache based on the cache strategy set by the cache keys below.
# Change 'v1' to 'v2', 'v3' etc., commit and push to force cache reset.
# Lookup cache based on the default branch and a timestamp. Allows
# to use cache from the very first build on the day (sanitized database dump, for example).
- name: Restore DB cache
uses: actions/cache/restore@v4
with:
path: .data
key: v24.9.0-db10-${{ hashFiles('db_cache_branch') }}-${{ hashFiles('db_cache_fallback') }}-${{ hashFiles('db_cache_timestamp') }}
# Fallback to caching by default branch name only. Allows to use
# cache from the branch build on the previous day.
restore-keys: |
v24.9.0-db10-${{ hashFiles('db_cache_branch') }}-${{ hashFiles('db_cache_fallback') }}-
- name: Download DB
run: |
VORTEX_DB_DOWNLOAD_SEMAPHORE=/tmp/download-db-success ./scripts/vortex/download-db.sh
echo "db_hash=${{ hashFiles('.data') }}" >> "$GITHUB_ENV"
timeout-minutes: 30
- name: Export DB
run: |
if [ ! -f /tmp/download-db-success ]; then echo "==> Database download semaphore file is missing. DB export will not proceed."; exit 0; fi
./scripts/vortex/login-container-registry.sh
docker compose up --detach
sleep 15
docker compose exec cli mkdir -p .data && docker compose cp -L .data/db.sql cli:/app/.data/db.sql
docker compose exec cli bash -c "VORTEX_PROVISION_POST_OPERATIONS_SKIP=1 ./scripts/vortex/provision.sh"
./scripts/vortex/export-db.sh db.sql
timeout-minutes: 30
# Save cache per default branch and the timestamp.
# The cache will not be saved if it already exists.
# Note that the cache fallback flag is enabled for this case in order
# to save cache even if the fallback is not used when restoring it.
- name: Save DB cache
uses: actions/cache/save@v4
if: env.db_hash != hashFiles('.data')
with:
path: .data
key: v24.9.0-db10-${{ hashFiles('db_cache_branch') }}-${{ hashFiles('db_cache_fallback_yes') }}-${{ hashFiles('db_cache_timestamp') }}
#;> !PROVISION_USE_PROFILE
build:
runs-on: ubuntu-latest
needs: database
#;< !PROVISION_USE_PROFILE
if: github.event_name != 'schedule'
#;> !PROVISION_USE_PROFILE
strategy:
matrix:
instance: [0, 1]
fail-fast: false
container:
image: drevops/ci-runner:24.10.0
env:
TZ: Australia/Melbourne
TERM: xterm-256color
VORTEX_CONTAINER_REGISTRY_USER: ${{ secrets.VORTEX_CONTAINER_REGISTRY_USER }}
VORTEX_CONTAINER_REGISTRY_PASS: ${{ secrets.VORTEX_CONTAINER_REGISTRY_PASS }}
VORTEX_DEBUG: ${{ vars.VORTEX_DEBUG }}
#;< !PROVISION_USE_PROFILE
# How often to refresh the cache of the DB dump. Refer to `date` command.
VORTEX_CI_DB_CACHE_TIMESTAMP: +%Y%m%d
# Use previous database caches on this branch as a fallback if the above cache
# does not match (for example, the cache is available only from the previous
# day). If "no" is set, the cache will be rebuilt from scratch.
VORTEX_CI_DB_CACHE_FALLBACK: "yes"
# Which branch to use as a source of DB caches.
VORTEX_CI_DB_CACHE_BRANCH: "develop"
#;> !PROVISION_USE_PROFILE
steps:
- name: Preserve $HOME set in the container
run: echo HOME=/root >> "$GITHUB_ENV" # @see https://github.com/actions/runner/issues/863
- name: Check out code
uses: actions/checkout@v4
- name: Process the codebase to run in CI
run: find . -name "docker-compose.yml" -print0 | xargs -0 -I {} sh -c "sed -i -e '/###/d' {} && sed -i -e 's/##//' {}"
#;< !PROVISION_USE_PROFILE
- name: Create cache keys files for database caching
run: |
echo "${VORTEX_CI_DB_CACHE_BRANCH}" | tee db_cache_branch
echo "yes" | tee db_cache_fallback_yes
date "${VORTEX_CI_DB_CACHE_TIMESTAMP}" | tee db_cache_timestamp
- name: Show cache key for database caching
run: echo 'v24.9.0-db10-${{ hashFiles('db_cache_branch') }}-${{ hashFiles('db_cache_fallback_yes') }}-${{ hashFiles('db_cache_timestamp') }}'
# Restore DB cache based on the cache strategy set by the cache keys below.
# Change 'v1' to 'v2', 'v3' etc., commit and push to force cache reset.
# Lookup cache based on the default branch and a timestamp. Allows
# to use cache from the very first build on the day (sanitized database dump, for example).
- name: Restore DB cache
uses: actions/cache/restore@v4
with:
path: .data
fail-on-cache-miss: true
# Use cached database from previous builds of this branch.
key: v24.9.0-db10-${{ hashFiles('db_cache_branch') }}-${{ hashFiles('db_cache_fallback_yes') }}-${{ hashFiles('db_cache_timestamp') }}
restore-keys: |
v24.9.0-db10-${{ hashFiles('db_cache_branch') }}-${{ hashFiles('db_cache_fallback_yes') }}-
#;> !PROVISION_USE_PROFILE
- name: Lint Dockerfiles with Hadolint
run: |
find .docker -name 'Dockerfile' -o -name '*.dockerfile' | while read -r file; do
echo "Linting ${file}" && cat "${file}" | docker run --rm -i hadolint/hadolint
done
continue-on-error: ${{ vars.VORTEX_CI_HADOLINT_IGNORE_FAILURE == '1' }}
- name: Login to container registry
run: ./scripts/vortex/login-container-registry.sh
- name: Build stack
run: docker compose up -d
- name: Export built codebase
if: matrix.instance == 0
run: |
mkdir -p "/tmp/workspace/code"
docker compose cp -L cli:"/app/." "/tmp/workspace/code"
- name: Upload exported codebase as artifact
uses: actions/upload-artifact@v4
if: matrix.instance == 0
with:
name: code-artifact
path: "/tmp/workspace/code"
include-hidden-files: true
if-no-files-found: error
- name: Validate Composer configuration
run: docker compose exec cli composer validate --strict
continue-on-error: ${{ vars.VORTEX_CI_COMPOSER_VALIDATE_IGNORE_FAILURE == '1' }}
- name: Install development dependencies
run: |
docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli bash -c " \
if [ -n \"${GITHUB_TOKEN:-}\" ]; then export COMPOSER_AUTH='{\"github-oauth\": {\"github.com\": \"${GITHUB_TOKEN-}\"}}'; fi && \
COMPOSER_MEMORY_LIMIT=-1 composer --ansi install --prefer-dist"
- name: Validate Composer configuration normalised
run: docker compose exec -T cli composer normalize --dry-run
continue-on-error: ${{ vars.VORTEX_CI_COMPOSER_NORMALIZE_IGNORE_FAILURE == '1' }}
- name: Lint code with PHPCS
run: docker compose exec -T cli vendor/bin/phpcs
continue-on-error: ${{ vars.VORTEX_CI_PHPCS_IGNORE_FAILURE == '1' }}
- name: Lint code with PHPStan
run: docker compose exec -T cli vendor/bin/phpstan
continue-on-error: ${{ vars.VORTEX_CI_PHPSTAN_IGNORE_FAILURE == '1' }}
- name: Lint code with Rector
run: docker compose exec -T cli vendor/bin/rector --clear-cache --dry-run
continue-on-error: ${{ vars.VORTEX_CI_RECTOR_IGNORE_FAILURE == '1' }}
- name: Lint code with PHPMD
run: docker compose exec -T cli vendor/bin/phpmd . text phpmd.xml
continue-on-error: ${{ vars.VORTEX_CI_PHPMD_IGNORE_FAILURE == '1' }}
- name: Lint code with Twig CS Fixer
run: docker compose exec -T cli vendor/bin/twig-cs-fixer
continue-on-error: ${{ vars.VORTEX_CI_TWIG_CS_FIXER_IGNORE_FAILURE == '1' }}
- name: Lint code with Gherkin Lint
run: docker compose exec -T cli vendor/bin/gherkinlint lint tests/behat/features
continue-on-error: ${{ vars.VORTEX_CI_GHERKIN_LINT_IGNORE_FAILURE == '1' }}
- name: Lint code with NPM linters
run: docker compose exec -T cli bash -c "npm run --prefix \${VORTEX_WEBROOT}/themes/custom/\${DRUPAL_THEME} lint"
continue-on-error: ${{ vars.VORTEX_CI_NPM_LINT_IGNORE_FAILURE == '1' }}
- name: Provision site
run: |
if [ -f .data/db.sql ]; then
docker compose exec cli mkdir -p .data
docker compose cp -L .data/db.sql cli:/app/.data/db.sql
fi
docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli ./scripts/vortex/provision.sh
timeout-minutes: 30
- name: Test with PHPUnit
run: |
XDEBUG_ENABLE=true docker compose up -d cli php nginx # Restart stack with XDEBUG enabled for coverage.
docker compose exec -T -e XDEBUG_MODE=coverage cli vendor/bin/phpunit
docker compose up -d cli php nginx # Restart stack without XDEBUG enabled for coverage.
continue-on-error: ${{ vars.VORTEX_CI_PHPUNIT_IGNORE_FAILURE == '1' }}
- name: Test with Behat
run: |
# shellcheck disable=SC2170
if [ ${{ strategy.job-total }} -gt 1 ]; then export VORTEX_CI_BEHAT_PROFILE="${VORTEX_CI_BEHAT_PROFILE:-p${{ strategy.job-index }}}"; fi
echo "Running with ${VORTEX_CI_BEHAT_PROFILE:-default} profile"
docker compose exec -T cli php -d memory_limit=-1 vendor/bin/behat --colors --strict --profile="${VORTEX_CI_BEHAT_PROFILE:-default}" || \
docker compose exec -T cli php -d memory_limit=-1 vendor/bin/behat --colors --strict --rerun --profile="${VORTEX_CI_BEHAT_PROFILE:-default}"
env:
VORTEX_CI_BEHAT_PROFILE: ${{ vars.VORTEX_CI_BEHAT_PROFILE }}
continue-on-error: ${{ vars.VORTEX_CI_BEHAT_IGNORE_FAILURE == '1' }}
timeout-minutes: 30
- name: Process test logs and artifacts
if: always()
run: |
mkdir -p ".logs"
if docker compose ps --services --filter "status=running" | grep -q cli && docker compose exec cli test -d /app/.logs; then
docker compose cp cli:/app/.logs/. ".logs/"
fi
- name: Upload test artifacts
uses: actions/upload-artifact@v4
with:
name: test-artifacts-${{ matrix.instance }}
path: .logs
include-hidden-files: true
if-no-files-found: error
- name: Upload coverage report to Codecov
uses: codecov/codecov-action@v4
if: ${{ env.CODECOV_TOKEN != '' }}
with:
directory: .logs/coverage
fail_ci_if_error: true
token: ${{ secrets.CODECOV_TOKEN }}
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
- name: Setup tmate session
if: ${{ !cancelled() && github.event.inputs.enable_terminal }}
uses: mxschmitt/action-tmate@v3
timeout-minutes: 120 # Cancel the action after 15 minutes, regardless of whether a connection has been established.
with:
detached: true
#;< DEPLOYMENT
deploy:
runs-on: ubuntu-latest
needs: build
#;< !PROVISION_USE_PROFILE
if: github.event_name != 'schedule'
#;> !PROVISION_USE_PROFILE
container:
image: drevops/ci-runner:24.10.0
env:
TZ: Australia/Melbourne
TERM: xterm-256color
VORTEX_DEBUG: ${{ vars.VORTEX_DEBUG }}
steps:
- name: Preserve $HOME set in the container
run: echo HOME=/root >> "$GITHUB_ENV" # @see https://github.com/actions/runner/issues/863
- name: Checkout code
uses: actions/checkout@v4
with:
# Fetch all history for git repository.
fetch-depth: 0
# Do not persist credentials after checkout
# to allow using the custom credentials to push to a remote repo.
persist-credentials: false
ref: ${{ github.head_ref || github.ref_name }}
- name: Download exported codebase as an artifact
uses: actions/download-artifact@v4
with:
name: code-artifact
path: "/tmp/workspace/code"
- name: Add SSH private key to the runner
if: ${{ env.VORTEX_DEPLOY_SSH_PRIVATE_KEY != '' }}
uses: shimataro/ssh-key-action@v2
with:
key: ${{ secrets.VORTEX_DEPLOY_SSH_PRIVATE_KEY }}
known_hosts: ${{ secrets.VORTEX_DEPLOY_SSH_KNOWN_HOSTS }}
env:
VORTEX_DEPLOY_SSH_PRIVATE_KEY: ${{ secrets.VORTEX_DEPLOY_SSH_PRIVATE_KEY }}
- name: Deploy
run: ./scripts/vortex/deploy.sh
env:
# Get branch for PR from 'head_ref' or for branch from 'ref_name'.
VORTEX_DEPLOY_BRANCH: ${{ github.head_ref || github.ref_name }}
VORTEX_DEPLOY_PR: ${{ github.event.number }}
VORTEX_DEPLOY_PR_HEAD: ${{ github.sha }}
VORTEX_DEPLOY_ARTIFACT_SRC: /tmp/workspace/code
VORTEX_DEPLOY_ARTIFACT_ROOT: ${{ github.workspace }}
VORTEX_DEPLOY_ARTIFACT_GIT_REMOTE: ${{ vars.VORTEX_DEPLOY_ARTIFACT_GIT_REMOTE }}
VORTEX_DEPLOY_ARTIFACT_GIT_USER_EMAIL: ${{ vars.VORTEX_DEPLOY_ARTIFACT_GIT_USER_EMAIL }}
VORTEX_DEPLOY_ARTIFACT_GIT_USER_NAME: ${{ vars.VORTEX_DEPLOY_ARTIFACT_GIT_USER_NAME }}
timeout-minutes: 30
#;> DEPLOYMENT