Skip to content

feat(ci): Docker build rework #25

feat(ci): Docker build rework

feat(ci): Docker build rework #25

Workflow file for this run

name: Docker Build
on:
pull_request:
branches: [main, 'release-*', 'pre-release-*']
push:
branches: [main, 'release-*', 'pre-release-*']
workflow_dispatch:
inputs:
projects:
description: 'Comma-separated list of project names to build.'
required: true
concurrency:
group: docker-build-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
defaults:
run:
shell: bash -euo pipefail {0}
env:
PUSH_REGISTRY: ${{ vars.PUSH_REGISTRY }}
jobs:
prepare:
name: Prepare workflow Docker build
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
node_image_tag: ${{ steps.build-args.outputs.node_image_tag }}
docker_registry: ${{ steps.build-args.outputs.docker_registry }}
steps:
- uses: actions/checkout@v4
- name: Build arg prep
id: build-args
run: |
echo node_image_tag="$(./scripts/ci/get-node-version.mjs)" >>"$GITHUB_OUTPUT"
- name: Create matrix from input
id: set-matrix
env:
localrun: ${{ !!github.event.localrun }}
run: |
if [[ ${localrun} == true ]]; then
output="matrix=$(
echo '{
"include":[
{"project":"web","docker":"next"},
{"project":"api","docker":"nest"},
{"project":"service-portal","docker":"static"}
]
}' | jq -c
)"
echo "$output" >>"$GITHUB_OUTPUT"
exit 0
fi
# Create a list of objects of the form:
# [
# {
# "name": "services-my-service",
# "docker": "next|nest|mytype"
# },
# ...
# ]
echo "matrix=$(git ls-files '**/project.json' |
xargs cat | \
jq -s -c '{ include: [
.[]
| {
project: .name,
docker: (.targets | keys | map(select(startswith("docker-") and . != "docker-native")) | map(sub("^docker-"; "")) | .[])
}
]
}')" >>"$GITHUB_OUTPUT"
build:
name: Build ${{ matrix.project }}
runs-on: ubuntu-latest
needs: prepare
strategy:
fail-fast: true
matrix: ${{ fromJson(needs.prepare.outputs.matrix) }}
permissions:
id-token: write # This is required for requesting the JWT
contents: read # This is required for actions/checkout
steps:
- name: Prepare and debug inputs
id: inputs
env:
# Append a slash when PUSH_REGISTRY is non-empty
registry: "${{ env.PUSH_REGISTRY }}${{ env.PUSH_REGISTRY && '/' || '' }}"
# We don't use a repository prefix, just the raw project
# repository: '${{ github.repository }}/${{ matrix.project }}'
repository: '${{ matrix.project }}'
run: |
image_repository="$registry$repository"
echo "Labels: ${{ toJSON(github.event.pull_request.labels) }}"
echo "Matrix: ${{ toJSON(matrix) }}"
echo image_repository="$image_repository" >>"$GITHUB_OUTPUT"
if [[ ${{ github.event.localrun == 'true' }} ]]; then
echo build_cache="type=local,src=./build-cache" >>"$GITHUB_OUTPUT"
else
echo build_cache="type=registry,ref=$image_repository:cache" >>"$GITHUB_OUTPUT"
fi
- name: Check out repo
uses: actions/checkout@v4
- name: Configure AWS Credentials
if: ${{ !github.event.localrun && env.PUSH_REGISTRY && env.PUSH_REGISTRY != 'ghcr.io' }}
id: aws-creds
uses: aws-actions/configure-aws-credentials@v4
with:
role-session-name: docker-build
aws-region: ${{ vars.AWS_REGION }}
# Identical to usage in push.yml
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
# Use this instead of aws-{access,secret}, but needs proper roles & policies
# role-to-assume: ${{ vars.AWS_ECR_ROLE }}
- name: Log in to Amazon ECR
if: ${{ steps.aws-creds.conclusion == 'success' }}
id: ecr-login
uses: aws-actions/amazon-ecr-login@v2
- name: Log in to Docker
if: ${{ !github.event.localrun && env.PUSH_REGISTRY == 'ghcr.io' }}
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
with:
driver: docker-container
# driver-opts: image=moby/buildkit:buildx-stable-1
install: true
use: true
- name: Generate Docker metadata
id: meta
uses: docker/metadata-action@v5
with:
images: |
${{ steps.inputs.outputs.image_repository }}
tags: |
type=ref,event=branch
# Git SHA
type=sha,format=short
type=sha,format=long
# SemVer by tag (e.g. v1.2.3)
type=semver,pattern={{version}}
- name: Build and push Docker image
uses: docker/build-push-action@v6
with:
context: .
file: scripts/ci/Dockerfile
push: ${{ !github.event.localrun }}
labels: ${{ steps.meta.outputs.labels }}
tags: ${{ steps.meta.outputs.tags }}
target: output-${{ matrix.docker }}
build-args: |
NODE_IMAGE_TAG=${{ needs.prepare.outputs.node_image_tag }}
status:
name: Collect statuses
runs-on: ubuntu-latest
if: ${{ always() }}
needs:
- prepare
- build
steps:
- name: Check statuses
env:
dependencies: ${{ toJSON(needs) }}
run: |
# Debug inputs
echo "$dependencies" | jq
echo "# Summary report" >>"$GITHUB_STEP_SUMMARY"
echo "|job|result|" >>"$GITHUB_STEP_SUMMARY"
echo "|---|------|" >>"$GITHUB_STEP_SUMMARY"
success=true
# Loop through each job and ensure .result == "success"
for job in $(echo "$dependencies" | jq -r 'keys[]'); do
result=$(echo "$dependencies" | jq -r ".[\"$job\"].result")
echo "Job $job => $result"
echo "|$job|$result $([[ "$result" == "success" ]] && echo "✅" || echo "❌")|" >>"$GITHUB_STEP_SUMMARY"
if [ "$result" != "success" ]; then
success=false
fi
done
if [[ success != true ]]; then
exit 1
fi
echo "All dependencies succeeded!"