Skip to content

Build, Test, Push

Build, Test, Push #886

Workflow file for this run

name: Build, Test, Push
on:
schedule:
- cron: "0 10 * * 0" # Every Sunday at 10AM
push:
branches:
- master
- develop
- feature/*
tags:
- "v*.*.*"
workflow_dispatch: # Allow manually triggering a build
defaults:
run:
shell: bash
env:
IMAGE: docksal/cli
UPSTREAM_IMAGE: debian
LATEST_VERSION: "8.3"
DOCKSAL_VERSION: develop
jobs:
build:
name: "Build: ${{ matrix.version }}/${{ matrix.arch }}"
runs-on: ubuntu-22.04
strategy:
fail-fast: false # Don't cancel other jobs if one fails
matrix:
include:
-
platform: linux/amd64
arch: amd64
version: "8.1"
-
platform: linux/amd64
arch: amd64
version: "8.2"
-
platform: linux/amd64
arch: amd64
version: "8.3"
-
platform: linux/arm64
arch: arm64
version: "8.1"
-
platform: linux/arm64
arch: arm64
version: "8.2"
-
platform: linux/arm64
arch: arm64
version: "8.3"
env:
ARCH: ${{ matrix.arch }}
VERSION_PREFIX: php
VERSION: ${{ matrix.version }}
steps:
-
name: Checkout
uses: actions/checkout@v4
-
name: Environment variables
run: |
# Export variables for further steps
echo GIT_SHA7="${GITHUB_SHA:0:7}" | tee -a ${GITHUB_ENV}
echo BUILD_DIR="${VERSION:-.}" | tee -a ${GITHUB_ENV}
echo BUILD_IMAGE_TAG="${IMAGE}:${VERSION_PREFIX}${VERSION}-build" | tee -a ${GITHUB_ENV}
# Pull the host public SSH key at runtime instead of relying on a static value stored in secrets.
echo ARM64_HOST_SSH_CERT="$(ssh-keyscan -t rsa ${{ secrets.ARM64_HOST }} 2>/dev/null)" | tee -a ${GITHUB_ENV}
-
# Switch docker context to a remote arm64 host
# Used for building heavy images that take too long to build using QEMU + for native arm64 testing.
name: Switch to arm64 builder host
if: ${{ env.ARCH == 'arm64' }}
uses: docksal/actions/docker-context@main
with:
docker_host: "ssh://build-agent@${{ secrets.ARM64_HOST }}"
context_name: arm64-host
ssh_key: "${{ secrets.ARM64_HOST_SSH_KEY }}"
ssh_cert: "${{ env.ARM64_HOST_SSH_CERT }}"
use_context: true
-
name: Check Docker
run: |
docker version
docker info
-
name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
-
# Build and cache image in the registry
name: Build image
uses: docker/build-push-action@v5
with:
context: ${{ env.BUILD_DIR }}
file: ${{ env.BUILD_DIR }}/Dockerfile
build-args: VERSION=${{ env.VERSION }}
# Push intermediate arch-specific build tag to repo
tags: ${{ env.BUILD_IMAGE_TAG }}-${{ env.GIT_SHA7 }}-${{ env.ARCH }}
push: ${{ github.event_name != 'pull_request' }} # Don't push for PRs
# BUILD_IMAGE_TAG - persistent multi-arch tag, updated at the end of the build (success or failure)
cache-from: type=registry,ref=${{ env.BUILD_IMAGE_TAG }}
cache-to: type=inline # Write the cache metadata into the image configuration
test:
name: "Test: ${{ matrix.version }}/${{ matrix.arch }}"
runs-on: ubuntu-22.04
needs: build
strategy:
fail-fast: false # Don't cancel other jobs if one fails
matrix:
include:
-
platform: linux/amd64
arch: amd64
version: "8.1"
-
platform: linux/amd64
arch: amd64
version: "8.2"
-
platform: linux/amd64
arch: amd64
version: "8.3"
-
platform: linux/arm64
arch: arm64
version: "8.1"
-
platform: linux/arm64
arch: arm64
version: "8.2"
-
platform: linux/arm64
arch: arm64
version: "8.3"
env:
ARCH: ${{ matrix.arch }}
VERSION_PREFIX: php
VERSION: ${{ matrix.version }}
steps:
-
name: Setup Bats
uses: bats-core/[email protected]
-
name: Checkout
uses: actions/checkout@v4
-
name: Environment variables
run: |
# Export variables for further steps
echo GIT_SHA7="${GITHUB_SHA:0:7}" | tee -a ${GITHUB_ENV}
echo BUILD_DIR="${VERSION:-.}" | tee -a ${GITHUB_ENV}
echo BUILD_IMAGE_TAG="${IMAGE}:${VERSION_PREFIX}${VERSION}-build" | tee -a ${GITHUB_ENV}
# Pull the host public SSH key at runtime instead of relying on a static value stored in secrets.
echo ARM64_HOST_SSH_CERT="$(ssh-keyscan -t rsa ${{ secrets.ARM64_HOST }} 2>/dev/null)" | tee -a ${GITHUB_ENV}
-
# Switch docker context to a remote arm64 host
# Used for building heavy images that take too long to build using QEMU + for native arm64 testing.
name: Switch to arm64 builder host
if: ${{ env.ARCH == 'arm64' }}
uses: docksal/actions/docker-context@main
with:
docker_host: "ssh://build-agent@${{ secrets.ARM64_HOST }}"
context_name: arm64-host
ssh_key: "${{ secrets.ARM64_HOST_SSH_KEY }}"
ssh_cert: "${{ env.ARM64_HOST_SSH_CERT }}"
use_context: true
-
name: Check Docker
run: |
docker version
docker info
-
# Run tests
name: Test
id: tests
working-directory: ${{ env.BUILD_DIR }}
env:
BUILD_IMAGE_TAG: ${{ env.BUILD_IMAGE_TAG }}-${{ env.GIT_SHA7 }}-${{ env.ARCH }}
SECRET_PLATFORMSH_CLI_TOKEN: ${{ secrets.SECRET_PLATFORMSH_CLI_TOKEN }}
SECRET_TERMINUS_TOKEN: ${{ secrets.SECRET_TERMINUS_TOKEN }}
run: |
make test
([[ $? == 0 ]] && echo "pass" || echo "fail") | tee ${{ github.workspace }}/test-results-${VERSION_PREFIX}${VERSION}-${ARCH}.txt
# Store tests results as an artifact (used by downstream jobs)
# Note: Cannot use "::set-output name=var_name::var_value" as var_name would need to be dynamic here.
# Dynamic variable names cannot be used when mapping step outputs to job outputs.
# Step outputs cannot be accessed directly from other jobs. Dead end.
- name: Store test results
uses: actions/upload-artifact@v4
with:
name: test-results-${{ env.GIT_SHA7 }}-${{ env.VERSION_PREFIX }}${{ env.VERSION }}-${{ env.ARCH }}
path: ${{ github.workspace }}/test-results-*.txt
if-no-files-found: error
overwrite: true
push:
name: "Push: ${{ matrix.version }}/multi"
runs-on: ubuntu-22.04
# Wait for test to either succeed or fail
needs: test
if: always()
strategy:
matrix:
version:
- "8.1"
- "8.2"
- "8.3"
env:
VERSION_PREFIX: php
VERSION: ${{ matrix.version }}
steps:
-
name: Checkout
uses: actions/checkout@v4
-
name: Environment variables
run: |
# Export variables for further steps
echo GIT_SHA7="${GITHUB_SHA:0:7}" | tee -a ${GITHUB_ENV}
echo BUILD_DIR="${VERSION:-.}" | tee -a ${GITHUB_ENV}
echo BUILD_IMAGE_TAG="${IMAGE}:${VERSION_PREFIX}${VERSION}-build" | tee -a ${GITHUB_ENV}
-
# Login to Docker Hub
name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
-
name: Retrieve test results
uses: actions/download-artifact@v4
with:
pattern: test-results-${{ env.GIT_SHA7 }}-*
merge-multiple: true
-
# Generate persistent tags (edge, stable, release)
name: Docker image tags
id: docker_tags
# Don't push broken builds to persistent tags (both amd64 and arm64 tests must pass)
run: |
amd64_tests=$(cat test-results-${VERSION_PREFIX}${VERSION}-amd64.txt)
arm64_tests=$(cat test-results-${VERSION_PREFIX}${VERSION}-arm64.txt)
if [[ "${amd64_tests}" == "pass" ]] && [[ "${arm64_tests}" == "pass" ]]; then
.github/scripts/docker-tags.sh
fi
-
# Create and push multi-arch image manifests
name: Push multi-arch images
env:
# build tags are always pushed (build caching, debugging needs)
# edge, stage, release are only pushed if tests were successful (see docker_tags step)
TAGS: |
${{ env.BUILD_IMAGE_TAG }}
${{ steps.docker_tags.outputs.tags }}
DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }} # Needed for docker-tag-delete.sh
DOCKERHUB_PASSWORD: ${{ secrets.DOCKERHUB_PASSWORD }} # Needed for docker-tag-delete.sh
run: |
set -xeuo pipefail
IFS="${IFS}," # Also split strings by comma (in case list of tag is comma-separated)
for tag in ${TAGS}; do
if [[ "${tag}" == "" ]]; then continue; fi
docker manifest create --amend ${tag} \
${{ env.BUILD_IMAGE_TAG }}-${{ env.GIT_SHA7 }}-amd64 \
${{ env.BUILD_IMAGE_TAG }}-${{ env.GIT_SHA7 }}-arm64
docker manifest inspect ${tag}
docker manifest push ${tag}
done
# Clean up intermediate arch-specific image tags (DockerHub only)
.github/scripts/docker-tag-delete.sh "${{ env.BUILD_IMAGE_TAG }}-${{ env.GIT_SHA7 }}-amd64"
.github/scripts/docker-tag-delete.sh "${{ env.BUILD_IMAGE_TAG }}-${{ env.GIT_SHA7 }}-arm64"