buster/.github/workflows/docker-release.yml

392 lines
15 KiB
YAML

name: Docker Release
on:
push:
branches:
- main # Trigger when PR from staging is merged to main
permissions:
contents: read
packages: write
env:
# Placeholder for Docker Hub username/organization or GHCR owner
DOCKER_REGISTRY_OWNER: ghcr.io/${{ github.repository_owner }}
API_IMAGE_NAME: buster/api
WEB_IMAGE_NAME: buster/web
jobs:
prepare_docker_release_info:
name: Prepare Docker Release Information
runs-on: blacksmith-32vcpu-ubuntu-2204
outputs:
api_version: ${{ steps.version_info.outputs.api_version }}
web_version: ${{ steps.version_info.outputs.web_version }}
api_version_found: ${{ steps.version_info.outputs.api_version_found }}
web_version_found: ${{ steps.version_info.outputs.web_version_found }}
steps:
- name: Checkout code from main
uses: actions/checkout@v4
with:
ref: ${{ github.sha }} # Checkout the specific commit on main (merge commit)
- name: Read API and Web Versions
id: version_info
shell: bash
run: |
API_VERSION=""
WEB_VERSION=""
API_VERSION_FOUND="false"
WEB_VERSION_FOUND="false"
# Read API version from api/server/Cargo.toml
if [ -f api/server/Cargo.toml ]; then
API_VERSION=$(grep '^version' api/server/Cargo.toml | head -n 1 | sed 's/version = \"\(.*\)\"/\1/')
if [ -n "$API_VERSION" ]; then
echo "Read API version '$API_VERSION' from api/server/Cargo.toml"
API_VERSION_FOUND="true"
else
echo "API version string not found in api/server/Cargo.toml despite file existing."
fi
else
echo "Warning: api/server/Cargo.toml not found. Cannot determine API version."
fi
# Read Web version from web/package.json
if [ -f web/package.json ]; then
WEB_VERSION=$(jq -r '.version // empty' web/package.json)
if [ -n "$WEB_VERSION" ]; then
echo "Read Web version '$WEB_VERSION' from web/package.json"
WEB_VERSION_FOUND="true"
else
echo "Web version string not found in web/package.json despite file existing."
fi
else
echo "Warning: web/package.json not found. Cannot determine Web version."
fi
echo "api_version=$API_VERSION" >> $GITHUB_OUTPUT
echo "web_version=$WEB_VERSION" >> $GITHUB_OUTPUT
echo "api_version_found=$API_VERSION_FOUND" >> $GITHUB_OUTPUT
echo "web_version_found=$WEB_VERSION_FOUND" >> $GITHUB_OUTPUT
build_and_push_api:
name: Build and Push API Image
needs: prepare_docker_release_info
if: needs.prepare_docker_release_info.outputs.api_version_found == 'true'
strategy:
fail-fast: false
matrix:
platform: [amd64, arm64]
include:
- platform: amd64
runner: blacksmith-8vcpu-ubuntu-2204
docker_platform: linux/amd64
- platform: arm64
runner: blacksmith-8vcpu-ubuntu-2204-arm
docker_platform: linux/arm64
runs-on: ${{ matrix.runner }}
env:
API_VERSION: ${{ needs.prepare_docker_release_info.outputs.api_version }}
steps:
- name: Checkout code from main
uses: actions/checkout@v4
with:
ref: ${{ github.sha }}
- name: Docker meta for API
id: meta_api
uses: docker/metadata-action@v5
with:
images: ${{ env.DOCKER_REGISTRY_OWNER }}/${{ env.API_IMAGE_NAME }}
tags: |
type=semver,pattern={{version}},value=${{ env.API_VERSION }}
type=sha,format=short
type=raw,value=latest
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Docker Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push API image
id: build_api_image_platform
uses: useblacksmith/build-push-action@v1
with:
context: ./api
file: ./api/Dockerfile
push: true
platforms: ${{ matrix.docker_platform }}
tags: ${{ steps.meta_api.outputs.tags }}
labels: ${{ steps.meta_api.outputs.labels }}
outputs: type=image,name=${{ env.DOCKER_REGISTRY_OWNER }}/${{ env.API_IMAGE_NAME }},push-by-digest=true,name-canonical=true
- name: Export API digest
run: |
mkdir -p ${{ runner.temp }}/digests
digest_full="${{ steps.build_api_image_platform.outputs.digest }}"
digest_sha="${digest_full#sha256:}"
echo "Digest SHA for API ${{ matrix.platform }}: ${digest_sha}"
echo "${digest_sha}" > "${{ runner.temp }}/digests/api-${{ matrix.platform }}.sha"
- name: Upload API digest file
uses: actions/upload-artifact@v4
with:
name: api-digest-${{ matrix.platform }}
path: ${{ runner.temp }}/digests/api-${{ matrix.platform }}.sha
if-no-files-found: error
retention-days: 1
- name: Set API Package Visibility to Public
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
ORG_NAME: ${{ github.repository_owner }}
run: |
echo "Attempting to set visibility for $ORG_NAME/${{ env.API_IMAGE_NAME }}"
RESPONSE_CODE=$(curl -L -s -o /dev/null -w "%{http_code}" -X PATCH \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer $GH_TOKEN" \
-H "X-GitHub-Api-Version: 2022-11-28" \
"https://api.github.com/orgs/$ORG_NAME/packages/container/${{ env.API_IMAGE_NAME }}" \
-d '{"visibility":"public"}')
if [ "$RESPONSE_CODE" -eq 200 ] || [ "$RESPONSE_CODE" -eq 204 ]; then
echo "Package $ORG_NAME/${{ env.API_IMAGE_NAME }} visibility set to public successfully."
else
echo "Failed to set package $ORG_NAME/${{ env.API_IMAGE_NAME }} visibility to public. HTTP Status: $RESPONSE_CODE"
# Optionally, fail the step: exit 1
fi
build_and_push_web:
name: Build and Push Web Image
needs: prepare_docker_release_info
if: needs.prepare_docker_release_info.outputs.web_version_found == 'true'
environment: main
strategy:
fail-fast: false
matrix:
platform: [amd64, arm64]
include:
- platform: amd64
runner: blacksmith-8vcpu-ubuntu-2204
docker_platform: linux/amd64
- platform: arm64
runner: blacksmith-8vcpu-ubuntu-2204-arm
docker_platform: linux/arm64
runs-on: ${{ matrix.runner }}
env:
WEB_VERSION: ${{ needs.prepare_docker_release_info.outputs.web_version }}
steps:
- name: Checkout code from main
uses: actions/checkout@v4
with:
ref: ${{ github.sha }}
- name: Docker meta for Web
id: meta_web
uses: docker/metadata-action@v5
with:
images: ${{ env.DOCKER_REGISTRY_OWNER }}/${{ env.WEB_IMAGE_NAME }}
tags: |
type=semver,pattern={{version}},value=${{ env.WEB_VERSION }}
type=sha,format=short
type=raw,value=latest
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Docker Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push Web image
id: build_web_image_platform
uses: useblacksmith/build-push-action@v1
with:
context: ./web
file: ./web/Dockerfile
push: true
platforms: ${{ matrix.docker_platform }}
tags: ${{ steps.meta_web.outputs.tags }}
labels: ${{ steps.meta_web.outputs.labels }}
outputs: type=image,name=${{ env.DOCKER_REGISTRY_OWNER }}/${{ env.WEB_IMAGE_NAME }},push-by-digest=true,name-canonical=true
build-args: |
NEXT_PUBLIC_API_URL=${{ secrets.NEXT_PUBLIC_API_URL }}
NEXT_PUBLIC_URL=${{ secrets.NEXT_PUBLIC_URL }}
NEXT_PUBLIC_SUPABASE_URL=${{ secrets.NEXT_PUBLIC_SUPABASE_URL }}
NEXT_PUBLIC_SUPABASE_ANON_KEY=${{ secrets.NEXT_PUBLIC_SUPABASE_ANON_KEY }}
NEXT_PUBLIC_WEB_SOCKET_URL=${{ secrets.NEXT_PUBLIC_WEB_SOCKET_URL }}
- name: Export Web digest
run: |
mkdir -p ${{ runner.temp }}/digests
digest_full="${{ steps.build_web_image_platform.outputs.digest }}"
digest_sha="${digest_full#sha256:}"
echo "Digest SHA for Web ${{ matrix.platform }}: ${digest_sha}"
echo "${digest_sha}" > "${{ runner.temp }}/digests/web-${{ matrix.platform }}.sha"
- name: Upload Web digest file
uses: actions/upload-artifact@v4
with:
name: web-digest-${{ matrix.platform }}
path: ${{ runner.temp }}/digests/web-${{ matrix.platform }}.sha
if-no-files-found: error
retention-days: 1
- name: Set Web Package Visibility to Public
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
ORG_NAME: ${{ github.repository_owner }}
run: |
echo "Attempting to set visibility for $ORG_NAME/${{ env.WEB_IMAGE_NAME }}"
RESPONSE_CODE=$(curl -L -s -o /dev/null -w "%{http_code}" -X PATCH \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer $GH_TOKEN" \
-H "X-GitHub-Api-Version: 2022-11-28" \
"https://api.github.com/orgs/$ORG_NAME/packages/container/${{ env.WEB_IMAGE_NAME }}" \
-d '{"visibility":"public"}')
if [ "$RESPONSE_CODE" -eq 200 ] || [ "$RESPONSE_CODE" -eq 204 ]; then
echo "Package $ORG_NAME/${{ env.WEB_IMAGE_NAME }} visibility set to public successfully."
else
echo "Failed to set package $ORG_NAME/${{ env.WEB_IMAGE_NAME }} visibility to public. HTTP Status: $RESPONSE_CODE"
# Optionally, fail the step: exit 1
fi
merge_api_manifests:
name: Merge API Manifests
runs-on: blacksmith-4vcpu-ubuntu-2204
needs: [prepare_docker_release_info, build_and_push_api]
if: needs.prepare_docker_release_info.outputs.api_version_found == 'true'
steps:
- name: Download API digests
uses: actions/download-artifact@v4
with:
path: ${{ runner.temp }}/all_api_digests
pattern: api-digest-*
merge-multiple: true
- name: Log in to Docker Registry
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
- name: Docker meta for API Manifest
id: meta_api_manifest
uses: docker/metadata-action@v5
with:
images: ${{ env.DOCKER_REGISTRY_OWNER }}/${{ env.API_IMAGE_NAME }}
tags: |
type=semver,pattern={{version}},value=${{ needs.prepare_docker_release_info.outputs.api_version }}
type=sha,format=short
type=raw,value=latest
# Ensure DOCKER_METADATA_OUTPUT_JSON is populated for the next step
# outputs: |
# json
- name: Create and push API manifest list
env:
API_IMAGE_FULL_NAME: ${{ env.DOCKER_REGISTRY_OWNER }}/${{ env.API_IMAGE_NAME }}
working-directory: ${{ runner.temp }}/all_api_digests
run: |
echo "Listing downloaded API digests in $(pwd):"
ls -lR .
TAG_ARGS=$(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON")
echo "Generated tag arguments for API manifest: $TAG_ARGS"
DIGEST_FILES_FOUND=$(find . -type f -name '*.sha' -print)
if [ -z "$DIGEST_FILES_FOUND" ]; then
echo "Error: No API digest files (*.sha) found."
exit 1
fi
IMAGE_PLUS_DIGEST_ARGS=""
for digest_file_path in $DIGEST_FILES_FOUND; do
sha_value=$(cat "$digest_file_path")
IMAGE_PLUS_DIGEST_ARGS="$IMAGE_PLUS_DIGEST_ARGS ${API_IMAGE_FULL_NAME}@sha256:${sha_value}"
done
echo "API Manifest images with digests: $IMAGE_PLUS_DIGEST_ARGS"
if [ -z "$IMAGE_PLUS_DIGEST_ARGS" ]; then
echo "Error: No API digests were processed to create the manifest."
exit 1
fi
docker buildx imagetools create $TAG_ARGS $IMAGE_PLUS_DIGEST_ARGS
merge_web_manifests:
name: Merge Web Manifests
runs-on: blacksmith-4vcpu-ubuntu-2204
needs: [prepare_docker_release_info, build_and_push_web]
if: needs.prepare_docker_release_info.outputs.web_version_found == 'true'
steps:
- name: Download Web digests
uses: actions/download-artifact@v4
with:
path: ${{ runner.temp }}/all_web_digests
pattern: web-digest-*
merge-multiple: true
- name: Log in to Docker Registry
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
- name: Docker meta for Web Manifest
id: meta_web_manifest
uses: docker/metadata-action@v5
with:
images: ${{ env.DOCKER_REGISTRY_OWNER }}/${{ env.WEB_IMAGE_NAME }}
tags: |
type=semver,pattern={{version}},value=${{ needs.prepare_docker_release_info.outputs.web_version }}
type=sha,format=short
type=raw,value=latest
# outputs: |
# json
- name: Create and push Web manifest list
env:
WEB_IMAGE_FULL_NAME: ${{ env.DOCKER_REGISTRY_OWNER }}/${{ env.WEB_IMAGE_NAME }}
working-directory: ${{ runner.temp }}/all_web_digests
run: |
echo "Listing downloaded Web digests in $(pwd):"
ls -lR .
TAG_ARGS=$(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON")
echo "Generated tag arguments for Web manifest: $TAG_ARGS"
DIGEST_FILES_FOUND=$(find . -type f -name '*.sha' -print)
if [ -z "$DIGEST_FILES_FOUND" ]; then
echo "Error: No Web digest files (*.sha) found."
exit 1
fi
IMAGE_PLUS_DIGEST_ARGS=""
for digest_file_path in $DIGEST_FILES_FOUND; do
sha_value=$(cat "$digest_file_path")
IMAGE_PLUS_DIGEST_ARGS="$IMAGE_PLUS_DIGEST_ARGS ${WEB_IMAGE_FULL_NAME}@sha256:${sha_value}"
done
echo "Web Manifest images with digests: $IMAGE_PLUS_DIGEST_ARGS"
if [ -z "$IMAGE_PLUS_DIGEST_ARGS" ]; then
echo "Error: No Web digests were processed to create the manifest."
exit 1
fi
docker buildx imagetools create $TAG_ARGS $IMAGE_PLUS_DIGEST_ARGS