Skip to content

ci: standardize on main-<7sha> + semver-on-tag #90

ci: standardize on main-<7sha> + semver-on-tag

ci: standardize on main-<7sha> + semver-on-tag #90

name: Build and Push Docker images
# Multi-arch (amd64 + arm64) build with native runners.
# Two images are produced:
# public.ecr.aws/r4g1k2s3/vcon-dev/vcon-server-api
# public.ecr.aws/r4g1k2s3/vcon-dev/vcon-server-conserver
#
# Tag scheme:
# - on `push: main` → `main-<7sha>` + `latest`
# - on `push: tags: ['v*']` → `1.2.3`, `1.2`, `1` (semver, no `v` prefix in image tag)
on:
push:
branches: [main]
tags: ['v*']
jobs:
prepare:
runs-on: ubuntu-latest
outputs:
version: ${{ steps.version.outputs.version }}
short_sha: ${{ steps.version.outputs.short_sha }}
build_time: ${{ steps.version.outputs.build_time }}
steps:
- name: Compute version metadata
id: version
run: |
SHORT_SHA="${GITHUB_SHA::7}"
BUILD_TIME=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
if [[ "${GITHUB_REF}" == refs/tags/v* ]]; then
VERSION="${GITHUB_REF#refs/tags/v}" # v1.2.3 → 1.2.3
else
VERSION="main-${SHORT_SHA}"
fi
{
echo "short_sha=${SHORT_SHA}"
echo "version=${VERSION}"
echo "build_time=${BUILD_TIME}"
} >> "$GITHUB_OUTPUT"
build:
needs: prepare
runs-on: ${{ matrix.runner }}
permissions:
contents: read
packages: write
strategy:
matrix:
include:
- service: api
dockerfile: ./docker/Dockerfile.api
image: public.ecr.aws/r4g1k2s3/vcon-dev/vcon-server-api
platform: linux/amd64
platform_tag: amd64
runner: ubuntu-latest
- service: api
dockerfile: ./docker/Dockerfile.api
image: public.ecr.aws/r4g1k2s3/vcon-dev/vcon-server-api
platform: linux/arm64
platform_tag: arm64
runner: ubuntu-24.04-arm
- service: conserver
dockerfile: ./docker/Dockerfile.conserver
image: public.ecr.aws/r4g1k2s3/vcon-dev/vcon-server-conserver
platform: linux/amd64
platform_tag: amd64
runner: ubuntu-latest
- service: conserver
dockerfile: ./docker/Dockerfile.conserver
image: public.ecr.aws/r4g1k2s3/vcon-dev/vcon-server-conserver
platform: linux/arm64
platform_tag: arm64
runner: ubuntu-24.04-arm
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Amazon ECR Public
uses: docker/login-action@v3
with:
registry: public.ecr.aws
username: ${{ secrets.AWS_ACCESS_KEY }}
password: ${{ secrets.AWS_SECRET }}
- name: Build and push ${{ matrix.service }} (${{ matrix.platform_tag }})
uses: docker/build-push-action@v5
with:
context: .
file: ${{ matrix.dockerfile }}
platforms: ${{ matrix.platform }}
push: true
cache-from: type=gha,scope=${{ matrix.service }}-${{ matrix.platform_tag }}
cache-to: type=gha,mode=max,scope=${{ matrix.service }}-${{ matrix.platform_tag }}
tags: ${{ matrix.image }}:${{ needs.prepare.outputs.version }}-${{ matrix.platform_tag }}
build-args: |
VCON_SERVER_VERSION=${{ needs.prepare.outputs.version }}
VCON_SERVER_GIT_COMMIT=${{ needs.prepare.outputs.short_sha }}
VCON_SERVER_BUILD_TIME=${{ needs.prepare.outputs.build_time }}
merge:
needs: [prepare, build]
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
strategy:
matrix:
include:
- service: api
image: public.ecr.aws/r4g1k2s3/vcon-dev/vcon-server-api
- service: conserver
image: public.ecr.aws/r4g1k2s3/vcon-dev/vcon-server-conserver
steps:
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Amazon ECR Public
uses: docker/login-action@v3
with:
registry: public.ecr.aws
username: ${{ secrets.AWS_ACCESS_KEY }}
password: ${{ secrets.AWS_SECRET }}
- name: Create multi-arch manifests for ${{ matrix.service }}
env:
IMAGE: ${{ matrix.image }}
VERSION: ${{ needs.prepare.outputs.version }}
run: |
AMD64="${IMAGE}:${VERSION}-amd64"
ARM64="${IMAGE}:${VERSION}-arm64"
# Always emit a unique version-stamped tag (main-<sha> on main, 1.2.3 on tag).
docker buildx imagetools create --tag "${IMAGE}:${VERSION}" "${AMD64}" "${ARM64}"
if [[ "${GITHUB_REF}" == refs/heads/main ]]; then
docker buildx imagetools create --tag "${IMAGE}:latest" "${AMD64}" "${ARM64}"
fi
if [[ "${GITHUB_REF}" == refs/tags/v* ]]; then
# Semver aliases: 1.2.3 already exists; also emit 1.2 and 1.
MAJOR="${VERSION%%.*}"
MINOR="${VERSION%.*}"
if [[ "${MINOR}" != "${VERSION}" ]]; then
docker buildx imagetools create --tag "${IMAGE}:${MINOR}" "${AMD64}" "${ARM64}"
fi
docker buildx imagetools create --tag "${IMAGE}:${MAJOR}" "${AMD64}" "${ARM64}"
fi
release:
needs: [prepare, merge]
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/v')
permissions:
contents: write
steps:
- name: Create GitHub Release
uses: softprops/action-gh-release@v1
with:
tag_name: ${{ github.ref_name }}
name: Release ${{ github.ref_name }}
body: |
## Release ${{ github.ref_name }}
**Commit:** `${{ needs.prepare.outputs.short_sha }}`
**Build Time:** `${{ needs.prepare.outputs.build_time }}`
### Docker Images (linux/amd64 + linux/arm64)
```bash
docker pull public.ecr.aws/r4g1k2s3/vcon-dev/vcon-server-api:${{ needs.prepare.outputs.version }}
docker pull public.ecr.aws/r4g1k2s3/vcon-dev/vcon-server-conserver:${{ needs.prepare.outputs.version }}
```
draft: false
prerelease: false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Summary
run: |
{
echo "## Build Summary"
echo ""
echo "| Property | Value |"
echo "|----------|-------|"
echo "| **Version** | ${{ needs.prepare.outputs.version }} |"
echo "| **Git Commit** | ${{ needs.prepare.outputs.short_sha }} |"
echo "| **Build Time** | ${{ needs.prepare.outputs.build_time }} |"
echo ""
echo "### Docker Images Built (linux/amd64 + linux/arm64)"
echo "- \`vcon-server-api:${{ needs.prepare.outputs.version }}\`"
echo "- \`vcon-server-conserver:${{ needs.prepare.outputs.version }}\`"
} >> "$GITHUB_STEP_SUMMARY"