1
0
Fork 0
mirror of https://forgejo.ellis.link/continuwuation/continuwuity.git synced 2025-09-15 17:26:58 +00:00

ci: Split Docker builds into sequential release and max-perf stages

Separate fast release builds from slow max-perf builds to optimise runner
utilisation and provide quicker feedback. Release builds complete first with
standard optimisations, followed by Haswell-optimised dragrace builds once
the safe builds pass successfully.

Extract build logic into focused composite actions for better log visibility
in Forgejo UI. Split monolithic build action into prepare-docker-build,
inline docker build step, and upload-docker-artifacts to ensure each phase
completes independently and shows logs immediately.

Creates separate manifests at each stage to avoid waiting for all builds
before publishing.
This commit is contained in:
Tom Foster 2025-09-12 10:45:06 +01:00
parent 9c147b182f
commit 542dff50bd
4 changed files with 461 additions and 249 deletions

View file

@ -0,0 +1,104 @@
name: create-manifest
description: |
Create and push a multi-platform Docker manifest from individual platform digests.
Handles downloading digests, creating manifest lists, and pushing to registry.
inputs:
digest_pattern:
description: Glob pattern to match digest artifacts (e.g. "digests-linux-{amd64,arm64}")
required: true
tag_suffix:
description: Suffix to add to all Docker tags (e.g. "-maxperf")
required: false
default: ""
images:
description: Container registry images (newline-separated)
required: true
registry_user:
description: Registry username for authentication
required: false
registry_password:
description: Registry password for authentication
required: false
outputs:
version:
description: The version tag created for the manifest
value: ${{ steps.meta.outputs.version }}
tags:
description: All tags created for the manifest
value: ${{ steps.meta.outputs.tags }}
runs:
using: composite
steps:
- name: Download digests
if: ${{ env.BUILTIN_REGISTRY_ENABLED == 'true' }}
uses: forgejo/download-artifact@v4
with:
path: /tmp/digests
pattern: ${{ inputs.digest_pattern }}
merge-multiple: true
- name: Login to builtin registry
if: ${{ env.BUILTIN_REGISTRY_ENABLED == 'true' }}
uses: docker/login-action@v3
with:
registry: ${{ env.BUILTIN_REGISTRY }}
username: ${{ inputs.registry_user }}
password: ${{ inputs.registry_password }}
- name: Set up Docker Buildx
if: ${{ env.BUILTIN_REGISTRY_ENABLED == 'true' }}
uses: docker/setup-buildx-action@v3
with:
# Use persistent BuildKit if BUILDKIT_ENDPOINT is set (e.g. tcp://buildkit:8125)
driver: ${{ env.BUILDKIT_ENDPOINT != '' && 'remote' || 'docker-container' }}
endpoint: ${{ env.BUILDKIT_ENDPOINT || '' }}
- name: Extract metadata (tags) for Docker
if: ${{ env.BUILTIN_REGISTRY_ENABLED == 'true' }}
id: meta
uses: docker/metadata-action@v5
with:
tags: |
type=semver,pattern={{version}},prefix=v,suffix=${{ inputs.tag_suffix }}
type=semver,pattern={{major}}.{{minor}},enable=${{ !startsWith(github.ref, 'refs/tags/v0.0.') }},prefix=v,suffix=${{ inputs.tag_suffix }}
type=semver,pattern={{major}},enable=${{ !startsWith(github.ref, 'refs/tags/v0.') }},prefix=v,suffix=${{ inputs.tag_suffix }}
type=ref,event=branch,prefix=${{ format('refs/heads/{0}', github.event.repository.default_branch) != github.ref && 'branch-' || '' }},suffix=${{ inputs.tag_suffix }}
type=ref,event=pr,suffix=${{ inputs.tag_suffix }}
type=sha,format=short,suffix=${{ inputs.tag_suffix }}
type=raw,value=latest${{ inputs.tag_suffix }},enable=${{ startsWith(github.ref, 'refs/tags/v') }}
images: ${{ inputs.images }}
# default labels & annotations: https://github.com/docker/metadata-action/blob/master/src/meta.ts#L509
env:
DOCKER_METADATA_ANNOTATIONS_LEVELS: index
- name: Create manifest list and push
if: ${{ env.BUILTIN_REGISTRY_ENABLED == 'true' }}
working-directory: /tmp/digests
shell: bash
env:
IMAGES: ${{ inputs.images }}
run: |
IFS=$'\n'
IMAGES_LIST=($IMAGES)
ANNOTATIONS_LIST=($DOCKER_METADATA_OUTPUT_ANNOTATIONS)
TAGS_LIST=($DOCKER_METADATA_OUTPUT_TAGS)
for REPO in "${IMAGES_LIST[@]}"; do
docker buildx imagetools create \
$(for tag in "${TAGS_LIST[@]}"; do echo "--tag"; echo "$tag"; done) \
$(for annotation in "${ANNOTATIONS_LIST[@]}"; do echo "--annotation"; echo "$annotation"; done) \
$(for reference in *; do printf "$REPO@sha256:%s\n" $reference; done)
done
- name: Inspect image
if: ${{ env.BUILTIN_REGISTRY_ENABLED == 'true' }}
shell: bash
env:
IMAGES: ${{ inputs.images }}
run: |
IMAGES_LIST=($IMAGES)
for REPO in "${IMAGES_LIST[@]}"; do
docker buildx imagetools inspect $REPO:${{ steps.meta.outputs.version }}
done

