Skip to content

build: refactor container build process #3585

build: refactor container build process

build: refactor container build process #3585

Workflow file for this run

name: Containers
# Build containers when pushed to master or if a pull request has been labeled with "container"
on:
push:
branches:
- master
pull_request:
branches:
- master
types: [labeled, synchronize, opened]
jobs:
setup:
# Determine if any containers need to be built and what tags they will result in
name: Setup container tags
runs-on: ubuntu-latest
outputs:
# Version information
# v7.0.0
version: ${{ steps.version.outputs.version }}
# v7
version_major: ${{ steps.version.outputs.version_major }}
# v7.1
version_major_minor: ${{ steps.version.outputs.version_major_minor }}
# Tagging information as a JSON object
# eg { cli: ["ghcr.io/linz/basemaps/cli:latest", "ghcr.io/linz/basemaps/cli:v7"], needs_containers: true }
tags: ${{ steps.tags.outputs.result }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup tags
id: version
run: |
GIT_VERSION=$(git describe --tags --always --match 'v*')
GIT_VERSION_MAJOR=$(echo $GIT_VERSION | cut -d. -f1)
GIT_VERSION_MAJOR_MINOR=$(echo $GIT_VERSION | cut -d. -f1,2)
echo "version=${GIT_VERSION}" >> $GITHUB_OUTPUT
echo "version_major=${GIT_VERSION_MAJOR}" >> $GITHUB_OUTPUT
echo "version_major_minor=${GIT_VERSION_MAJOR_MINOR}" >> $GITHUB_OUTPUT
- name: Create Image Tags
id: tags
uses: actions/github-script@v7
with:
script: |
// Images to create tags for
const images = ['cli', 'server'];
// Mapping of images to their tags
// cli => "ghcr.io/linz/basemaps/cli:latest,ghcr.io/linz/basemaps/cli:v7"
const output = {};
// List of tags to apply to images, eg "v7" or "latest"
const tags = [];
// If on master ensure that the "latest" and a specific tag version is used
if ('${{ github.ref }}' == 'refs/heads/master' ){
tags.push('latest');
// If on a release commit add `v7`, `v7.1` and `v7.1`
if (`${{ toJson(github.event.head_commit.message) }}`.startsWith('release:')) {
tags.push('${{ steps.version.outputs.version_major }}');
tags.push('${{ steps.version.outputs.version_major_minor }}');
}
tags.push('${{ steps.version.outputs.version }}');
}
// If a pull request is labeled as "container", ensure a pull request tag is created
// "ghcr.io/linz/basemaps/cli:pr-1124"
const labels = ${{ toJson(github.event.pull_request.labels.*.name) }}
if (labels.includes('container')) {
tags.push('pr-${{ github.event.number }}')
}
for (const img of images) {
const repo = `ghcr.io/${{ github.repository }}/${img}`
output[img] = JSON.stringify(tags.map(t => `${repo}:${t}`))
}
// Have any tags been created
output.needs_containers = tags.length > 0;
return output;
- name: List tags
run: |
echo ${{ toJson(steps.tags.outputs.result) }} | jq
build-containers:
needs: setup
if: ${{ fromJson(needs.setup.outputs.tags).needs_containers == true }}
runs-on: ${{ matrix.os }}
strategy:
matrix:
include:
- os: ubuntu-latest
arch: amd64
platform: linux/amd64
- os: ubuntu-24.04-arm
arch: arm64
platform: linux/arm64
permissions:
id-token: write
contents: read
packages: write
steps:
- uses: linz/action-typescript@v3
- name: (Prod) Ensure tag exists
if: github.ref == 'refs/heads/master' && startsWith(github.event.head_commit.message, 'release:')
run: |
git fetch --depth=1 origin +refs/tags/*:refs/tags/* # see https://stackoverflow.com/a/60184319/9285308
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
CURRENT_VERSION=$(node -p "require('./lerna.json').version")
git tag v${CURRENT_VERSION} -m v${CURRENT_VERSION} || true # Only create the tag if it doesn't exist
- name: Bundle & Package all files
run: |
npx lerna run bundle --stream
npm pack --workspaces
env:
NODE_ENV: 'production'
- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v3
- name: Copy packages and files
run: |
# Files are packed into the base directory
cp *.tgz packages/server/
cp *.tgz packages/cli/
cp -r packages/lambda-tiler/static/ packages/server/
cp -r packages/lambda-tiler/static/ packages/cli/
- name: Create docker metadata
id: meta
uses: docker/metadata-action@v5
with:
labels:
org.opencontainers.image.version=${{ needs.setup.outputs.version }}
org.opencontainers.image.licenses=MIT
tags: |
type=sha
- name: Login to GitHub Container Registry
uses: docker/login-action@v3 # v3
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: 'Build Container - @basemaps/cli'
uses: docker/build-push-action@v6
id: 'build_cli'
with:
context: packages/cli
labels: ${{ steps.meta.outputs.labels }}
outputs: type=image,"name=ghcr.io/${{ github.repository }}/cli",push-by-digest=true,push=true
build-args: |
GIT_HASH=${{ github.sha }}
GIT_VERSION=${{ needs.setup.outputs.version }}
GITHUB_RUN_ID=${{ github.run_id }}
- name: 'Build Container - @basemaps/server'
uses: docker/build-push-action@v6
id: 'build_server'
with:
context: packages/server
labels: ${{ steps.meta.outputs.labels }}
outputs: type=image,"name=ghcr.io/${{ github.repository }}/server",push-by-digest=true,push=true
build-args: |
GIT_HASH=${{ github.sha }}
GIT_VERSION=${{ needs.setup.outputs.version }}
GITHUB_RUN_ID=${{ github.run_id }}
- name: Export digests
run: |
mkdir -p ${{ runner.temp }}/digests/cli ${{ runner.temp }}/digests/server
digest="${{ steps.build_cli.outputs.digest }}"
touch "${{ runner.temp }}/digests/cli/${digest#sha256:}"
digest="${{ steps.build_server.outputs.digest }}"
touch "${{ runner.temp }}/digests/server/${digest#sha256:}"
- name: Upload digest
uses: actions/upload-artifact@v4
with:
name: digests-${{ matrix.arch }}
path: ${{ runner.temp }}/digests/*
if-no-files-found: error
retention-days: 1
merge:
# Find all the containers built from the matrix jobs then tag and publish them
name: Merge and publish containers
permissions:
id-token: write
contents: read
packages: write
runs-on: ubuntu-latest
needs:
- build-containers
- setup
steps:
- name: Download digests
uses: actions/download-artifact@v4
with:
path: ${{ runner.temp }}/digests
pattern: digests-*
merge-multiple: true
- name: Show digests
working-directory: ${{ runner.temp }}/digests
run:
ls -R .
- name: Login to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Create manifest list and push
working-directory: ${{ runner.temp }}/digests
run: |
cd cli
docker buildx imagetools create $(jq -cr '. | map("-t " + .) | join(" ")' <<< '${{ fromJson(needs.setup.outputs.tags).cli }}') \
$(printf 'ghcr.io/${{ github.repository }}/cli@sha256:%s ' *)
cd ../server/
docker buildx imagetools create $(jq -cr '. | map("-t " + .) | join(" ")' <<< '${{ fromJson(needs.setup.outputs.tags).server }}') \
$(printf 'ghcr.io/${{ github.repository }}/server@sha256:%s ' *)