Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 69 additions & 5 deletions .github/workflows/deploy-prod.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ jobs:
sync-dev-to-main:
runs-on: ubuntu-latest
if: ${{ contains(fromJson(vars.PROD_DEPLOYMENT_ALLOWED_USERS), github.actor) }}
permissions:
contents: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
Expand All @@ -33,17 +35,79 @@ jobs:
git merge --ff-only origin/dev || {
echo "❌ Fast-forward merge failed. Manual conflict resolution required."
echo "Please ensure dev branch is ahead of main with no conflicts."
git merge --abort
exit 1
}

- name: Push updated main branch
run: git push origin main

# Bump minor version on main
bump-minor-version:
runs-on: ubuntu-latest
needs: sync-dev-to-main
if: ${{ contains(fromJson(vars.PROD_DEPLOYMENT_ALLOWED_USERS), github.actor) }}
Comment thread
aditeyabaral marked this conversation as resolved.
permissions:
contents: write
steps:
- name: Checkout main
uses: actions/checkout@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
ref: main
fetch-depth: 0

- name: Configure Git
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"

- name: Bump minor version
run: |
pip install uv
python3 scripts/bump_version.py minor
uv lock

- name: Commit and push
run: |
git add pyproject.toml uv.lock
Comment thread
aditeyabaral marked this conversation as resolved.
git diff --cached --quiet && exit 0
git commit -m "chore: bump minor version [skip ci]"
Comment thread
aditeyabaral marked this conversation as resolved.
Comment thread
aditeyabaral marked this conversation as resolved.
git push origin main
Comment thread
aditeyabaral marked this conversation as resolved.

# Sync minor version bump back to dev so dev and main stay on the same commit
sync-minor-to-dev:
runs-on: ubuntu-latest
needs: bump-minor-version
if: ${{ contains(fromJson(vars.PROD_DEPLOYMENT_ALLOWED_USERS), github.actor) }}
permissions:
contents: write
steps:
- name: Checkout dev
uses: actions/checkout@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
ref: dev
fetch-depth: 0

- name: Configure Git
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"

- name: Fast-forward dev to main
run: |
git fetch origin main
git merge --ff-only origin/main || {
echo "❌ Fast-forward merge of main into dev failed. dev has diverged from main."
echo "Please manually fast-forward dev to main before retrying the production deployment."
exit 1
}
git push origin dev

# Build and push Docker images
push-to-dockerhub:
runs-on: ubuntu-latest
needs: sync-dev-to-main
needs: bump-minor-version
if: ${{ contains(fromJson(vars.PROD_DEPLOYMENT_ALLOWED_USERS), github.actor) }}
env:
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
Expand Down Expand Up @@ -84,7 +148,7 @@ jobs:
# Push to GitHub Container Registry
push-to-ghcr:
runs-on: ubuntu-latest
needs: sync-dev-to-main
needs: bump-minor-version
if: ${{ contains(fromJson(vars.PROD_DEPLOYMENT_ALLOWED_USERS), github.actor) }}
permissions:
contents: read
Expand Down Expand Up @@ -119,7 +183,7 @@ jobs:
# Deploy to Staging
deploy-to-staging:
runs-on: ubuntu-latest
needs: [sync-dev-to-main, push-to-dockerhub, push-to-ghcr]
needs: [bump-minor-version, push-to-dockerhub, push-to-ghcr, sync-minor-to-dev]
if: ${{ contains(fromJson(vars.PROD_DEPLOYMENT_ALLOWED_USERS), github.actor) }}
env:
RENDER_DEPLOY_HOOK_URL_DEV: ${{ secrets.RENDER_DEPLOY_HOOK_URL_DEV }}
Expand All @@ -143,7 +207,7 @@ jobs:
# Deploy to Production
deploy-to-prod:
runs-on: ubuntu-latest
needs: [sync-dev-to-main, push-to-dockerhub, push-to-ghcr, deploy-to-staging]
needs: [bump-minor-version, push-to-dockerhub, push-to-ghcr, deploy-to-staging, sync-minor-to-dev]
if: ${{ contains(fromJson(vars.PROD_DEPLOYMENT_ALLOWED_USERS), github.actor) }}
env:
RENDER_DEPLOY_HOOK_URL_PROD: ${{ secrets.RENDER_DEPLOY_HOOK_URL_PROD }}
Expand Down
43 changes: 42 additions & 1 deletion .github/workflows/deploy-staging.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,17 @@ on:
types:
- completed