View file

@ -0,0 +1,169 @@
name: prepare-docker-build
description: |
Prepare the Docker build environment for Continuwuity builds.
Sets up Rust toolchain, Docker Buildx, caching, and extracts metadata for Docker builds.
inputs:
platform:
description: Target platform (e.g. linux/amd64, linux/arm64)
required: true
slug:
description: Platform slug for artifact naming (e.g. linux-amd64, linux-arm64)
required: true
target_cpu:
description: Target CPU architecture (e.g. haswell, empty for base)
required: false
default: ""
profile:
description: Cargo build profile (release or release-max-perf)
required: true
images:
description: Container registry images (newline-separated)
required: true
registry_user:
description: Registry username for authentication
required: false
registry_password:
description: Registry password for authentication
required: false
outputs:
cpu_suffix:
description: CPU suffix for artifact naming
value: ${{ steps.cpu-suffix.outputs.suffix }}
metadata_labels:
description: Docker labels for the image
value: ${{ steps.meta.outputs.labels }}
metadata_annotations:
description: Docker annotations for the image
value: ${{ steps.meta.outputs.annotations }}
runs:
using: composite
steps:
- name: Set CPU suffix variable
id: cpu-suffix
shell: bash
run: |
if [[ -n "${{ inputs.target_cpu }}" ]]; then
echo "suffix=-${{ inputs.target_cpu }}" >> $GITHUB_OUTPUT
echo "CPU_SUFFIX=-${{ inputs.target_cpu }}" >> $GITHUB_ENV
else
echo "suffix=" >> $GITHUB_OUTPUT
echo "CPU_SUFFIX=" >> $GITHUB_ENV
fi
- name: Echo matrix configuration
shell: bash
run: |
echo "Platform: ${{ inputs.platform }}"
echo "Slug: ${{ inputs.slug }}"
echo "Target CPU: ${{ inputs.target_cpu }}"
echo "Profile: ${{ inputs.profile }}"
- name: Install rust
if: ${{ env.BUILDKIT_ENDPOINT == '' }}
id: rust-toolchain
uses: ./.forgejo/actions/rust-toolchain
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
with:
# Use persistent BuildKit if BUILDKIT_ENDPOINT is set (e.g. tcp://buildkit:8125)
driver: ${{ env.BUILDKIT_ENDPOINT != '' && 'remote' || 'docker-container' }}
endpoint: ${{ env.BUILDKIT_ENDPOINT || '' }}
- name: Set up QEMU
if: ${{ env.BUILDKIT_ENDPOINT == '' }}
uses: docker/setup-qemu-action@v3
- name: Login to builtin registry
if: ${{ env.BUILTIN_REGISTRY_ENABLED == 'true' }}
uses: docker/login-action@v3
with:
registry: ${{ env.BUILTIN_REGISTRY }}
username: ${{ inputs.registry_user }}
password: ${{ inputs.registry_password }}
- name: Extract metadata (labels, annotations) for Docker
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ inputs.images }}
# default labels & annotations: https://github.com/docker/metadata-action/blob/master/src/meta.ts#L509
env:
DOCKER_METADATA_ANNOTATIONS_LEVELS: manifest,index
- name: Get short git commit SHA
id: sha
shell: bash
run: |
calculatedSha=$(git rev-parse --short ${{ github.sha }})
echo "COMMIT_SHORT_SHA=$calculatedSha" >> $GITHUB_ENV
echo "Short SHA: $calculatedSha"
- name: Get Git commit timestamps
shell: bash
run: |
timestamp=$(git log -1 --pretty=%ct)
echo "TIMESTAMP=$timestamp" >> $GITHUB_ENV
echo "Commit timestamp: $timestamp"
- uses: ./.forgejo/actions/timelord
id: timelord
- name: Cache Rust registry
if: ${{ env.BUILDKIT_ENDPOINT == '' }}
uses: actions/cache@v3
with:
path: |
.cargo/git
.cargo/git/checkouts
.cargo/registry
.cargo/registry/src
key: rust-registry-image-${{hashFiles('**/Cargo.lock') }}
- name: Cache cargo target
if: ${{ env.BUILDKIT_ENDPOINT == '' }}
id: cache-cargo-target
uses: actions/cache@v3
with:
path: |
cargo-target${{ env.CPU_SUFFIX }}-${{ inputs.slug }}-${{ inputs.profile }}
key: cargo-target${{ env.CPU_SUFFIX }}-${{ inputs.slug }}-${{ inputs.profile }}-${{hashFiles('**/Cargo.lock') }}-${{steps.rust-toolchain.outputs.rustc_version}}
- name: Cache apt cache
if: ${{ env.BUILDKIT_ENDPOINT == '' }}
id: cache-apt
uses: actions/cache@v3
with:
path: |
var-cache-apt-${{ inputs.slug }}
key: var-cache-apt-${{ inputs.slug }}
- name: Cache apt lib
if: ${{ env.BUILDKIT_ENDPOINT == '' }}
id: cache-apt-lib
uses: actions/cache@v3
with:
path: |
var-lib-apt-${{ inputs.slug }}
key: var-lib-apt-${{ inputs.slug }}
- name: inject cache into docker
if: ${{ env.BUILDKIT_ENDPOINT == '' }}
uses: https://github.com/reproducible-containers/buildkit-cache-dance@v3.3.0
with:
cache-map: |
{
".cargo/registry": "/usr/local/cargo/registry",
".cargo/git/db": "/usr/local/cargo/git/db",
"cargo-target${{ env.CPU_SUFFIX }}-${{ inputs.slug }}-${{ inputs.profile }}": {
"target": "/app/target",
"id": "cargo-target${{ env.CPU_SUFFIX }}-${{ inputs.slug }}-${{ inputs.profile }}"
},
"var-cache-apt-${{ inputs.slug }}": "/var/cache/apt",
"var-lib-apt-${{ inputs.slug }}": "/var/lib/apt",
"${{ steps.timelord.outputs.database-path }}":"/timelord"
}
skip-extraction: ${{ steps.cache.outputs.cache-hit }}

