eCourt-note/.forgejo/workflows/uat.yml
Your Name 8ba911a119 CD: uat.yml ไม่ build image เอง reuse ของ build.yml + ขึ้น UAT ผ่าน Forgejo UI ได้ — ลบ job build ทั้ง job (เดิม build ซ้ำทุกครั้ง) แทนด้วย steps ใหม่ใน deploy job: Resolve image tag map deploy1.2.3/1.2.3/v1.2.3 → v1.2.3 เสมอ (ตัด prefix deploy ตัด v เติม v กลับ — ใช้ image เดียวกับที่ build.yml push ตอน tag v*) + login registry + docker manifest inspect เช็ค image มีจริงก่อน SSH (fail-fast พร้อมข้อความบอกให้ push tag v* ก่อน ถ้ายังไม่มี) + workflow_dispatch เพิ่ม input version (required) — กด Run workflow ใน UI ใส่เวอร์ชันได้เลยไม่ต้องสร้าง tag deploy* (ทางเดิมยังใช้ได้) — deploy job เปิด if ให้รันกรณ้ dispatch (always() && !failure() && !cancelled() — ผ่านเมื่อ validate-schema success หรือ skip แต่ยัง block ถ้า fail เหมือนเดิม) + notify ถอด needs.build ที่ลบไป + field Tag โชว์เวอร์ชันจาก input ตอน dispatch แทนชื่อ branch + field Image Tag ดึงจาก output ของ deploy job — กติกาคงเดิม: image เกิดจาก build.yml ตอน push tag v* (deploy Test ไปด้วย) เท่านั้น UAT แค่ reuse — verify: js-yaml parse ผ่าน + ทดสอบ normalize ครบ 3 รูปแบบ (deploy1.2.3/v1.2.3/1.2.3 → v1.2.3)
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-17 16:56:38 +07:00

243 lines
9.5 KiB
YAML
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

name: Deploy eCourt Note Web to UAT Server
on:
push:
tags:
- "deploy*.*.*"
workflow_dispatch:
inputs:
version:
description: "เวอร์ชันที่จะ deploy เช่น 1.2.3 / v1.2.3 / deploy1.2.3 — จะ map เป็น image v1.2.3 (ต้อง push tag v1.2.3 ให้ build.yml build ไว้ก่อน)"
required: true
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)
id: image-tag
run: |
RAW="${{ github.event_name == 'workflow_dispatch' && github.event.inputs.version || github.ref_name }}"
TAG="${RAW#deploy}"
TAG="${TAG#v}"
TAG="v$TAG"
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