docker-publish.ymlβ’11.3 kB
name: Build and Publish Docker Image
on:
pull_request:
branches: [publish-docker]
release:
types: [published]
# Manual trigger for emergency releases
workflow_dispatch:
inputs:
sync_with_npm:
description: 'Sync version with NPM package'
required: false
default: true
type: boolean
force_version:
description: 'Force specific version (optional)'
required: false
type: string
# Make this workflow reusable
workflow_call:
inputs:
sync_with_npm:
description: 'Sync version with NPM package'
required: false
default: true
type: boolean
force_version:
description: 'Force specific version (optional)'
required: false
type: string
env:
REGISTRY: docker.io
IMAGE_NAME: hiveacademy/anubis
PACKAGE_NAME: '@hive-academy/anubis'
DATABASE_URL: 'file:./prisma/.anubis/workflow.db'
jobs:
build-and-publish:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
id-token: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Node.js (for version sync)
uses: actions/setup-node@v4
with:
node-version: '22'
cache: 'npm'
# ===================================================================
# π€ INTELLIGENT VERSION SYNCHRONIZATION
# ===================================================================
- name: Intelligent version synchronization
id: version_sync
run: |
echo "π€ Starting intelligent version synchronization..."
# Get current package.json version
PACKAGE_VERSION=$(node -p "require('./package.json').version")
echo "π¦ Package.json version: $PACKAGE_VERSION"
# Determine target version
if [ -n "${{ inputs.force_version }}" ]; then
TARGET_VERSION="${{ inputs.force_version }}"
VERSION_STRATEGY="forced"
echo "π― Using forced version: $TARGET_VERSION"
elif [ "${{ inputs.sync_with_npm }}" = "true" ]; then
# Get NPM version for sync
NPM_VERSION=$(npm view ${{ env.PACKAGE_NAME }} version 2>/dev/null || echo "0.0.0")
echo "π¦ NPM version: $NPM_VERSION"
# Use NPM version if it's newer than package.json
if [ "$NPM_VERSION" != "0.0.0" ]; then
TARGET_VERSION="$NPM_VERSION"
VERSION_STRATEGY="npm-sync"
echo "π Syncing with NPM version: $TARGET_VERSION"
else
TARGET_VERSION="$PACKAGE_VERSION"
VERSION_STRATEGY="package-json"
echo "π¦ Using package.json version: $TARGET_VERSION"
fi
else
TARGET_VERSION="$PACKAGE_VERSION"
VERSION_STRATEGY="package-json"
echo "π¦ Using package.json version: $TARGET_VERSION"
fi
# Store version info
echo "target_version=$TARGET_VERSION" >> $GITHUB_OUTPUT
echo "version_strategy=$VERSION_STRATEGY" >> $GITHUB_OUTPUT
echo "package_version=$PACKAGE_VERSION" >> $GITHUB_OUTPUT
echo "π― Final target version: $TARGET_VERSION"
echo "π Version strategy: $VERSION_STRATEGY"
- name: Update Dockerfile version labels
run: |
TARGET_VERSION="${{ steps.version_sync.outputs.target_version }}"
echo "π·οΈ Updating Dockerfile version labels to: $TARGET_VERSION"
# Update version labels in Dockerfile
sed -i "s/LABEL version=\".*\"/LABEL version=\"$TARGET_VERSION\"/" Dockerfile
sed -i "s/LABEL org.opencontainers.image.version=\".*\"/LABEL org.opencontainers.image.version=\"$TARGET_VERSION\"/" Dockerfile
sed -i "s/ENV ANUBIS_VERSION=.*/ENV ANUBIS_VERSION=$TARGET_VERSION/" Dockerfile
echo "β
Dockerfile version labels updated"
# ===================================================================
# π³ DOCKER BUILD SETUP
# ===================================================================
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Docker Hub
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: hiveacademy
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}},value=v${{ steps.version_sync.outputs.target_version }}
type=semver,pattern={{major}}.{{minor}},value=v${{ steps.version_sync.outputs.target_version }}
type=semver,pattern={{major}},value=v${{ steps.version_sync.outputs.target_version }}
type=raw,value=latest,enable={{is_default_branch}}
type=raw,value=${{ steps.version_sync.outputs.target_version }}
labels: |
org.opencontainers.image.title=Anubis MCP Server
org.opencontainers.image.description=πΊ Intelligent Guidance for AI Workflows | MCP-compliant workflow intelligence system
org.opencontainers.image.vendor=Hive Academy
org.opencontainers.image.version=${{ steps.version_sync.outputs.target_version }}
org.opencontainers.image.url=https://github.com/Hive-Academy/Anubis-MCP
org.opencontainers.image.source=https://github.com/Hive-Academy/Anubis-MCP
org.opencontainers.image.documentation=https://github.com/Hive-Academy/Anubis-MCP#readme
org.opencontainers.image.licenses=MIT
maintainer=Hive Academy <abdallah@nghive.tech>
version=${{ steps.version_sync.outputs.target_version }}
anubis.version=${{ steps.version_sync.outputs.target_version }}
anubis.npm.sync=${{ inputs.sync_with_npm }}
anubis.version.strategy=${{ steps.version_sync.outputs.version_strategy }}
# ===================================================================
# π PRE-BUILD VALIDATION
# ===================================================================
- name: Database template verification
run: |
echo "π Verifying pre-seeded database template..."
if [ -f "prisma/.anubis/workflow.db" ]; then
DB_SIZE=$(ls -lh prisma/.anubis/workflow.db | awk '{print $5}')
echo "β
Pre-seeded database found: $DB_SIZE"
# Verify it's approximately the expected size (~589kB)
DB_SIZE_BYTES=$(stat -c%s prisma/.anubis/workflow.db)
if [ $DB_SIZE_BYTES -gt 500000 ] && [ $DB_SIZE_BYTES -lt 700000 ]; then
echo "β
Database size is within expected range (500kB-700kB)"
else
echo "β οΈ Database size ($DB_SIZE_BYTES bytes) is outside expected range"
echo "π§ Regenerating database template..."
mkdir -p prisma/.anubis
npm ci
npx prisma db push --accept-data-loss
npm run db:seed
fi
else
echo "β Pre-seeded database not found - regenerating..."
mkdir -p prisma/.anubis
npm ci
npx prisma db push --accept-data-loss
npm run db:seed
if [ -f "prisma/.anubis/workflow.db" ]; then
echo "β
Database template regenerated successfully"
else
echo "β Failed to generate database template"
exit 1
fi
fi
- name: Docker build test (PR only)
if: github.event_name == 'pull_request'
uses: docker/build-push-action@v5
with:
context: .
push: false
tags: ${{ env.IMAGE_NAME }}:test
platforms: linux/amd64
cache-from: type=gha
cache-to: type=gha,mode=max
build-args: |
NODE_ENV=production
DATABASE_URL=${{ env.DATABASE_URL }}
# ===================================================================
# π BUILD AND PUBLISH
# ===================================================================
- name: Build and push Docker image
if: github.event_name != 'pull_request'
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
platforms: linux/amd64,linux/arm64
cache-from: type=gha
cache-to: type=gha,mode=max
build-args: |
NODE_ENV=production
DATABASE_URL=${{ env.DATABASE_URL }}
# ===================================================================
# π POST-BUILD VERIFICATION
# ===================================================================
- name: Test Docker image
if: github.event_name != 'pull_request'
run: |
echo "π§ͺ Testing published Docker image..."
TARGET_VERSION="${{ steps.version_sync.outputs.target_version }}"
# Test image runs and shows version
docker run --rm ${{ env.IMAGE_NAME }}:$TARGET_VERSION --version
# Test MCP server functionality
timeout 10s docker run --rm ${{ env.IMAGE_NAME }}:$TARGET_VERSION || true
echo "β
Docker image test completed"
- name: Generate Docker health report
if: github.event_name != 'pull_request'
run: |
echo "π Generating Docker health report..."
TARGET_VERSION="${{ steps.version_sync.outputs.target_version }}"
# Get image size
IMAGE_SIZE=$(docker images ${{ env.IMAGE_NAME }}:$TARGET_VERSION --format "table {{.Size}}" | tail -n 1)
echo "## π³ Docker Image Health Report" >> $GITHUB_STEP_SUMMARY
echo "- **Image:** \`${{ env.IMAGE_NAME }}:$TARGET_VERSION\`" >> $GITHUB_STEP_SUMMARY
echo "- **Version Strategy:** ${{ steps.version_sync.outputs.version_strategy }}" >> $GITHUB_STEP_SUMMARY
echo "- **Size:** $IMAGE_SIZE" >> $GITHUB_STEP_SUMMARY
echo "- **Platforms:** linux/amd64, linux/arm64" >> $GITHUB_STEP_SUMMARY
echo "- **Registry:** Docker Hub" >> $GITHUB_STEP_SUMMARY
echo "- **Database:** Pre-seeded workflow.db included" >> $GITHUB_STEP_SUMMARY
echo "- **NPM Version Sync:** ${{ inputs.sync_with_npm }}" >> $GITHUB_STEP_SUMMARY
if [ "${{ steps.version_sync.outputs.version_strategy }}" = "npm-sync" ]; then
echo "- **NPM Sync:** β
Synced with NPM package version" >> $GITHUB_STEP_SUMMARY
fi