concurrency:
group: deploy-staging-${{ github.event.workflow_run.head_branch }}
cancel-in-progress: false

jobs:
# Deploy to staging environment
deploy-staging:
runs-on: ubuntu-latest
if: ${{ github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.head_branch == 'dev' }}
if: "${{ github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.head_branch == 'dev' && !startsWith(github.event.workflow_run.head_commit.message, 'chore: bump') }}"
permissions:
contents: write
env:
RENDER_DEPLOY_HOOK_URL_DEV: ${{ secrets.RENDER_DEPLOY_HOOK_URL_DEV }}
steps:
Expand All @@ -21,6 +27,41 @@ jobs:
exit 1
fi

- name: Checkout validated commit
uses: actions/checkout@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
ref: ${{ github.event.workflow_run.head_sha }}
fetch-depth: 0

- name: Configure Git
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"

- name: Verify dev HEAD matches validated SHA
run: |
git fetch origin dev
DEV_HEAD=$(git rev-parse origin/dev)
VALIDATED_SHA="${{ github.event.workflow_run.head_sha }}"
if [ "$DEV_HEAD" != "$VALIDATED_SHA" ]; then
echo "⚠️ dev has advanced to $DEV_HEAD beyond the validated SHA $VALIDATED_SHA. Skipping."
exit 0
fi
Comment thread
aditeyabaral marked this conversation as resolved.
Comment thread
aditeyabaral marked this conversation as resolved.

- name: Bump patch version
run: |
pip install uv
python3 scripts/bump_version.py patch
uv lock

- name: Commit and push
run: |
git add pyproject.toml uv.lock
Comment thread
aditeyabaral marked this conversation as resolved.
git diff --cached --quiet && exit 0
git commit -m "chore: bump patch version [skip ci]"
Comment thread
aditeyabaral marked this conversation as resolved.
git push origin HEAD:dev
Comment thread
aditeyabaral marked this conversation as resolved.
Comment thread
aditeyabaral marked this conversation as resolved.

- name: Deploy to Staging Environment
Comment thread
aditeyabaral marked this conversation as resolved.
run: |
echo "🚀 Deploying to Staging..."
Expand Down
37 changes: 37 additions & 0 deletions scripts/bump_version.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#!/usr/bin/env python3
"""Bump the project version in pyproject.toml. Usage: bump_version.py [patch|minor]."""

import re
import sys

if len(sys.argv) != 2 or sys.argv[1] not in ("patch", "minor"):
raise SystemExit("Usage: bump_version.py [patch|minor]")

bump_type = sys.argv[1]

with open("pyproject.toml") as f:
content = f.read()

match = re.search(r'^version = "(\d+)\.(\d+)\.(\d+)"', content, re.MULTILINE)
if not match:
raise SystemExit('version = "x.y.z" not found in pyproject.toml')

major, minor, patch = int(match.group(1)), int(match.group(2)), int(match.group(3))

if bump_type == "patch":
new_version = f"{major}.{minor}.{patch + 1}"
else:
new_version = f"{major}.{minor + 1}.0"

new_content = re.sub(
r'^version = "\d+\.\d+\.\d+"',
f'version = "{new_version}"',
content,
count=1,
flags=re.MULTILINE,
)

with open("pyproject.toml", "w") as f:
f.write(new_content)
Comment thread
aditeyabaral marked this conversation as resolved.

print(f"Bumped: {major}.{minor}.{patch} -> {new_version}")
Loading