094b3e35b4
ROOT CAUSE OF CI/CD DEPLOYMENT FAILURE: Line 48 used: find ../src/KArtSell.Host/wwwroot -mindepth 1 -delete This fails because: 1. Directory may not exist 2. find -delete has permission issues in CI environment 3. No mkdir to create directory if missing SOLUTION: Replace with same pattern as deploy-working ci.yml: cd .. rm -rf src/KArtSell.Host/wwwroot mkdir -p src/KArtSell.Host/wwwroot cp -r frontend/dist/* src/KArtSell.Host/wwwroot/ This is portable, reliable, and works in all CI/CD environments. Also updated .gitignore to ignore entire wwwroot directory to prevent git ownership conflicts. This fixes the persistent "Build frontend into Host static assets" failure. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
139 lines
4.8 KiB
YAML
139 lines
4.8 KiB
YAML
name: deploy
|
|
|
|
on:
|
|
push:
|
|
branches:
|
|
- main
|
|
workflow_dispatch:
|
|
|
|
permissions:
|
|
contents: write
|
|
|
|
jobs:
|
|
deploy:
|
|
if: github.event_name == 'workflow_dispatch' || (github.event_name == 'push' && github.ref == 'refs/heads/main')
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 30
|
|
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- uses: actions/setup-dotnet@v4
|
|
with:
|
|
dotnet-version: '10.0.x'
|
|
|
|
- uses: pnpm/action-setup@v4
|
|
with:
|
|
version: 10
|
|
|
|
- uses: actions/setup-node@v4
|
|
with:
|
|
node-version: 22
|
|
cache: pnpm
|
|
cache-dependency-path: frontend/pnpm-lock.yaml
|
|
|
|
- name: Build frontend into Host static assets
|
|
run: |
|
|
cd frontend
|
|
pnpm install --frozen-lockfile
|
|
VERSION_DATE="$(TZ=Asia/Seoul date +%Y.%m.%d)"
|
|
RELEASE_COUNT="$(git ls-remote --tags origin "refs/tags/v${VERSION_DATE}.*" | wc -l | tr -d ' ')"
|
|
VERSION_SEQUENCE="$((RELEASE_COUNT + 1))"
|
|
APP_VERSION="${VERSION_DATE}.${VERSION_SEQUENCE}.${GITHUB_SHA::10}"
|
|
echo "VITE_APP_VERSION=${APP_VERSION}" >> "$GITHUB_ENV"
|
|
echo "release_version=${APP_VERSION}"
|
|
VITE_APP_VERSION="${APP_VERSION}" pnpm build
|
|
grep -R -q 'app-version' dist
|
|
grep -R -q 'UI contract 4.0' dist
|
|
grep -R -q "${APP_VERSION}" dist
|
|
cd ..
|
|
rm -rf src/KArtSell.Host/wwwroot
|
|
mkdir -p src/KArtSell.Host/wwwroot
|
|
cp -r frontend/dist/* src/KArtSell.Host/wwwroot/
|
|
echo "✅ Frontend assets deployed to wwwroot"
|
|
|
|
- run: dotnet restore KArtSell.sln
|
|
|
|
- run: dotnet build KArtSell.sln --no-restore -c Release
|
|
|
|
- name: Publish Release Build
|
|
run: |
|
|
dotnet publish -c Release -o ./publish src/KArtSell.Host
|
|
dotnet publish -c Release -o ./publish src/KArtSell.DbMigrator
|
|
# DbMigrator publish flattens Content SQL beside the executable.
|
|
# Keep the migration files in the release package; Host publish alone is insufficient.
|
|
test -f ./publish/0032_shadow_run_queued_status_contract.sql
|
|
|
|
- name: Create deployment package
|
|
run: |
|
|
cd ./publish
|
|
zip -r ../kartsell-release.zip .
|
|
cd ..
|
|
ls -lh kartsell-release.zip
|
|
|
|
- name: Deploy via SCP to server
|
|
env:
|
|
DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }}
|
|
run: |
|
|
# SSH 키 설정 (SSH_KEY에서 변환)
|
|
echo "$DEPLOY_KEY" > /tmp/deploy_key.pem
|
|
chmod 600 /tmp/deploy_key.pem
|
|
|
|
# 서버에 파일 전송
|
|
echo "📦 Deploying kartsell-release.zip to server..."
|
|
scp -i /tmp/deploy_key.pem -o StrictHostKeyChecking=no \
|
|
./kartsell-release.zip kjh2064@178.104.200.7:/tmp/
|
|
|
|
echo "✅ File transferred"
|
|
echo ""
|
|
ssh -i /tmp/deploy_key.pem -o StrictHostKeyChecking=no kjh2064@178.104.200.7 \
|
|
"set -euo pipefail; \
|
|
sudo -n -l | grep -Fq '/usr/bin/systemctl restart kartsell' || { \
|
|
echo 'Deployment blocked: one-time sudoers delegation is missing for kartsell.' >&2; \
|
|
echo 'Expected: kjh2064 ALL=(root) NOPASSWD: /usr/bin/systemctl restart kartsell' >&2; \
|
|
exit 77; \
|
|
}; \
|
|
export KARTSELL_POSTGRES='${{ secrets.KARTSELL_POSTGRES }}'; \
|
|
mkdir -p /app/kartsell/current; \
|
|
unzip -oq /tmp/kartsell-release.zip -d /app/kartsell/current; \
|
|
cd /app/kartsell/current; \
|
|
test -f KArtSell.DbMigrator.dll; \
|
|
test -f 0032_shadow_run_queued_status_contract.sql; \
|
|
dotnet KArtSell.DbMigrator.dll; \
|
|
sudo -n systemctl restart kartsell; \
|
|
sleep 3; \
|
|
systemctl is-active --quiet kartsell; \
|
|
echo 'deployment_verified=true'"
|
|
|
|
echo "✅ Artifact deployed, DbMigrator executed, and kartsell restarted"
|
|
|
|
# Cleanup
|
|
rm /tmp/deploy_key.pem
|
|
|
|
- name: Tag release version
|
|
run: |
|
|
git tag "v${VITE_APP_VERSION}"
|
|
git push origin "v${VITE_APP_VERSION}"
|
|
|
|
notify:
|
|
if: always()
|
|
needs: deploy
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: Notify deployment status
|
|
env:
|
|
TELEGRAM_TOKEN: ${{ secrets.TELEGRAM_TOKEN }}
|
|
TELEGRAM_CHAT_ID: ${{ secrets.TELEGRAM_CHAT_ID }}
|
|
run: |
|
|
STATUS="${{ needs.deploy.result }}"
|
|
if [ "$STATUS" = "success" ]; then
|
|
MESSAGE="✅ K-ArtSell Aegis deployed successfully to production"
|
|
else
|
|
MESSAGE="❌ K-ArtSell Aegis deployment failed"
|
|
fi
|
|
|
|
curl -X POST "https://api.telegram.org/bot$TELEGRAM_TOKEN/sendMessage" \
|
|
-d "chat_id=$TELEGRAM_CHAT_ID" \
|
|
-d "text=$MESSAGE" \
|
|
-d "parse_mode=HTML" || echo "Telegram notification failed"
|