Skip to content

docker

docker #2

Workflow file for this run

name: docker
# Build and publish multi-arch images to ghcr.io on every git tag (v*).
#
# Tags produced for ``v12.3.0``:
# ghcr.io/vbcherepanov/total-agent-memory:12.3.0
# ghcr.io/vbcherepanov/total-agent-memory:12.3
# ghcr.io/vbcherepanov/total-agent-memory:12
# ghcr.io/vbcherepanov/total-agent-memory:latest
#
# Also runnable manually via workflow_dispatch with an explicit tag — used
# to backfill missing ghcr tags (e.g. 12.1, 12.2) without cutting a new
# git tag.
#
# Smoke step: pull the freshly-pushed amd64 image, run it, hit /healthz,
# fail the workflow if 200 doesn't come back within 60s.
on:
push:
tags:
- 'v*'
workflow_dispatch:
inputs:
tag:
description: 'Version to publish (e.g. 12.3.0). Defaults to git ref tag.'
required: false
default: ''
permissions:
contents: read
packages: write
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository_owner }}/total-agent-memory
jobs:
build:
runs-on: ubuntu-latest
outputs:
version: ${{ steps.version.outputs.version }}
steps:
- uses: actions/checkout@v4
- name: Resolve version
id: version
run: |
if [ -n "${{ inputs.tag }}" ]; then
v="${{ inputs.tag }}"
else
v="${GITHUB_REF_NAME#v}"
fi
if ! echo "$v" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+$'; then
echo "::error::expected semver MAJOR.MINOR.PATCH, got '$v'"
exit 1
fi
echo "version=$v" >> "$GITHUB_OUTPUT"
echo "major=$(echo "$v" | cut -d. -f1)" >> "$GITHUB_OUTPUT"
echo "minor=$(echo "$v" | cut -d. -f1-2)" >> "$GITHUB_OUTPUT"
- name: Set up QEMU (for arm64 cross-build)
uses: docker/setup-qemu-action@v3.6.0
- name: Set up Buildx
uses: docker/setup-buildx-action@v3.10.0
- name: Login to ghcr
uses: docker/login-action@v3.4.0
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build + push (amd64 + arm64)
uses: docker/build-push-action@v6.18.0
with:
context: .
file: ./Dockerfile
platforms: linux/amd64,linux/arm64
push: true
provenance: false
tags: |
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.version }}
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.minor }}
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.major }}
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
labels: |
org.opencontainers.image.title=total-agent-memory
org.opencontainers.image.description=Persistent memory MCP server for AI coding agents
org.opencontainers.image.source=https://github.com/${{ github.repository }}
org.opencontainers.image.version=${{ steps.version.outputs.version }}
org.opencontainers.image.licenses=MIT
org.opencontainers.image.url=https://totalmemory.dev
cache-from: type=gha
cache-to: type=gha,mode=max
smoke:
needs: build
runs-on: ubuntu-latest
steps:
- name: Pull just-pushed image (amd64)
run: |
docker pull ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.build.outputs.version }}
- name: Run + probe /healthz + /api/stats
run: |
set -e
docker volume create tam-ci-data
docker run -d --name tam-ci \
-p 37737:37737 \
-v tam-ci-data:/data \
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.build.outputs.version }}
# Wait up to 60s for /healthz to come up.
for i in $(seq 1 30); do
if curl -fsS http://127.0.0.1:37737/healthz >/dev/null 2>&1; then
echo "✓ /healthz responding after ${i}*2s"
break
fi
if [ "$i" = "30" ]; then
echo "::error::/healthz did not respond within 60s"
docker logs tam-ci
exit 1
fi
sleep 2
done
# Wait up to 60s for /api/stats (depends on DB migration).
for i in $(seq 1 30); do
code=$(curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:37737/api/stats)
if [ "$code" = "200" ]; then
echo "✓ /api/stats → 200 after ${i}*2s"
break
fi
if [ "$i" = "30" ]; then
echo "::error::/api/stats did not return 200 within 60s (last: $code)"
docker logs tam-ci
exit 1
fi
sleep 2
done
# Check Docker's own healthcheck reports healthy.
for i in $(seq 1 20); do
h=$(docker inspect tam-ci --format '{{.State.Health.Status}}')
if [ "$h" = "healthy" ]; then
echo "✓ docker healthcheck = healthy"
break
fi
if [ "$i" = "20" ]; then
echo "::error::docker healthcheck never reached 'healthy' (last: $h)"
docker logs tam-ci
exit 1
fi
sleep 3
done
- name: Cleanup
if: always()
run: |
docker rm -f tam-ci 2>/dev/null || true
docker volume rm tam-ci-data 2>/dev/null || true