Spaces:
Sleeping
Sleeping
| 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 | |