Merge pull request #21 from FakeOverFlow/shreyas/tags #46
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Build and Push Backend Image | |
| on: | |
| push: | |
| branches: [ main ] | |
| paths: | |
| - '.github/workflows/build-push-backend-image.yml' | |
| - 'apps/fakeoverflow-api/**' | |
| workflow_dispatch: | |
| permissions: | |
| contents: read | |
| packages: write | |
| env: | |
| REGISTRY: ghcr.io | |
| IMAGE_NAME: ${{ github.repository }}-backend | |
| jobs: | |
| build: | |
| name: Build and Push (${{ matrix.platform }}) | |
| runs-on: ${{ matrix.runs_on }} | |
| timeout-minutes: 30 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - arch: amd64 | |
| platform: linux/amd64 | |
| runs_on: ubuntu-latest | |
| - arch: arm64 | |
| platform: linux/arm64 | |
| runs_on: ubuntu-24.04-arm | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - name: Log in to the Container registry | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Extract Docker metadata with arch suffix | |
| id: meta | |
| uses: docker/metadata-action@v5 | |
| with: | |
| images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} | |
| tags: | | |
| type=ref,event=branch | |
| type=semver,pattern={{version}} | |
| type=semver,pattern={{major}}.{{minor}} | |
| type=semver,pattern={{major}} | |
| type=raw,value=latest | |
| flavor: | | |
| latest=auto | |
| suffix=-${{ matrix.arch }} | |
| - name: Verify Dockerfile exists | |
| run: | | |
| DOCKERFILE_PATH="apps/fakeoverflow-api/FakeOverFlow/FakeoverFlow.Backend.Http.Api/Dockerfile" | |
| if [ ! -f "$DOCKERFILE_PATH" ]; then | |
| echo "Error: Dockerfile not found at $DOCKERFILE_PATH" | |
| exit 1 | |
| fi | |
| - name: Build and push per-arch image | |
| id: build | |
| uses: docker/build-push-action@v6 | |
| with: | |
| context: apps/fakeoverflow-api/FakeOverFlow | |
| file: apps/fakeoverflow-api/FakeOverFlow/FakeoverFlow.Backend.Http.Api/Dockerfile | |
| push: true | |
| platforms: ${{ matrix.platform }} | |
| build-args: | | |
| BUILD_CONFIGURATION=Release | |
| tags: ${{ steps.meta.outputs.tags }} | |
| labels: ${{ steps.meta.outputs.labels }} | |
| cache-from: type=gha,scope=${{ matrix.arch }} | |
| cache-to: type=gha,mode=max,scope=${{ matrix.arch }} | |
| provenance: false | |
| sbom: false | |
| manifest: | |
| name: Create and Push Multi-Arch Manifests | |
| runs-on: ubuntu-latest | |
| needs: build | |
| steps: | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - name: Log in to the Container registry | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Extract base Docker metadata (no arch suffix) | |
| id: meta | |
| uses: docker/metadata-action@v5 | |
| with: | |
| images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} | |
| tags: | | |
| type=ref,event=branch | |
| type=semver,pattern={{version}} | |
| type=semver,pattern={{major}}.{{minor}} | |
| type=semver,pattern={{major}} | |
| type=raw,value=latest,enable={{is_default_branch}} | |
| flavor: | | |
| latest=auto | |
| - name: Create and push manifest list for each tag | |
| run: | | |
| set -euo pipefail | |
| # Function to check if image exists | |
| check_image_exists() { | |
| local image="$1" | |
| if docker buildx imagetools inspect "$image" >/dev/null 2>&1; then | |
| echo "✓ Image exists: $image" | |
| return 0 | |
| else | |
| echo "✗ Image not found: $image" | |
| return 1 | |
| fi | |
| } | |
| echo "Creating multi-arch manifests for the following tags:" | |
| echo "${{ steps.meta.outputs.tags }}" | |
| echo "---" | |
| # Convert tags to array and process each one | |
| IFS=$'\n' read -rd '' -a tags_array <<< "${{ steps.meta.outputs.tags }}" || true | |
| for tag in "${tags_array[@]}"; do | |
| if [ -n "$tag" ]; then | |
| echo "Processing tag: $tag" | |
| # Check if both arch-specific images exist | |
| amd64_image="${tag}-amd64" | |
| arm64_image="${tag}-arm64" | |
| if check_image_exists "$amd64_image" && check_image_exists "$arm64_image"; then | |
| echo "Creating manifest $tag from $amd64_image and $arm64_image" | |
| docker buildx imagetools create \ | |
| --tag "$tag" \ | |
| "$amd64_image" \ | |
| "$arm64_image" | |
| echo "✓ Successfully created manifest for $tag" | |
| else | |
| echo "⚠️ Skipping $tag due to missing arch-specific images" | |
| exit 1 | |
| fi | |
| echo "---" | |
| fi | |
| done | |
| echo "All manifests created successfully!" | |
| - name: Cleanup arch-specific tags to reduce SHA clutter in GHCR | |
| env: | |
| REGISTRY: ${{ env.REGISTRY }} | |
| IMAGE_NAME: ${{ env.IMAGE_NAME }} | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| set -euo pipefail | |
| IMAGE_LOWER=$(echo "$IMAGE_NAME" | tr '[:upper:]' '[:lower:]') | |
| ACCEPT="application/vnd.oci.image.manifest.v1+json, application/vnd.docker.distribution.manifest.v2+json" | |
| echo "Cleaning up arch-specific tags for: ${IMAGE_LOWER} on ${REGISTRY}" | |
| IFS=$'\n' read -rd '' -a tags_array <<< "${{ steps.meta.outputs.tags }}" || true | |
| for tag in "${tags_array[@]}"; do | |
| if [ -z "$tag" ]; then continue; fi | |
| for arch in amd64 arm64; do | |
| ref="${tag}-${arch}" | |
| echo "Processing tag to delete: $ref" | |
| # Get digest for the tag | |
| digest=$(curl -fsSLI \ | |
| -H "Authorization: Bearer ${GITHUB_TOKEN}" \ | |
| -H "Accept: ${ACCEPT}" \ | |
| "https://${REGISTRY}/v2/${IMAGE_LOWER}/manifests/${ref}" \ | |
| | awk -F': ' '/Docker-Content-Digest/ {gsub("\r",""); print $2; exit}') || true | |
| if [ -n "${digest:-}" ]; then | |
| echo "Deleting manifest by digest: ${digest} (for ${ref})" | |
| curl -fsSL -X DELETE \ | |
| -H "Authorization: Bearer ${GITHUB_TOKEN}" \ | |
| "https://${REGISTRY}/v2/${IMAGE_LOWER}/manifests/${digest}" \ | |
| && echo "✓ Deleted ${ref}" \ | |
| || echo "⚠️ Failed to delete ${ref} (it may already be removed)" | |
| else | |
| echo "No digest found for ${ref}; skipping." | |
| fi | |
| done | |
| done | |
| - name: Verify multi-arch manifests | |
| run: | | |
| echo "Verifying created manifests support both architectures:" | |
| IFS=$'\n' read -rd '' -a tags_array <<< "${{ steps.meta.outputs.tags }}" || true | |
| for tag in "${tags_array[@]}"; do | |
| if [ -n "$tag" ]; then | |
| echo "Checking $tag:" | |
| docker buildx imagetools inspect "$tag" --format '{{json .Manifest}}' | jq -r '.manifests[] | " - \(.platform.architecture)/\(.platform.os)"' | |
| fi | |
| done |