mirror of
https://github.com/we-promise/sure.git
synced 2026-04-07 22:34:47 +00:00
* feat(ci): add OCI annotations and metadata to multi-arch images - Include created, source, revision, ref-name, vendor & license - Add title and description for Sure Rails app multi-arch image - Dynamically annotate version when tag builds are triggered * chore(ci): add nightly tag with weekday pattern to tag config * fix(ci): allow publish workflow to push images from main branch - Update conditional checks to include refs/heads/main - Reflect new condition in workflow comments for clarity * fix(ci): set image version label only for tag builds in metadata * fix(ci): avoid quotations being passed as CLI argument Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: Himank Dave <93311724+steadyfall@users.noreply.github.com> * refactor(ci): remove deprecated `::set-output` command Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: Himank Dave <93311724+steadyfall@users.noreply.github.com> --------- Signed-off-by: Himank Dave <93311724+steadyfall@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
232 lines
8.1 KiB
YAML
232 lines
8.1 KiB
YAML
# Reference: https://docs.docker.com/build/ci/github-actions/multi-platform/#distribute-build-across-multiple-runners
|
|
|
|
# Conditions for pushing the image to GHCR:
|
|
# - Triggered by push to default branch (`main`)
|
|
# - Triggered by push to a version tag (`v*`)
|
|
# - Triggered by a scheduled run
|
|
# - Triggered manually via `workflow_dispatch` with `push: true`
|
|
#
|
|
# Conditional expression:
|
|
# github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v') || github.event_name == 'schedule' || github.event.inputs.push
|
|
|
|
name: Publish Docker image
|
|
|
|
on:
|
|
workflow_dispatch:
|
|
inputs:
|
|
ref:
|
|
description: 'Git ref (tag or commit SHA) to build'
|
|
required: true
|
|
type: string
|
|
default: 'main'
|
|
push:
|
|
description: 'Push the image to container registry'
|
|
required: false
|
|
type: boolean
|
|
default: false
|
|
push:
|
|
tags:
|
|
- 'v*'
|
|
branches:
|
|
- main
|
|
schedule:
|
|
- cron: '30 1 * * *'
|
|
|
|
env:
|
|
REGISTRY: ghcr.io
|
|
IMAGE_NAME: ${{ github.repository }}
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
jobs:
|
|
ci:
|
|
uses: ./.github/workflows/ci.yml
|
|
|
|
build:
|
|
name: Build Docker image
|
|
needs: [ ci ]
|
|
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
platform: [amd64, arm64]
|
|
|
|
timeout-minutes: 60
|
|
runs-on: ${{ matrix.platform == 'arm64' && 'ubuntu-24.04-arm' || 'ubuntu-24.04' }}
|
|
|
|
outputs:
|
|
tags: ${{ steps.meta.outputs.tags }}
|
|
|
|
permissions:
|
|
contents: read
|
|
packages: write
|
|
|
|
steps:
|
|
- name: Check out the repo
|
|
uses: actions/checkout@v4.2.0
|
|
with:
|
|
ref: ${{ github.event.inputs.ref || github.ref }}
|
|
|
|
- name: Set up Docker Buildx
|
|
uses: docker/setup-buildx-action@v3.10.0
|
|
|
|
- name: Log in to the container registry
|
|
uses: docker/login-action@v3.3.0
|
|
with:
|
|
registry: ${{ env.REGISTRY }}
|
|
username: ${{ github.actor }}
|
|
password: ${{ secrets.GITHUB_TOKEN }}
|
|
|
|
- name: Configure image tags
|
|
id: tag_config
|
|
shell: bash
|
|
run: |
|
|
BASE_CONFIG="type=sha,format=long"
|
|
if [[ $GITHUB_EVENT_NAME == "schedule" ]]; then
|
|
BASE_CONFIG+=$'\n'"type=schedule,pattern=nightly"
|
|
BASE_CONFIG+=$'\n'"type=schedule,pattern=nightly-{{date 'ddd'}}"
|
|
elif [[ "$GITHUB_REF" == refs/tags/v* ]]; then
|
|
BASE_CONFIG="type=semver,pattern={{version}}"
|
|
BASE_CONFIG+=$'\n'"type=raw,value=stable"
|
|
fi
|
|
{
|
|
echo 'TAGS_SPEC<<EOF'
|
|
echo "$BASE_CONFIG"
|
|
echo EOF
|
|
} >> $GITHUB_ENV
|
|
|
|
- name: Get current date (RFC 3339 format)
|
|
id: date
|
|
run: echo "date=$(date -Iseconds)" >> $GITHUB_OUTPUT
|
|
|
|
- name: Extract metadata for Docker
|
|
id: meta
|
|
uses: docker/metadata-action@v5.6.0
|
|
with:
|
|
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
|
flavor: latest=false
|
|
tags: ${{ env.TAGS_SPEC }}
|
|
labels: |
|
|
org.opencontainers.image.version=${{ startsWith(github.ref, 'refs/tags/v') && github.ref_name || '' }}
|
|
org.opencontainers.image.created=${{ steps.date.outputs.date }}
|
|
org.opencontainers.image.ref.name=${{ github.ref_name }}
|
|
org.opencontainers.image.vendor=we-promise
|
|
org.opencontainers.image.title=Sure
|
|
org.opencontainers.image.description=A multi-arch Docker image for the Sure Rails app
|
|
|
|
- name: Publish 'linux/${{ matrix.platform }}' image by digest
|
|
uses: docker/build-push-action@v6.16.0
|
|
id: build
|
|
with:
|
|
context: .
|
|
build-args: BUILD_COMMIT_SHA=${{ github.sha }}
|
|
platforms: 'linux/${{ matrix.platform }}'
|
|
cache-from: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:cache-${{ matrix.platform }}
|
|
cache-to: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:cache-${{ matrix.platform }},mode=max
|
|
labels: ${{ steps.meta.outputs.labels }}
|
|
provenance: false
|
|
push: true
|
|
# DO NOT REMOVE `oci-mediatypes=true`, fixes annotation not showing up on job.merge.steps[-1]
|
|
# ref: https://github.com/docker/build-push-action/discussions/1022
|
|
outputs: type=image,name=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }},name-canonical=true,push-by-digest=true,oci-mediatypes=true
|
|
|
|
- name: Export the Docker image digest
|
|
if: ${{ github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v') || github.event_name == 'schedule' || github.event.inputs.push }}
|
|
run: |
|
|
mkdir -p "${RUNNER_TEMP}"/digests
|
|
echo "${DIGEST#sha256:}" > "${RUNNER_TEMP}/digests/digest-${PLATFORM}"
|
|
env:
|
|
DIGEST: ${{ steps.build.outputs.digest }}
|
|
PLATFORM: ${{ matrix.platform }}
|
|
|
|
- name: Upload the Docker image digest
|
|
if: ${{ github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v') || github.event_name == 'schedule' || github.event.inputs.push }}
|
|
uses: actions/upload-artifact@v4.6.2
|
|
with:
|
|
name: digest-${{ matrix.platform }}
|
|
path: ${{ runner.temp }}/digests/*
|
|
if-no-files-found: error
|
|
retention-days: 1
|
|
|
|
merge:
|
|
name: Merge multi-arch manifest & push multi-arch tag
|
|
if: ${{ github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v') || github.event_name == 'schedule' || github.event.inputs.push }}
|
|
needs: [build]
|
|
|
|
timeout-minutes: 60
|
|
runs-on: 'ubuntu-24.04'
|
|
|
|
permissions:
|
|
packages: write
|
|
|
|
steps:
|
|
- name: Set up Docker Buildx
|
|
uses: docker/setup-buildx-action@v3.10.0
|
|
|
|
- name: Download Docker image digests
|
|
uses: actions/download-artifact@v4.3.0
|
|
with:
|
|
path: ${{ runner.temp }}/digests
|
|
pattern: digest-*
|
|
merge-multiple: true
|
|
|
|
- name: Log in to the container registry
|
|
uses: docker/login-action@v3.3.0
|
|
with:
|
|
registry: ${{ env.REGISTRY }}
|
|
username: ${{ github.actor }}
|
|
password: ${{ secrets.GITHUB_TOKEN }}
|
|
|
|
- name: Merge and push Docker image
|
|
env:
|
|
TAGS: ${{ needs.build.outputs.tags }}
|
|
DIGESTS_DIR: ${{ runner.temp }}/digests
|
|
shell: bash -xeuo pipefail {0}
|
|
run: |
|
|
tag_args=()
|
|
while IFS=$'\n' read -r tag; do
|
|
[[ -n "${tag}" ]] || continue
|
|
tag_args+=("--tag=${tag}")
|
|
done <<< "${TAGS}"
|
|
|
|
image_args=()
|
|
for PLATFORM in amd64 arm64; do
|
|
image_args+=("${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@sha256:$(<"${DIGESTS_DIR}/digest-${PLATFORM}")")
|
|
done
|
|
|
|
annotations=(
|
|
"index:org.opencontainers.image.created=$(date -Iseconds)"
|
|
'index:org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }}'
|
|
'index:org.opencontainers.image.revision=${{ github.sha }}'
|
|
'index:org.opencontainers.image.ref.name=${{ github.ref_name }}'
|
|
'index:org.opencontainers.image.vendor=we-promise'
|
|
'index:org.opencontainers.image.licenses=AGPL-3.0'
|
|
'index:org.opencontainers.image.title=Sure'
|
|
'index:org.opencontainers.image.description=A multi-arch Docker image for the Sure Rails app'
|
|
)
|
|
annotation_args=()
|
|
for annotation in "${annotations[@]}"; do
|
|
annotation_args+=("--annotation=${annotation}")
|
|
done
|
|
if [[ $GITHUB_REF_TYPE == "tag" ]]; then
|
|
annotation_args+=("--annotation=index:org.opencontainers.image.version=$GITHUB_REF_NAME")
|
|
fi
|
|
|
|
attempts=0
|
|
until docker buildx imagetools create \
|
|
"${annotation_args[@]}" \
|
|
"${tag_args[@]}" \
|
|
"${image_args[@]}" \
|
|
; do
|
|
attempts=$((attempts + 1))
|
|
if [[ $attempts -ge 3 ]]; then
|
|
echo "[$(date -u)] ERROR: Failed after 3 attempts." >&2
|
|
exit 1
|
|
fi
|
|
delay=$((2 ** attempts))
|
|
if [[ $delay -gt 15 ]]; then delay=15; fi
|
|
echo "Push failed (attempt $attempts). Retrying in ${delay} seconds..."
|
|
sleep ${delay}
|
|
done
|