Skip to content

Docker

Docker #43

Workflow file for this run

name: Docker
# Triggers:
# 1. workflow_run after Release completes successfully -- THE canonical
# path. We download the wheel artifact that release.yml uploaded and
# install from it inside the container, bypassing PyPI entirely.
# 2. workflow_dispatch -- manual retries.
#
# The push-tag trigger was REMOVED in v0.5.0. When a v*.*.* tag is
# pushed, GitHub fires release.yml AND docker.yml in parallel; the
# docker.yml run starts immediately and the dist/ artifact doesn't
# exist yet (release.yml hasn't finished building it), AND PyPI
# doesn't have the new version yet either. Both paths in the
# Dockerfile fail. The workflow_run path waits for release.yml to
# fully complete, then downloads the wheel artifact, which is the
# reliable path.
on:
workflow_run:
workflows: ["Release"]
types: [completed]
workflow_dispatch:
inputs:
ref:
description: "Git ref to build (defaults to the workflow's default branch)."
required: false
default: ""
permissions:
contents: read
packages: write
id-token: write
actions: read
concurrency:
# Dedupe push-tag + workflow_run firings for the same tag.
group: docker-${{ github.event.workflow_run.head_sha || github.ref }}
cancel-in-progress: true
jobs:
build-and-push:
name: Build + push container to GHCR
runs-on: ubuntu-latest
# When triggered by workflow_run, only proceed if Release succeeded.
# Other triggers (push tag, workflow_dispatch) always run.
if: >-
github.event_name != 'workflow_run' ||
github.event.workflow_run.conclusion == 'success'
steps:
- name: Resolve checkout ref
id: ref
run: |
set -e
case "${{ github.event_name }}" in
workflow_dispatch)
ref="${{ github.event.inputs.ref }}"
;;
workflow_run)
ref="${{ github.event.workflow_run.head_branch }}"
;;
*)
ref="${GITHUB_REF}"
;;
esac
if [ -z "$ref" ]; then ref="${GITHUB_REF}"; fi
echo "ref=$ref" >> "$GITHUB_OUTPUT"
- uses: actions/checkout@v4
with:
ref: ${{ steps.ref.outputs.ref }}
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Derive image metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ghcr.io/valani9/vstack
tags: |
type=ref,event=tag
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
type=raw,value=latest,enable={{is_default_branch}}
labels: |
org.opencontainers.image.title=vstack
org.opencontainers.image.description=Organizational behavior, practiced on AI agents.
org.opencontainers.image.licenses=MIT
org.opencontainers.image.source=https://github.com/valani9/vstack
org.opencontainers.image.url=https://pypi.org/project/valanistack/
org.opencontainers.image.authors=Ilhan Valani <valani@bu.edu>
- name: Compute build argument VSTACK_VERSION
id: ver
run: |
set -e
ref="${{ steps.ref.outputs.ref }}"
ref="${ref##*/}"
case "$ref" in
v[0-9]*)
echo "version=${ref#v}" >> "$GITHUB_OUTPUT"
;;
*)
echo "version=" >> "$GITHUB_OUTPUT"
;;
esac
# On workflow_run, download the wheel that release.yml just built
# and uploaded as an artifact (artifact name set in release.yml).
# Skips the PyPI CDN race entirely.
- name: Download wheel artifact from the triggering Release run
if: github.event_name == 'workflow_run'
uses: actions/download-artifact@v4
with:
name: release-dist
path: dist/
run-id: ${{ github.event.workflow_run.id }}
github-token: ${{ secrets.GITHUB_TOKEN }}
- name: Ensure dist/ exists for the docker build context
run: |
set -e
mkdir -p dist
ls -la dist/ || true
- name: Build + push image
uses: docker/build-push-action@v6
with:
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
VSTACK_VERSION=${{ steps.ver.outputs.version }}
provenance: true
sbom: true