Skip to content

Build from source → GHCR #2

Build from source → GHCR

Build from source → GHCR #2

name: Build from source → GHCR
on:
push:
branches: [main, intarweb-dev]
paths:
- 'Dockerfile'
- 'pyproject.toml'
- 'uv.lock'
- 'mcp_python_interpreter/**'
- '.github/workflows/build-from-source.yml'
workflow_dispatch:
permissions:
contents: read
packages: write
id-token: write
env:
IMAGE: ghcr.io/${{ github.repository_owner }}/mcp-python-interpreter
PLATFORMS: linux/amd64,linux/arm64
jobs:
build:
runs-on: ubuntu-latest
outputs:
sha-tag: ${{ steps.sha.outputs.short }}
steps:
- uses: actions/checkout@v4
with:
persist-credentials: false
fetch-depth: 0
- uses: docker/setup-qemu-action@v3
- uses: docker/setup-buildx-action@v3
- uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: 🏷️ Compute short SHA
id: sha
run: echo "short=${GITHUB_SHA:0:7}" >> "$GITHUB_OUTPUT"
- name: 🚀 Build & push :sha-${{ steps.sha.outputs.short }}
uses: docker/build-push-action@v6
id: build
with:
context: .
file: ./Dockerfile
platforms: ${{ env.PLATFORMS }}
push: true
provenance: mode=max
sbom: true
tags: ${{ env.IMAGE }}:sha-${{ steps.sha.outputs.short }}
annotations: |
index:org.opencontainers.image.source=https://github.com/${{ github.repository_owner }}/mcp-python-interpreter
index:org.opencontainers.image.revision=${{ github.sha }}
index:org.opencontainers.image.description=mcp-python-interpreter — from-source build of upstream HEAD + open PR patches
- name: 🔬 Smoke test (image starts + binds port 8000)
env:
IMAGE: ${{ env.IMAGE }}
SHA_SHORT: ${{ steps.sha.outputs.short }}
run: |
set -e
docker pull "${IMAGE}:sha-${SHA_SHORT}"
# Start container detached on host port 18000 -> container 8000.
cid=$(docker run -d -p 18000:8000 "${IMAGE}:sha-${SHA_SHORT}")
trap "docker rm -f $cid >/dev/null 2>&1 || true" EXIT
# Wait up to 15s for the streamable-http endpoint to be reachable.
for i in $(seq 1 15); do
if docker exec "$cid" sh -c "python3 -c 'import socket; s=socket.socket(); s.settimeout(2); s.connect((\"127.0.0.1\", 8000))'" >/dev/null 2>&1; then
echo " ✓ container listening on 8000 after ${i}s"
break
fi
sleep 1
if [ "$i" = "15" ]; then
echo " ✗ container never bound port 8000"
docker logs "$cid" || true
exit 1
fi
done
# GET on /mcp should return some HTTP status (not connection refused).
# FastMCP returns 405/400 for GET (POST-only) which is fine — we just
# care that the HTTP server is alive.
code=$(curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:18000/mcp || echo "000")
echo " HTTP /mcp → $code"
if [ "$code" = "000" ]; then
echo " ✗ /mcp not reachable"
docker logs "$cid" || true
exit 1
fi
echo " ✓ smoke passed"
- name: 🏷️ Promote :latest (smoke passed, intarweb-dev branch only)
if: github.ref == 'refs/heads/intarweb-dev'
env:
IMAGE: ${{ env.IMAGE }}
SHA_SHORT: ${{ steps.sha.outputs.short }}
run: |
docker buildx imagetools create \
--tag "${IMAGE}:latest" \
"${IMAGE}:sha-${SHA_SHORT}"