ruslanmv's picture
Fist commit
8c4c4be
name: 📦 Publish Docker (Docker Hub)
on:
release:
types: [published]
workflow_dispatch:
inputs:
version:
description: "Release tag (e.g., v1.2.3 or 1.2.3)"
required: true
permissions:
contents: read
concurrency:
group: dockerhub-publish-a2a-validator
cancel-in-progress: true
jobs:
build-and-push:
name: Build & Push (Docker Hub)
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
# Normalize version from release tag or manual input
- name: Derive release version
id: version
shell: bash
run: |
if [ "${{ github.event_name }}" = "release" ]; then
RAW="${GITHUB_REF#refs/tags/}"
else
RAW="${{ github.event.inputs.version }}"
fi
if [ -z "$RAW" ]; then
echo "Version not provided."; exit 1
fi
if [[ "$RAW" =~ ^v ]]; then
RELEASE_TAG="$RAW"
SEMVER="${RAW#v}"
else
RELEASE_TAG="v$RAW"
SEMVER="$RAW"
fi
echo "RELEASE_TAG=$RELEASE_TAG" >> $GITHUB_ENV
echo "SEMVER=$SEMVER" >> $GITHUB_ENV
echo "SHORT_SHA=${GITHUB_SHA::7}" >> $GITHUB_ENV
echo "BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> $GITHUB_ENV
echo "Resolved RELEASE_TAG=${RELEASE_TAG}, SEMVER=${SEMVER}, SHORT_SHA=${SHORT_SHA}"
# docker.io requires lowercase namespace
- name: Compute image name (lowercase)
id: img
shell: bash
run: |
USER_RAW="${{ secrets.DOCKERHUB_USERNAME }}"
USER_LC="${USER_RAW,,}"
IMAGE="docker.io/${USER_LC}/a2a-validator"
echo "IMAGE=$IMAGE" >> $GITHUB_ENV
echo "Image: $IMAGE"
- name: Set up QEMU (multi-arch)
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Docker Hub login
uses: docker/login-action@v3
with:
registry: docker.io
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Docker metadata (tags & labels)
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.IMAGE }}
flavor: |
latest=false
tags: |
# stable semver tags (always)
type=raw,value=v${{ env.SEMVER }}
type=semver,pattern={{version}},value=${{ env.SEMVER }}
type=semver,pattern={{major}}.{{minor}},value=${{ env.SEMVER }}
type=semver,pattern={{major}},value=${{ env.SEMVER }}
# short sha tag (always)
type=raw,value=sha-${{ env.SHORT_SHA }}
# latest only on release
type=raw,value=latest,enable=${{ github.event_name == 'release' }}
labels: |
org.opencontainers.image.title=a2a-validator
org.opencontainers.image.description=A2A Validator — web inspector & debugger for A2A agents
org.opencontainers.image.url=https://github.com/${{ github.repository }}
org.opencontainers.image.source=https://github.com/${{ github.repository }}
org.opencontainers.image.version=${{ env.SEMVER }}
org.opencontainers.image.revision=${{ github.sha }}
org.opencontainers.image.created=${{ env.BUILD_DATE }}
# Build & push using your Dockerfile
- name: Build & push (Docker Hub)
id: build
uses: docker/build-push-action@v6
with:
context: .
file: ./Dockerfile
push: true
platforms: linux/amd64,linux/arm64
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
build-args: |
BUILD_VERSION=${{ env.SEMVER }}
BUILD_COMMIT=${{ github.sha }}
BUILD_DATE=${{ env.BUILD_DATE }}
# Guard 1: The image must NOT contain a baked /app/.env
- name: Sanity guard no baked .env
shell: bash
run: |
REF="$(echo "${{ steps.meta.outputs.tags }}" | head -n1)"
docker run --rm --entrypoint /bin/bash "$REF" -lc 'test ! -f /app/.env'
echo "OK: no baked /app/.env"
# Guard 2: The image must NOT contain a SQLite db (e.g. *.sqlite)
- name: Sanity guard no baked SQLite DB
shell: bash
run: |
REF="$(echo "${{ steps.meta.outputs.tags }}" | head -n1)"
docker run --rm --entrypoint /bin/bash "$REF" -lc 'if find /app -maxdepth 6 -name "*.sqlite" -o -name "*.db" | grep -q .; then echo "Found SQLite DB in image"; exit 1; fi'
echo "OK: no baked SQLite DB"
- name: Inspect multi-arch manifest (release tag)
if: always()
shell: bash
run: |
echo "Inspecting v${SEMVER}…"
docker buildx imagetools inspect "${IMAGE}:v${SEMVER}"
if [ "${{ github.event_name }}" = "release" ]; then
echo "Inspecting latest…"
docker buildx imagetools inspect "${IMAGE}:latest"
fi