Build, Test, Push #827
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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/bats-action@2.0.0 | |
- | |
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" |