View file

@ -0,0 +1,70 @@
name: upload-docker-artifacts
description: |
Upload Docker build artifacts including binary and digest files.
Handles artifact naming and conditional digest uploads for registry publishing.
inputs:
slug:
description: Platform slug for artifact naming (e.g. linux-amd64, linux-arm64)
required: true
cpu_suffix:
description: CPU suffix for artifact naming (e.g. -haswell)
required: false
default: ""
artifact_suffix:
description: Suffix for binary artifacts (e.g. -maxperf)
required: false
default: ""
digest_suffix:
description: Suffix for digest artifacts (e.g. -maxperf)
required: false
default: ""
digest:
description: The digest of the built Docker image
required: true
outputs:
binary_artifact_name:
description: The name of the uploaded binary artifact
value: conduwuit${{ inputs.cpu_suffix }}-${{ inputs.slug }}${{ inputs.artifact_suffix }}
runs:
using: composite
steps:
- name: Export digest
if: ${{ env.BUILTIN_REGISTRY_ENABLED == 'true' }}
shell: bash
run: |
mkdir -p /tmp/digests
digest="${{ inputs.digest }}"
echo "🔍 Build step digest output: '$digest'"
if [[ -z "$digest" ]]; then
echo "❌ ERROR: No digest found from build step"
exit 1
fi
digest_file="/tmp/digests/${digest#sha256:}"
echo "📁 Creating digest file: $digest_file"
touch "$digest_file"
echo "✅ Digest file created successfully"
echo "📋 Contents of /tmp/digests:"
ls -la /tmp/digests/
- name: Rename extracted binary
shell: bash
run: mv /tmp/binaries/sbin/conduwuit /tmp/binaries/conduwuit${{ inputs.cpu_suffix }}-${{ inputs.slug }}${{ inputs.artifact_suffix }}
- name: Upload binary artifact
uses: forgejo/upload-artifact@v4
with:
name: conduwuit${{ inputs.cpu_suffix }}-${{ inputs.slug }}${{ inputs.artifact_suffix }}
path: /tmp/binaries/conduwuit${{ inputs.cpu_suffix }}-${{ inputs.slug }}${{ inputs.artifact_suffix }}
if-no-files-found: error
- name: Upload digest
if: ${{ env.BUILTIN_REGISTRY_ENABLED == 'true' }}
uses: forgejo/upload-artifact@v4
with:
name: digests${{ inputs.digest_suffix }}-${{ inputs.slug }}${{ inputs.cpu_suffix }}
path: /tmp/digests/*
if-no-files-found: error
retention-days: 5

View file

@ -32,12 +32,12 @@ env:
jobs: jobs:
define-variables: define-variables:
name: "Setup Variables"
runs-on: ubuntu-latest runs-on: ubuntu-latest
outputs: outputs:
images: ${{ steps.var.outputs.images }} images: ${{ steps.var.outputs.images }}
images_list: ${{ steps.var.outputs.images_list }} images_list: ${{ steps.var.outputs.images_list }}
build_matrix: ${{ steps.var.outputs.build_matrix }}
steps: steps:
- name: Setting variables - name: Setting variables
@ -59,18 +59,9 @@ jobs:
} }
core.setOutput('images', images.join("\n")) core.setOutput('images', images.join("\n"))
core.setOutput('images_list', images.join(",")) core.setOutput('images_list', images.join(","))
const platforms = ['linux/amd64', 'linux/arm64']
core.setOutput('build_matrix', JSON.stringify({
platform: platforms,
target_cpu: ['base'],
include: platforms.map(platform => { return {
platform,
slug: platform.replace('/', '-')
}})
}))
build-image: build-release:
name: "Build ${{ matrix.slug }}${{ matrix.target_cpu != '' && format('-{0}', matrix.target_cpu) || '' }}" name: "Build ${{ matrix.slug }} (release)"
runs-on: dind runs-on: dind
needs: define-variables needs: define-variables
permissions: permissions:
@ -83,139 +74,25 @@ jobs:
include: include:
- platform: "linux/amd64" - platform: "linux/amd64"
slug: "linux-amd64" slug: "linux-amd64"
target_cpu: ""
profile: "release"
- platform: "linux/amd64"
slug: "linux-amd64"
target_cpu: "haswell"
profile: "release-max-perf"
- platform: "linux/arm64" - platform: "linux/arm64"
slug: "linux-arm64" slug: "linux-arm64"
target_cpu: ""
profile: "release"
steps: steps:
- name: Set CPU suffix variable
run: |
if [[ -n "${{ matrix.target_cpu }}" ]]; then
echo "CPU_SUFFIX=-${{ matrix.target_cpu }}" >> $GITHUB_ENV
else
echo "CPU_SUFFIX=" >> $GITHUB_ENV
fi
- name: Echo strategy
run: echo '${{ toJSON(fromJSON(needs.define-variables.outputs.build_matrix)) }}'
- name: Echo matrix
run: echo '${{ toJSON(matrix) }}'
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v5 uses: actions/checkout@v5
with: with:
persist-credentials: false persist-credentials: false
- name: Install rust - name: Prepare Docker build environment
if: ${{ env.BUILDKIT_ENDPOINT == '' }} id: prepare
id: rust-toolchain uses: ./.forgejo/actions/prepare-docker-build
uses: ./.forgejo/actions/rust-toolchain
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
with: with:
# Use persistent BuildKit if BUILDKIT_ENDPOINT is set (e.g. tcp://buildkit:8125) platform: ${{ matrix.platform }}
driver: ${{ env.BUILDKIT_ENDPOINT != '' && 'remote' || 'docker-container' }} slug: ${{ matrix.slug }}
endpoint: ${{ env.BUILDKIT_ENDPOINT || '' }} target_cpu: ""
- name: Set up QEMU profile: "release"
if: ${{ env.BUILDKIT_ENDPOINT == '' }} images: ${{ needs.define-variables.outputs.images }}
uses: docker/setup-qemu-action@v3 registry_user: ${{ vars.BUILTIN_REGISTRY_USER || github.actor }}
# Uses the `docker/login-action` action to log in to the Container registry registry using the account and password that will publish the packages. Once published, the packages are scoped to the account defined here. registry_password: ${{ secrets.BUILTIN_REGISTRY_PASSWORD || secrets.GITHUB_TOKEN }}
- name: Login to builtin registry
if: ${{ env.BUILTIN_REGISTRY_ENABLED == 'true' }}
uses: docker/login-action@v3
with:
registry: ${{ env.BUILTIN_REGISTRY }}
username: ${{ vars.BUILTIN_REGISTRY_USER || github.actor }}
password: ${{ secrets.BUILTIN_REGISTRY_PASSWORD || secrets.GITHUB_TOKEN }}
# This step uses [docker/metadata-action](https://github.com/docker/metadata-action#about) to extract tags and labels that will be applied to the specified image. The `id` "meta" allows the output of this step to be referenced in a subsequent step. The `images` value provides the base name for the tags and labels.
- name: Extract metadata (labels, annotations) for Docker
id: meta
uses: docker/metadata-action@v5
with:
images: ${{needs.define-variables.outputs.images}}
# default labels & annotations: https://github.com/docker/metadata-action/blob/master/src/meta.ts#L509
env:
DOCKER_METADATA_ANNOTATIONS_LEVELS: manifest,index
# This step uses the `docker/build-push-action` action to build the image, based on your repository's `Dockerfile`. If the build succeeds, it pushes the image to GitHub Packages.
# It uses the `context` parameter to define the build's context as the set of files located in the specified path. For more information, see "[Usage](https://github.com/docker/build-push-action#usage)" in the README of the `docker/build-push-action` repository.
# It uses the `tags` and `labels` parameters to tag and label the image with the output from the "meta" step.
# It will not push images generated from a pull request
- name: Get short git commit SHA
id: sha
run: |
calculatedSha=$(git rev-parse --short ${{ github.sha }})
echo "COMMIT_SHORT_SHA=$calculatedSha" >> $GITHUB_ENV
echo "Short SHA: $calculatedSha"
- name: Get Git commit timestamps
run: |
timestamp=$(git log -1 --pretty=%ct)
echo "TIMESTAMP=$timestamp" >> $GITHUB_ENV
echo "Commit timestamp: $timestamp"
- uses: ./.forgejo/actions/timelord
id: timelord
- name: Cache Rust registry
if: ${{ env.BUILDKIT_ENDPOINT == '' }}
uses: actions/cache@v3
with:
path: |
.cargo/git
.cargo/git/checkouts
.cargo/registry
.cargo/registry/src
key: rust-registry-image-${{hashFiles('**/Cargo.lock') }}
- name: Cache cargo target
if: ${{ env.BUILDKIT_ENDPOINT == '' }}
id: cache-cargo-target
uses: actions/cache@v3
with:
path: |
cargo-target${{ env.CPU_SUFFIX }}-${{ matrix.slug }}-${{ matrix.profile }}
key: cargo-target${{ env.CPU_SUFFIX }}-${{ matrix.slug }}-${{ matrix.profile }}-${{hashFiles('**/Cargo.lock') }}-${{steps.rust-toolchain.outputs.rustc_version}}
- name: Cache apt cache
if: ${{ env.BUILDKIT_ENDPOINT == '' }}
id: cache-apt
uses: actions/cache@v3
with:
path: |
var-cache-apt-${{ matrix.slug }}
key: var-cache-apt-${{ matrix.slug }}
- name: Cache apt lib
if: ${{ env.BUILDKIT_ENDPOINT == '' }}
id: cache-apt-lib
uses: actions/cache@v3
with:
path: |
var-lib-apt-${{ matrix.slug }}
key: var-lib-apt-${{ matrix.slug }}
- name: inject cache into docker
if: ${{ env.BUILDKIT_ENDPOINT == '' }}
uses: https://github.com/reproducible-containers/buildkit-cache-dance@v3.3.0
with:
cache-map: |
{
".cargo/registry": "/usr/local/cargo/registry",
".cargo/git/db": "/usr/local/cargo/git/db",
"cargo-target${{ env.CPU_SUFFIX }}-${{ matrix.slug }}-${{ matrix.profile }}": {
"target": "/app/target",
"id": "cargo-target${{ env.CPU_SUFFIX }}-${{ matrix.slug }}-${{ matrix.profile }}"
},
"var-cache-apt-${{ matrix.slug }}": "/var/cache/apt",
"var-lib-apt-${{ matrix.slug }}": "/var/lib/apt",
"{{ steps.timelord.outputs.database-path }}":"/timelord"
}
skip-extraction: ${{ steps.cache.outputs.cache-hit }}
- name: Build and push Docker image by digest - name: Build and push Docker image by digest
id: build id: build
uses: docker/build-push-action@v6 uses: docker/build-push-action@v6
@ -228,11 +105,11 @@ jobs:
GIT_REMOTE_URL=${{github.event.repository.html_url }} GIT_REMOTE_URL=${{github.event.repository.html_url }}
GIT_REMOTE_COMMIT_URL=${{github.event.head_commit.url }} GIT_REMOTE_COMMIT_URL=${{github.event.head_commit.url }}
CARGO_INCREMENTAL=${{ env.BUILDKIT_ENDPOINT != '' && '1' || '0' }} CARGO_INCREMENTAL=${{ env.BUILDKIT_ENDPOINT != '' && '1' || '0' }}
TARGET_CPU=${{ matrix.target_cpu }} TARGET_CPU=
RUST_PROFILE=${{ matrix.profile }} RUST_PROFILE=release
platforms: ${{ matrix.platform }} platforms: ${{ matrix.platform }}
labels: ${{ steps.meta.outputs.labels }} labels: ${{ steps.prepare.outputs.metadata_labels }}
annotations: ${{ steps.meta.outputs.annotations }} annotations: ${{ steps.prepare.outputs.metadata_annotations }}
cache-from: type=gha cache-from: type=gha
# cache-to: type=gha,mode=max # cache-to: type=gha,mode=max
sbom: true sbom: true
@ -241,124 +118,116 @@ jobs:
type=local,dest=/tmp/binaries type=local,dest=/tmp/binaries
env: env:
SOURCE_DATE_EPOCH: ${{ env.TIMESTAMP }} SOURCE_DATE_EPOCH: ${{ env.TIMESTAMP }}
- name: Upload Docker artifacts
# For publishing multi-platform manifests uses: ./.forgejo/actions/upload-docker-artifacts
- name: Export digest
if: ${{ env.BUILTIN_REGISTRY_ENABLED == 'true' }}
run: |
mkdir -p /tmp/digests
digest="${{ steps.build.outputs.digest }}"
echo "🔍 Build step digest output: '$digest'"
if [[ -z "$digest" ]]; then
echo "❌ ERROR: No digest found from build step"
exit 1
fi
digest_file="/tmp/digests/${digest#sha256:}"
echo "📁 Creating digest file: $digest_file"
touch "$digest_file"
echo "✅ Digest file created successfully"
echo "📋 Contents of /tmp/digests:"
ls -la /tmp/digests/
# Binary extracted via local output for all builds
- name: Rename extracted binary
run: mv /tmp/binaries/sbin/conduwuit /tmp/binaries/conduwuit${{ env.CPU_SUFFIX }}-${{ matrix.slug }}-${{ matrix.profile }}
- name: Upload binary artifact
uses: forgejo/upload-artifact@v4
with: with:
name: conduwuit${{ env.CPU_SUFFIX }}-${{ matrix.slug }}-${{ matrix.profile }} slug: ${{ matrix.slug }}
path: /tmp/binaries/conduwuit${{ env.CPU_SUFFIX }}-${{ matrix.slug }}-${{ matrix.profile }} cpu_suffix: ${{ steps.prepare.outputs.cpu_suffix }}
if-no-files-found: error artifact_suffix: ""
digest_suffix: ""
digest: ${{ steps.build.outputs.digest }}
- name: Upload digest merge-release:
if: ${{ env.BUILTIN_REGISTRY_ENABLED == 'true' }} name: "Create Multi-arch Release Manifest"
uses: forgejo/upload-artifact@v4
with:
name: digests-${{ matrix.slug }}${{ env.CPU_SUFFIX }}
path: /tmp/digests/*
if-no-files-found: error
retention-days: 5
merge:
name: "Create ${{ matrix.target_cpu == '' && 'Multi-arch' || 'Haswell' }} Manifest"
runs-on: dind runs-on: dind
needs: [define-variables, build-image] needs: [define-variables, build-release]
steps:
- name: Checkout repository
uses: actions/checkout@v5
with:
persist-credentials: false
- name: Create multi-platform manifest
uses: ./.forgejo/actions/create-docker-manifest
with:
digest_pattern: "digests-linux-{amd64,arm64}"
tag_suffix: ""
images: ${{ needs.define-variables.outputs.images }}
registry_user: ${{ vars.BUILTIN_REGISTRY_USER || github.actor }}
registry_password: ${{ secrets.BUILTIN_REGISTRY_PASSWORD || secrets.GITHUB_TOKEN }}
build-maxperf:
name: "Build ${{ matrix.slug }} (max-perf)"
runs-on: dind
needs: [define-variables, build-release]
permissions:
contents: read
packages: write
attestations: write
id-token: write
strategy: strategy:
matrix: matrix:
include: include:
- target_cpu: "" - platform: "linux/amd64"
digest_pattern: "digests-linux-{amd64,arm64}" slug: "linux-amd64"
- target_cpu: "haswell" target_cpu: "haswell"
digest_pattern: "digests-linux-amd64-haswell" - platform: "linux/arm64"
slug: "linux-arm64"
target_cpu: ""
steps: steps:
- name: Download digests - name: Checkout repository
if: ${{ env.BUILTIN_REGISTRY_ENABLED == 'true' }} uses: actions/checkout@v5
uses: forgejo/download-artifact@v4
with: with:
path: /tmp/digests persist-credentials: false
pattern: ${{ matrix.digest_pattern }} - name: Prepare max-perf Docker build environment
merge-multiple: true id: prepare
# Uses the `docker/login-action` action to log in to the Container registry registry using the account and password that will publish the packages. Once published, the packages are scoped to the account defined here. uses: ./.forgejo/actions/prepare-docker-build
- name: Login to builtin registry
if: ${{ env.BUILTIN_REGISTRY_ENABLED == 'true' }}
uses: docker/login-action@v3
with: with:
registry: ${{ env.BUILTIN_REGISTRY }} platform: ${{ matrix.platform }}
username: ${{ vars.BUILTIN_REGISTRY_USER || github.actor }} slug: ${{ matrix.slug }}
password: ${{ secrets.BUILTIN_REGISTRY_PASSWORD || secrets.GITHUB_TOKEN }} target_cpu: ${{ matrix.target_cpu }}
profile: "release-max-perf"
- name: Set up Docker Buildx images: ${{ needs.define-variables.outputs.images }}
if: ${{ env.BUILTIN_REGISTRY_ENABLED == 'true' }} registry_user: ${{ vars.BUILTIN_REGISTRY_USER || github.actor }}
uses: docker/setup-buildx-action@v3 registry_password: ${{ secrets.BUILTIN_REGISTRY_PASSWORD || secrets.GITHUB_TOKEN }}
- name: Build and push max-perf Docker image by digest
id: build
uses: docker/build-push-action@v6
with: with:
# Use persistent BuildKit if BUILDKIT_ENDPOINT is set (e.g. tcp://buildkit:8125) context: .
driver: ${{ env.BUILDKIT_ENDPOINT != '' && 'remote' || 'docker-container' }} file: "docker/Dockerfile"
endpoint: ${{ env.BUILDKIT_ENDPOINT || '' }} build-args: |
GIT_COMMIT_HASH=${{ github.sha }}
- name: Extract metadata (tags) for Docker GIT_COMMIT_HASH_SHORT=${{ env.COMMIT_SHORT_SHA }}
if: ${{ env.BUILTIN_REGISTRY_ENABLED == 'true' }} GIT_REMOTE_URL=${{github.event.repository.html_url }}
id: meta GIT_REMOTE_COMMIT_URL=${{github.event.head_commit.url }}
uses: docker/metadata-action@v5 CARGO_INCREMENTAL=${{ env.BUILDKIT_ENDPOINT != '' && '1' || '0' }}
with: TARGET_CPU=${{ matrix.target_cpu }}
tags: | RUST_PROFILE=release-max-perf
type=semver,pattern={{version}},prefix=v,suffix=${{ matrix.target_cpu != '' && format('-{0}', matrix.target_cpu) || '' }} platforms: ${{ matrix.platform }}
type=semver,pattern={{major}}.{{minor}},enable=${{ !startsWith(github.ref, 'refs/tags/v0.0.') }},prefix=v,suffix=${{ matrix.target_cpu != '' && format('-{0}', matrix.target_cpu) || '' }} labels: ${{ steps.prepare.outputs.metadata_labels }}
type=semver,pattern={{major}},enable=${{ !startsWith(github.ref, 'refs/tags/v0.') }},prefix=v,suffix=${{ matrix.target_cpu != '' && format('-{0}', matrix.target_cpu) || '' }} annotations: ${{ steps.prepare.outputs.metadata_annotations }}
type=ref,event=branch,prefix=${{ format('refs/heads/{0}', github.event.repository.default_branch) != github.ref && 'branch-' || '' }},suffix=${{ matrix.target_cpu != '' && format('-{0}', matrix.target_cpu) || '' }} cache-from: type=gha
type=ref,event=pr,suffix=${{ matrix.target_cpu != '' && format('-{0}', matrix.target_cpu) || '' }} # cache-to: type=gha,mode=max
type=sha,format=short,suffix=${{ matrix.target_cpu != '' && format('-{0}', matrix.target_cpu) || '' }} sbom: true
type=raw,value=latest${{ matrix.target_cpu != '' && format('-{0}', matrix.target_cpu) || '' }},enable=${{ startsWith(github.ref, 'refs/tags/v') }} outputs: |
images: ${{needs.define-variables.outputs.images}} ${{ env.BUILTIN_REGISTRY_ENABLED == 'true' && format('type=image,"name={0}",push-by-digest=true,name-canonical=true,push=true', needs.define-variables.outputs.images_list) || format('type=image,"name={0}",push=false', needs.define-variables.outputs.images_list) }}
# default labels & annotations: https://github.com/docker/metadata-action/blob/master/src/meta.ts#L509 type=local,dest=/tmp/binaries
env: env:
DOCKER_METADATA_ANNOTATIONS_LEVELS: index SOURCE_DATE_EPOCH: ${{ env.TIMESTAMP }}
- name: Upload max-perf Docker artifacts
uses: ./.forgejo/actions/upload-docker-artifacts
with:
slug: ${{ matrix.slug }}
cpu_suffix: ${{ steps.prepare.outputs.cpu_suffix }}
artifact_suffix: "-maxperf"
digest_suffix: "-maxperf"
digest: ${{ steps.build.outputs.digest }}
- name: Create manifest list and push merge-maxperf:
if: ${{ env.BUILTIN_REGISTRY_ENABLED == 'true' }} name: "Create Max-Perf Manifest"
working-directory: /tmp/digests runs-on: dind
env: needs: [define-variables, build-maxperf]
IMAGES: ${{needs.define-variables.outputs.images}} steps:
shell: bash - name: Checkout repository
run: | uses: actions/checkout@v5
IFS=$'\n' with:
IMAGES_LIST=($IMAGES) persist-credentials: false
ANNOTATIONS_LIST=($DOCKER_METADATA_OUTPUT_ANNOTATIONS) - name: Create max-perf manifest
TAGS_LIST=($DOCKER_METADATA_OUTPUT_TAGS) uses: ./.forgejo/actions/create-docker-manifest
for REPO in "${IMAGES_LIST[@]}"; do with:
docker buildx imagetools create \ digest_pattern: "digests-maxperf-linux-{amd64-haswell,arm64}"
$(for tag in "${TAGS_LIST[@]}"; do echo "--tag"; echo "$tag"; done) \ tag_suffix: "-maxperf"
$(for annotation in "${ANNOTATIONS_LIST[@]}"; do echo "--annotation"; echo "$annotation"; done) \ images: ${{ needs.define-variables.outputs.images }}
$(for reference in *; do printf "$REPO@sha256:%s\n" $reference; done) registry_user: ${{ vars.BUILTIN_REGISTRY_USER || github.actor }}
done registry_password: ${{ secrets.BUILTIN_REGISTRY_PASSWORD || secrets.GITHUB_TOKEN }}
- name: Inspect image
if: ${{ env.BUILTIN_REGISTRY_ENABLED == 'true' }}
env:
IMAGES: ${{needs.define-variables.outputs.images}}
shell: bash
run: |
IMAGES_LIST=($IMAGES)
for REPO in "${IMAGES_LIST[@]}"; do
docker buildx imagetools inspect $REPO:${{ steps.meta.outputs.version }}
done