Skip to content

Docker Release (Manual) #11

Docker Release (Manual)

Docker Release (Manual) #11

name: Docker Release (Manual)
on:
workflow_dispatch:
inputs:
version_bump:
description: 'Version bump type'
required: true
default: 'auto'
type: choice
options:
- auto
- major
- minor
- patch
- none
dry_run:
description: 'Dry run (build only, do not push)'
required: false
default: false
type: boolean
env:
DOCKER_IMAGE_NAME: app
DOCKER_HUB_USERNAME: withoutbg
jobs:
docker-release:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Node.js (for semver calculation)
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Calculate next version
id: version
run: |
# Get the latest git tag
LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0")
CURRENT_VERSION=${LATEST_TAG#v}
echo "📌 Current version: $CURRENT_VERSION"
# Parse version components
MAJOR=$(echo $CURRENT_VERSION | cut -d. -f1)
MINOR=$(echo $CURRENT_VERSION | cut -d. -f2)
PATCH=$(echo $CURRENT_VERSION | cut -d. -f3)
# Determine next version based on input
BUMP_TYPE="${{ inputs.version_bump }}"
if [ "$BUMP_TYPE" = "none" ]; then
NEW_VERSION="$CURRENT_VERSION"
echo "ℹ️ Using current version (no bump)"
elif [ "$BUMP_TYPE" = "major" ]; then
MAJOR=$((MAJOR + 1))
MINOR=0
PATCH=0
NEW_VERSION="$MAJOR.$MINOR.$PATCH"
echo "⬆️ MAJOR bump: $CURRENT_VERSION → $NEW_VERSION"
elif [ "$BUMP_TYPE" = "minor" ]; then
MINOR=$((MINOR + 1))
PATCH=0
NEW_VERSION="$MAJOR.$MINOR.$PATCH"
echo "⬆️ MINOR bump: $CURRENT_VERSION → $NEW_VERSION"
elif [ "$BUMP_TYPE" = "patch" ]; then
PATCH=$((PATCH + 1))
NEW_VERSION="$MAJOR.$MINOR.$PATCH"
echo "⬆️ PATCH bump: $CURRENT_VERSION → $NEW_VERSION"
elif [ "$BUMP_TYPE" = "auto" ]; then
# Auto-detect based on commit messages since last tag
COMMITS_SINCE_TAG=$(git log ${LATEST_TAG}..HEAD --oneline --pretty=format:"%s" 2>/dev/null || echo "")
if echo "$COMMITS_SINCE_TAG" | grep -qE "^feat!:|BREAKING CHANGE:"; then
MAJOR=$((MAJOR + 1))
MINOR=0
PATCH=0
NEW_VERSION="$MAJOR.$MINOR.$PATCH"
echo "🔍 Auto-detected MAJOR bump (breaking changes): $CURRENT_VERSION → $NEW_VERSION"
elif echo "$COMMITS_SINCE_TAG" | grep -qE "^feat:"; then
MINOR=$((MINOR + 1))
PATCH=0
NEW_VERSION="$MAJOR.$MINOR.$PATCH"
echo "🔍 Auto-detected MINOR bump (new features): $CURRENT_VERSION → $NEW_VERSION"
elif echo "$COMMITS_SINCE_TAG" | grep -qE "^fix:|^perf:|^refactor:"; then
PATCH=$((PATCH + 1))
NEW_VERSION="$MAJOR.$MINOR.$PATCH"
echo "🔍 Auto-detected PATCH bump (fixes/improvements): $CURRENT_VERSION → $NEW_VERSION"
else
NEW_VERSION="$CURRENT_VERSION"
echo "ℹ️ No version-worthy commits found, using current version: $NEW_VERSION"
fi
fi
# Output version info
VERSION="$NEW_VERSION"
VERSION_MAJOR=$(echo $VERSION | cut -d. -f1)
VERSION_MINOR=$(echo $VERSION | cut -d. -f1-2)
echo "VERSION=$VERSION" >> $GITHUB_OUTPUT
echo "MAJOR=$VERSION_MAJOR" >> $GITHUB_OUTPUT
echo "MINOR=$VERSION_MINOR" >> $GITHUB_OUTPUT
echo ""
echo "📦 Building version: $VERSION"
echo "🏷️ Tags: $VERSION, $VERSION_MINOR, $VERSION_MAJOR, latest"
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
with:
platforms: linux/amd64,linux/arm64
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ vars.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build and test Docker image locally
run: |
echo "🔨 Building Docker image for validation..."
docker buildx build \
--platform linux/amd64 \
-f apps/web/Dockerfile \
-t ${{ env.DOCKER_IMAGE_NAME }}:test \
--load \
.
echo "✅ Local build successful"
echo "🧪 Testing Docker image..."
docker run -d --name test-container -p 8080:80 ${{ env.DOCKER_IMAGE_NAME }}:test
# Wait for container to start
echo "⏳ Waiting for container to start..."
sleep 10
# Test health endpoint
echo "🏥 Testing health endpoint..."
curl -f http://localhost:8080/api/health || (docker logs test-container && exit 1)
echo "✅ Health check passed"
# Cleanup
docker stop test-container
docker rm test-container
echo "✅ Docker image validation complete"
- name: Build and push multi-platform Docker image
if: ${{ !inputs.dry_run }}
uses: docker/build-push-action@v5
with:
context: .
file: apps/web/Dockerfile
platforms: linux/amd64,linux/arm64
push: true
tags: |
${{ env.DOCKER_HUB_USERNAME }}/${{ env.DOCKER_IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}
${{ env.DOCKER_HUB_USERNAME }}/${{ env.DOCKER_IMAGE_NAME }}:${{ steps.version.outputs.MINOR }}
${{ env.DOCKER_HUB_USERNAME }}/${{ env.DOCKER_IMAGE_NAME }}:${{ steps.version.outputs.MAJOR }}
${{ env.DOCKER_HUB_USERNAME }}/${{ env.DOCKER_IMAGE_NAME }}:latest
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Build multi-platform Docker image (dry run)
if: ${{ inputs.dry_run }}
uses: docker/build-push-action@v5
with:
context: .
file: apps/web/Dockerfile
platforms: linux/amd64,linux/arm64
push: false
tags: |
${{ env.DOCKER_HUB_USERNAME }}/${{ env.DOCKER_IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}
${{ env.DOCKER_HUB_USERNAME }}/${{ env.DOCKER_IMAGE_NAME }}:${{ steps.version.outputs.MINOR }}
${{ env.DOCKER_HUB_USERNAME }}/${{ env.DOCKER_IMAGE_NAME }}:${{ steps.version.outputs.MAJOR }}
${{ env.DOCKER_HUB_USERNAME }}/${{ env.DOCKER_IMAGE_NAME }}:latest
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Update version files and create tag
if: ${{ !inputs.dry_run && inputs.version_bump != 'none' }}
run: |
VERSION="${{ steps.version.outputs.VERSION }}"
echo "📝 Updating version files..."
# Update backend pyproject.toml
sed -i.bak "s/version = \".*\"/version = \"$VERSION\"/" apps/web/backend/pyproject.toml
rm -f apps/web/backend/pyproject.toml.bak
# Update frontend package.json
sed -i.bak "s/\"version\": \".*\"/\"version\": \"$VERSION\"/" apps/web/frontend/package.json
rm -f apps/web/frontend/package.json.bak
# Configure git
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
# Commit and tag
git add apps/web/backend/pyproject.toml apps/web/frontend/package.json
git commit -m "chore(release): ${VERSION} [skip ci]" || echo "No changes to commit"
git tag -a "v${VERSION}" -m "Release v${VERSION}"
git push origin main --tags
echo "✅ Version updated to $VERSION and tagged"
- name: Summary
if: ${{ !inputs.dry_run }}
run: |
echo "## 🚀 Docker Release Summary" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "✅ Multi-platform release **${{ steps.version.outputs.VERSION }}** complete!" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### 📦 Built for platforms:" >> $GITHUB_STEP_SUMMARY
echo "- linux/amd64 (Intel/AMD CPUs, most cloud servers)" >> $GITHUB_STEP_SUMMARY
echo "- linux/arm64 (Apple Silicon, AWS Graviton, Raspberry Pi)" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### 🏷️ Available tags:" >> $GITHUB_STEP_SUMMARY
echo "- \`${{ steps.version.outputs.VERSION }}\` (full version)" >> $GITHUB_STEP_SUMMARY
echo "- \`${{ steps.version.outputs.MINOR }}\` (minor version)" >> $GITHUB_STEP_SUMMARY
echo "- \`${{ steps.version.outputs.MAJOR }}\` (major version)" >> $GITHUB_STEP_SUMMARY
echo "- \`latest\`" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### 🐳 Pull and run:" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`bash" >> $GITHUB_STEP_SUMMARY
echo "docker pull ${{ env.DOCKER_HUB_USERNAME }}/${{ env.DOCKER_IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}" >> $GITHUB_STEP_SUMMARY
echo "docker run -p 80:80 ${{ env.DOCKER_HUB_USERNAME }}/${{ env.DOCKER_IMAGE_NAME }}:latest" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### 📚 View on Docker Hub:" >> $GITHUB_STEP_SUMMARY
echo "https://hub.docker.com/r/${{ env.DOCKER_HUB_USERNAME }}/${{ env.DOCKER_IMAGE_NAME }}" >> $GITHUB_STEP_SUMMARY
- name: Summary (dry run)
if: ${{ inputs.dry_run }}
run: |
echo "## 🧪 Docker Build Test Summary (Dry Run)" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "✅ Multi-platform build **${{ steps.version.outputs.VERSION }}** successful!" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "⚠️ **Dry run mode**: Images were built but not pushed to Docker Hub" >> $GITHUB_STEP_SUMMARY
echo "⚠️ **No version bump**: Version files and tags were not updated" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### 📦 Would have released:" >> $GITHUB_STEP_SUMMARY
echo "- Version: **${{ steps.version.outputs.VERSION }}**" >> $GITHUB_STEP_SUMMARY
echo "- Tags: \`${{ steps.version.outputs.VERSION }}\`, \`${{ steps.version.outputs.MINOR }}\`, \`${{ steps.version.outputs.MAJOR }}\`, \`latest\`" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### 📦 Validated for platforms:" >> $GITHUB_STEP_SUMMARY
echo "- linux/amd64 (Intel/AMD CPUs)" >> $GITHUB_STEP_SUMMARY
echo "- linux/arm64 (Apple Silicon, ARM servers)" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "To push to Docker Hub, run the workflow without dry run mode." >> $GITHUB_STEP_SUMMARY