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