251 lines
9.6 KiB
YAML
251 lines
9.6 KiB
YAML
name: Deploy eCourt Note Web to UAT Server
|
||
|
||
on:
|
||
push:
|
||
tags:
|
||
- "deploy*.*.*"
|
||
workflow_dispatch:
|
||
inputs:
|
||
version:
|
||
description: "เวอร์ชันที่จะ deploy เช่น 1.2.3 (ว่าง = latest)"
|
||
required: false
|
||
type: string
|
||
|
||
env:
|
||
# Container Registry
|
||
REGISTRY_URL: ${{ vars.CONTAINER_REGISTRY }}
|
||
REGISTRY_USERNAME: ${{ vars.CONTAINER_REGISTRY_USERNAME }}
|
||
REGISTRY_PASSWORD: ${{ secrets.CONTAINER_REGISTRY_PASSWORD }}
|
||
|
||
# Docker Image — ไม่ build เอง ใช้ image เดียวกับที่ build.yml push ไว้
|
||
# (push tag deploy1.2.3 หรือ Run workflow จาก UI ใส่เวอร์ชัน → map เป็น image v1.2.3 เสมอ)
|
||
WEB_IMAGE_NAME: chamomind/ecourt-note
|
||
|
||
# SSH Deployment — ต่างจาก build.yml: ชี้เครื่อง UAT (ตั้ง vars.SSH_UAT_DEPLOY_HOST เพิ่มใน Forgejo) + ไม่ build image เอง
|
||
DEPLOY_HOST: ${{ vars.SSH_UAT_DEPLOY_HOST }}
|
||
DEPLOY_USER: ${{ vars.SSH_DEPLOY_USER }}
|
||
|
||
# Notifications
|
||
DISCORD_WEBHOOK_URL: ${{ vars.DISCORD_WEBHOOK_URL }}
|
||
NEXT_PUBLIC_APP_URL: ${{ vars.NEXT_PUBLIC_APP_URL }}
|
||
|
||
jobs:
|
||
validate-schema:
|
||
name: Validate Database Schema (Drizzle)
|
||
runs-on: ubuntu-latest
|
||
if: startsWith(github.ref, 'refs/tags/')
|
||
steps:
|
||
- name: Checkout code
|
||
uses: actions/checkout@v4
|
||
with:
|
||
fetch-depth: 0
|
||
|
||
- name: Verify tag is on dev branch
|
||
run: |
|
||
echo "======================================================"
|
||
echo "Verifying tag is pushed to dev branch"
|
||
echo "======================================================"
|
||
echo "Tag: ${{ github.ref_name }}"
|
||
echo "Commit: ${{ github.sha }}"
|
||
|
||
# Fetch dev branch
|
||
git fetch origin dev
|
||
|
||
# Check if the tag's commit is on dev branch
|
||
if git branch -r --contains ${{ github.sha }} | grep -q "origin/dev"; then
|
||
echo "✅ Tag is on dev branch"
|
||
echo "test_branch=true" >> $GITHUB_ENV
|
||
else
|
||
echo "❌ Tag is NOT on dev branch"
|
||
echo "This workflow only triggers for tags pushed to dev branch"
|
||
echo ""
|
||
echo "Current branches containing this commit:"
|
||
git branch -r --contains ${{ github.sha }}
|
||
exit 1
|
||
fi
|
||
|
||
- name: Check for schema changes
|
||
id: schema-check
|
||
run: |
|
||
# โปรเจกต์นี้ใช้ Drizzle (drizzle-kit push) ไม่มีโฟลเดอร์ migrations — ดูการเปลี่ยนแปลงที่ db/schema.ts
|
||
if git diff --name-only origin/dev...HEAD | grep -qE "^db/schema\.ts$"; then
|
||
echo "has_schema_changes=true" >> $GITHUB_OUTPUT
|
||
echo "✅ Schema changes detected"
|
||
else
|
||
echo "has_schema_changes=false" >> $GITHUB_OUTPUT
|
||
echo "ℹ️ No schema changes"
|
||
fi
|
||
|
||
- name: Schema change summary
|
||
if: steps.schema-check.outputs.has_schema_changes == 'true'
|
||
run: |
|
||
echo "=== Schema Change Summary ==="
|
||
echo ""
|
||
echo "Database schema (db/schema.ts) has been modified in this deployment."
|
||
echo "This project uses Drizzle push (no migration files)."
|
||
echo ""
|
||
echo "⚠️ REMINDERS:"
|
||
echo " 1. Run 'npx drizzle-kit push' on the target database (staging first)"
|
||
echo " 2. Monitor logs after deployment"
|
||
echo ""
|
||
echo "📚 Reference: README.md / docs/PLAN.md §3"
|
||
|
||
deploy:
|
||
name: Deploy eCourt Note Web to UAT Server
|
||
runs-on: ubuntu-latest
|
||
needs: validate-schema
|
||
# รันได้ 2 ทาง: push tag deploy*.*.* หรือกด Run workflow จาก UI (ใส่เวอร์ชันใน input)
|
||
# !failure() && !cancelled() = ผ่านได้เมื่อ validate-schema success หรือถูก skip (กรณี dispatch)
|
||
# แต่ยังไม่รันถ้า validate-schema fail (tag ไม่อยู่บน dev)
|
||
if: >-
|
||
always() && !failure() && !cancelled() &&
|
||
(startsWith(github.ref, 'refs/tags/') || github.event_name == 'workflow_dispatch')
|
||
outputs:
|
||
image_tag: ${{ steps.image-tag.outputs.tag }}
|
||
steps:
|
||
- name: Resolve image tag (deploy1.2.3 / v1.2.3 → v1.2.3, ว่าง → latest)
|
||
id: image-tag
|
||
run: |
|
||
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
|
||
RAW="${{ github.event.inputs.version }}"
|
||
else
|
||
RAW="${{ github.ref_name }}"
|
||
fi
|
||
TAG="latest"
|
||
if [ -n "$RAW" ]; then
|
||
TAG="${RAW#deploy}"
|
||
TAG="${TAG#v}"
|
||
TAG="v$TAG"
|
||
fi
|
||
echo "tag=$TAG" >> $GITHUB_OUTPUT
|
||
echo "Reuse image จาก build.yml: ${{ env.REGISTRY_URL }}/${{ env.WEB_IMAGE_NAME }}:$TAG"
|
||
|
||
- name: Log in to Container Registry
|
||
uses: docker/login-action@v3
|
||
with:
|
||
registry: ${{ env.REGISTRY_URL }}
|
||
username: ${{ env.REGISTRY_USERNAME }}
|
||
password: ${{ env.REGISTRY_PASSWORD }}
|
||
|
||
- name: Verify image exists in registry
|
||
run: |
|
||
if ! docker manifest inspect "${{ env.REGISTRY_URL }}/${{ env.WEB_IMAGE_NAME }}:${{ steps.image-tag.outputs.tag }}" > /dev/null; then
|
||
echo "❌ Image ${{ env.REGISTRY_URL }}/${{ env.WEB_IMAGE_NAME }}:${{ steps.image-tag.outputs.tag }} ไม่มีใน registry"
|
||
echo "workflow นี้ไม่ build เอง — push tag ${{ steps.image-tag.outputs.tag }} ก่อน เพื่อให้ build.yml build + push image ให้"
|
||
exit 1
|
||
fi
|
||
echo "✅ Image found — deploy ด้วย image เดียวกับ build.yml"
|
||
|
||
- name: Deploy web on UAT server
|
||
uses: appleboy/ssh-action@v1.2.1
|
||
with:
|
||
host: ${{ env.DEPLOY_HOST }}
|
||
port: ${{ vars.SSH_DEPLOY_PORT }}
|
||
username: ${{ env.DEPLOY_USER }}
|
||
password: ${{ secrets.SSH_DEPLOY_PASSWORD }}
|
||
script: |
|
||
cd ~/repo
|
||
|
||
chmod +x ./replace-env.sh ./deploy.sh
|
||
./replace-env.sh ECOURT_NOTE_TAG "${{ steps.image-tag.outputs.tag }}"
|
||
./deploy.sh
|
||
|
||
notify:
|
||
name: Notify Deployment Status
|
||
runs-on: ubuntu-latest
|
||
needs: [deploy]
|
||
if: always()
|
||
steps:
|
||
- name: Send Discord notification - Success
|
||
if: ${{ needs.deploy.result == 'success' }}
|
||
run: |
|
||
curl -H "Content-Type: application/json" \
|
||
-d '{
|
||
"embeds": [{
|
||
"title": "✅ eCourt Note UAT Deployment Successful",
|
||
"description": "eCourt Note Web deployed to UAT server",
|
||
"color": 3066993,
|
||
"fields": [
|
||
{
|
||
"name": "Environment",
|
||
"value": "UAT",
|
||
"inline": true
|
||
},
|
||
{
|
||
"name": "Tag",
|
||
"value": "${{ github.event_name == 'workflow_dispatch' && github.event.inputs.version || github.ref_name }}",
|
||
"inline": true
|
||
},
|
||
{
|
||
"name": "Commit",
|
||
"value": "`${{ github.sha }}`",
|
||
"inline": false
|
||
},
|
||
{
|
||
"name": "Image Tag",
|
||
"value": "`${{ needs.deploy.outputs.image_tag }}`",
|
||
"inline": true
|
||
},
|
||
{
|
||
"name": "Web URL",
|
||
"value": "${{ env.NEXT_PUBLIC_APP_URL }}",
|
||
"inline": false
|
||
},
|
||
{
|
||
"name": "Deployed By",
|
||
"value": "${{ github.actor }}",
|
||
"inline": true
|
||
}
|
||
],
|
||
"footer": {
|
||
"text": "eCourt Note CD Pipeline"
|
||
},
|
||
"timestamp": "'"$(date -u +%Y-%m-%dT%H:%M:%S.000Z)"'"
|
||
}]
|
||
}' \
|
||
${{ env.DISCORD_WEBHOOK_URL }}
|
||
|
||
- name: Send Discord notification - Failure
|
||
if: ${{ needs.deploy.result == 'failure' }}
|
||
run: |
|
||
curl -H "Content-Type: application/json" \
|
||
-d '{
|
||
"embeds": [{
|
||
"title": "❌ eCourt Note UAT Deployment Failed",
|
||
"description": "Failed to deploy eCourt Note Web to UAT server",
|
||
"color": 15158332,
|
||
"fields": [
|
||
{
|
||
"name": "Environment",
|
||
"value": "UAT",
|
||
"inline": true
|
||
},
|
||
{
|
||
"name": "Tag",
|
||
"value": "${{ github.ref_name }}",
|
||
"inline": true
|
||
},
|
||
{
|
||
"name": "Commit",
|
||
"value": "`${{ github.sha }}`",
|
||
"inline": false
|
||
},
|
||
{
|
||
"name": "Failed Job",
|
||
"value": "Deploy",
|
||
"inline": true
|
||
},
|
||
{
|
||
"name": "Deployed By",
|
||
"value": "${{ github.actor }}",
|
||
"inline": true
|
||
}
|
||
],
|
||
"footer": {
|
||
"text": "eCourt Note CD Pipeline"
|
||
},
|
||
"timestamp": "'"$(date -u +%Y-%m-%dT%H:%M:%S.000Z)"'"
|
||
}]
|
||
}' \
|
||
${{ env.DISCORD_WEBHOOK_URL }}
|
||
exit 1
|