Skip to content

Fix/notifications (#155) #95

Fix/notifications (#155)

Fix/notifications (#155) #95

Workflow file for this run

name: Build, Tag & Deploy to Dev
on:
push:
branches:
- dev
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Get latest tag from Docker Hub
id: get_tag
run: |
# Fetch tags from Docker Hub
REPO="${{ secrets.DOCKER_USERNAME }}/api-yapper-backend"
echo "πŸ” Fetching tags from Docker Hub for $REPO..."
# Get Docker Hub token for authenticated API access
TOKEN=$(curl -s -H "Content-Type: application/json" -X POST \
-d '{"username": "${{ secrets.DOCKER_USERNAME }}", "password": "${{ secrets.DOCKER_PASSWORD }}"}' \
https://hub.docker.com/v2/users/login/ | jq -r .token)
if [ "$TOKEN" = "null" ] || [ -z "$TOKEN" ]; then
echo "❌ Failed to authenticate with Docker Hub"
exit 1
fi
# Get all tags from Docker Hub API
TAGS=$(curl -s -H "Authorization: JWT ${TOKEN}" \
"https://hub.docker.com/v2/repositories/$REPO/tags/?page_size=100" | \
jq -r '.results[].name' | \
grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | \
sort -V | \
tail -1)
# If no tags found, start with v0.0.0
if [ -z "$TAGS" ]; then
LATEST_TAG="v0.0.0"
echo "⚠️ No version tags found on Docker Hub, starting from v0.0.0"
else
LATEST_TAG="$TAGS"
echo "πŸ“¦ Latest tag found on Docker Hub: $LATEST_TAG"
fi
echo "latest_tag=$LATEST_TAG" >> $GITHUB_OUTPUT
# Parse version components
VERSION=${LATEST_TAG#v}
IFS='.' read -r MAJOR MINOR PATCH <<< "$VERSION"
# Increment patch version
PATCH=$((PATCH + 1))
NEW_TAG="v${MAJOR}.${MINOR}.${PATCH}"
echo "new_tag=$NEW_TAG" >> $GITHUB_OUTPUT
echo "πŸš€ New version: $NEW_TAG"
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build and push Docker image
uses: docker/build-push-action@v6
with:
context: .
file: ./docker/Dockerfile
push: true
tags: |
${{ secrets.DOCKER_USERNAME }}/api-yapper-backend:${{ steps.get_tag.outputs.new_tag }}
${{ secrets.DOCKER_USERNAME }}/api-yapper-backend:dev
- name: Confirm image push
run: |
echo "βœ… Image pushed: ${{ secrets.DOCKER_USERNAME }}/api-yapper-backend:${{ steps.get_tag.outputs.new_tag }}"
echo "βœ… Image tagged: ${{ secrets.DOCKER_USERNAME }}/api-yapper-backend:dev"
- name: SSH into Dev VM and deploy
uses: appleboy/ssh-action@v1.0.0
env:
IMG_TAG: ${{ steps.get_tag.outputs.new_tag }}
with:
host: ${{ secrets.DEV_SERVER_HOST }}
username: ${{ secrets.DEV_SERVER_USER }}
key: ${{ secrets.DEV_SERVER_SSH_KEY }}
envs: IMG_TAG
script: |
set -e
cd ~/yapper # path to your app on VM
echo "🧭 Getting current running image tag..."
CURRENT_TAG=$(IMG_TAG="" docker compose ps -q api | xargs docker inspect -f '{{ .Config.Image }}' | cut -d':' -f2 || echo "unknown")
echo "CURRENT_TAG: $CURRENT_TAG"
echo "🐳 Setting new image tag for deployment..."
echo "Deploying version: $IMG_TAG"
echo "πŸ”„ Pulling new image and restarting app container..."
IMG_TAG=$IMG_TAG docker compose pull api api-local api-test
IMG_TAG=$IMG_TAG docker compose up -d api api-local api-test
echo "⏳ Waiting for health check..."
sleep 10
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" ${{ secrets.DEV_HEALTHCHECK_URL }})
if [ "$HTTP_CODE" = "200" ]; then
echo "βœ… Dev deployment successful for version $IMG_TAG"
echo "πŸ”„ Running migrations for all services..."
MIGRATION_FAILED=0
echo "πŸ“¦ Running migration for api..."
docker compose exec -T api npm run migration:run:prod 2>&1 | tee /tmp/api-migration.log
if grep -q "Error during migration" /tmp/api-migration.log || grep -q "Cannot find module" /tmp/api-migration.log; then
echo "❌ Migration for api failed!"
cat /tmp/api-migration.log
MIGRATION_FAILED=1
elif grep -q "No migrations are pending" /tmp/api-migration.log || grep -q "No pending migrations" /tmp/api-migration.log; then
echo "ℹ️ No pending migrations for api"
else
echo "βœ… Migration for api completed successfully"
fi
echo "πŸ“¦ Running migration for api-local..."
docker compose exec -T api-local npm run migration:run:prod 2>&1 | tee /tmp/api-local-migration.log
if grep -q "Error during migration" /tmp/api-local-migration.log || grep -q "Cannot find module" /tmp/api-local-migration.log; then
echo "❌ Migration for api-local failed!"
cat /tmp/api-local-migration.log
MIGRATION_FAILED=1
elif grep -q "No migrations are pending" /tmp/api-local-migration.log || grep -q "No pending migrations" /tmp/api-local-migration.log; then
echo "ℹ️ No pending migrations for api-local"
else
echo "βœ… Migration for api-local completed successfully"
fi
echo "πŸ“¦ Running migration for api-test..."
docker compose exec -T api-test npm run migration:run:prod 2>&1 | tee /tmp/api-test-migration.log
if grep -q "Error during migration" /tmp/api-test-migration.log || grep -q "Cannot find module" /tmp/api-test-migration.log; then
echo "❌ Migration for api-test failed!"
cat /tmp/api-test-migration.log
MIGRATION_FAILED=1
elif grep -q "No migrations are pending" /tmp/api-test-migration.log || grep -q "No pending migrations" /tmp/api-test-migration.log; then
echo "ℹ️ No pending migrations for api-test"
else
echo "βœ… Migration for api-test completed successfully"
fi
if [ "$MIGRATION_FAILED" = "1" ]; then
echo "❌ One or more migrations failed! Rolling back..."
if [ "$CURRENT_TAG" != "unknown" ]; then
IMG_TAG=$CURRENT_TAG docker compose up -d api api-local api-test
echo "πŸ”™ Rolled back to $CURRENT_TAG"
fi
exit 1
fi
echo "βœ… All migrations completed successfully"
else
echo "❌ Health check failed (HTTP $HTTP_CODE)! Rolling back app container..."
if [ "$CURRENT_TAG" != "unknown" ]; then
IMG_TAG=$CURRENT_TAG docker compose up -d api api-local api-test
echo "πŸ”™ Rolled back to $CURRENT_TAG"
fi
exit 1
fi
- name: Deployment summary
if: success()
run: |
echo "πŸŽ‰ Deployment Complete!"
echo "Version: ${{ steps.get_tag.outputs.new_tag }}"
echo "Branch: dev"
echo "Commit: ${{ github.sha }}"