173 lines
8.3 KiB
YAML
173 lines
8.3 KiB
YAML
name: TaxBaik CI/CD
|
|
|
|
on:
|
|
push:
|
|
branches:
|
|
- master
|
|
|
|
jobs:
|
|
build-and-deploy:
|
|
runs-on: ubuntu-latest
|
|
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Setup .NET
|
|
uses: actions/setup-dotnet@v4
|
|
with:
|
|
dotnet-version: '10.0'
|
|
|
|
- name: Restore dependencies
|
|
run: dotnet restore TaxBaik.sln
|
|
|
|
- name: Build solution
|
|
run: |
|
|
dotnet clean TaxBaik.sln -c Release
|
|
dotnet build TaxBaik.sln -c Release --no-restore
|
|
|
|
- name: Test solution
|
|
run: dotnet test TaxBaik.sln -c Release --no-build
|
|
|
|
- name: Publish Web (통합 앱)
|
|
run: dotnet publish TaxBaik.Web/ -c Release -o ./publish --no-restore
|
|
|
|
- name: Write production secrets
|
|
run: |
|
|
set -e
|
|
JWT_SECRET_KEY="${{ secrets.TAXBAIK_JWT_SECRET_KEY }}"
|
|
TELEGRAM_BOT_TOKEN="${{ secrets.TAXBAIK_TELEGRAM_BOT_TOKEN }}"
|
|
TELEGRAM_CHAT_ID="${{ secrets.TAXBAIK_TELEGRAM_CHAT_ID }}"
|
|
if [ -z "$JWT_SECRET_KEY" ]; then
|
|
echo "Missing TAXBAIK_JWT_SECRET_KEY secret" >&2
|
|
exit 1
|
|
fi
|
|
if [ -z "$TELEGRAM_BOT_TOKEN" ]; then
|
|
echo "Missing TAXBAIK_TELEGRAM_BOT_TOKEN secret" >&2
|
|
exit 1
|
|
fi
|
|
if [ -z "$TELEGRAM_CHAT_ID" ]; then
|
|
echo "Missing TAXBAIK_TELEGRAM_CHAT_ID secret" >&2
|
|
exit 1
|
|
fi
|
|
JWT_SECRET_KEY="$JWT_SECRET_KEY" TELEGRAM_BOT_TOKEN="$TELEGRAM_BOT_TOKEN" TELEGRAM_CHAT_ID="$TELEGRAM_CHAT_ID" python3 -c 'import json, os, pathlib; pathlib.Path("./publish/appsettings.Production.json").write_text(json.dumps({"Jwt":{"SecretKey":os.environ["JWT_SECRET_KEY"]},"Telegram":{"BotToken":os.environ["TELEGRAM_BOT_TOKEN"],"ChatId":os.environ["TELEGRAM_CHAT_ID"]}}, ensure_ascii=False, indent=2), encoding="utf-8")'
|
|
test -s ./publish/appsettings.Production.json
|
|
|
|
- name: Copy migrations to publish
|
|
run: |
|
|
cp -r db/migrations ./publish/migrations || true
|
|
|
|
- name: Generate build info
|
|
run: |
|
|
mkdir -p ./publish/wwwroot
|
|
COMMIT_HASH=$(git rev-parse --short HEAD)
|
|
BUILD_TIME=$(date -u +'%Y-%m-%d %H:%M:%S UTC')
|
|
echo "Version: $COMMIT_HASH" > ./publish/wwwroot/version.txt
|
|
echo "Built: $BUILD_TIME" >> ./publish/wwwroot/version.txt
|
|
echo "✓ Version: $COMMIT_HASH"
|
|
|
|
- name: Deploy (CI only, 통합 Web)
|
|
run: |
|
|
set -e
|
|
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
|
|
DEPLOY_HOME="/home/kjh2064"
|
|
DEPLOY_DIR="$DEPLOY_HOME/deployments/taxbaik_${TIMESTAMP}"
|
|
DEPLOY_HOST="${{ secrets.DEPLOY_HOST }}"
|
|
DEPLOY_USER="${{ secrets.DEPLOY_USER }}"
|
|
|
|
echo "=== Deploying TaxBaik v$(git rev-parse --short HEAD) ==="
|
|
mkdir -p ~/.ssh
|
|
SSH_KEY_B64="${{ secrets.DEPLOY_SSH_KEY_B64 }}"
|
|
SSH_KEY_RAW="${{ secrets.DEPLOY_SSH_KEY }}"
|
|
if [ -n "$SSH_KEY_B64" ]; then
|
|
printf '%s' "$SSH_KEY_B64" | base64 -d > ~/.ssh/id_ed25519
|
|
elif [ -n "$SSH_KEY_RAW" ]; then
|
|
if printf '%s' "$SSH_KEY_RAW" | grep -q 'BEGIN .*PRIVATE KEY'; then
|
|
printf '%b\n' "$SSH_KEY_RAW" > ~/.ssh/id_ed25519
|
|
else
|
|
printf '%s' "$SSH_KEY_RAW" | base64 -d > ~/.ssh/id_ed25519
|
|
fi
|
|
else
|
|
echo "Missing DEPLOY_SSH_KEY_B64 or DEPLOY_SSH_KEY secret" >&2
|
|
exit 1
|
|
fi
|
|
sed -i 's/\r$//' ~/.ssh/id_ed25519
|
|
chmod 600 ~/.ssh/id_ed25519
|
|
ssh-keyscan -H "$DEPLOY_HOST" >> ~/.ssh/known_hosts 2>/dev/null || true
|
|
|
|
tar -czf taxbaik_publish.tgz -C ./publish .
|
|
scp -i ~/.ssh/id_ed25519 -o StrictHostKeyChecking=yes taxbaik_publish.tgz "$DEPLOY_USER@$DEPLOY_HOST:/tmp/taxbaik_publish_${TIMESTAMP}.tgz"
|
|
ssh -i ~/.ssh/id_ed25519 -o StrictHostKeyChecking=yes "$DEPLOY_USER@$DEPLOY_HOST" "
|
|
set -e
|
|
mkdir -p '$DEPLOY_DIR'
|
|
tar -xzf '/tmp/taxbaik_publish_${TIMESTAMP}.tgz' -C '$DEPLOY_DIR'
|
|
rm -f '/tmp/taxbaik_publish_${TIMESTAMP}.tgz'
|
|
ln -sfn '$DEPLOY_DIR' '$DEPLOY_HOME/taxbaik_active'
|
|
sudo systemctl restart taxbaik
|
|
"
|
|
sleep 5
|
|
echo "✓ Deployed to $DEPLOY_HOST:$DEPLOY_DIR"
|
|
|
|
- name: Verify deployment
|
|
run: |
|
|
set -e
|
|
DEPLOY_HOST="${{ secrets.DEPLOY_HOST }}"
|
|
DEPLOY_USER="${{ secrets.DEPLOY_USER }}"
|
|
mkdir -p ~/.ssh
|
|
SSH_KEY_B64="${{ secrets.DEPLOY_SSH_KEY_B64 }}"
|
|
SSH_KEY_RAW="${{ secrets.DEPLOY_SSH_KEY }}"
|
|
if [ -n "$SSH_KEY_B64" ]; then
|
|
printf '%s' "$SSH_KEY_B64" | base64 -d > ~/.ssh/id_ed25519
|
|
elif [ -n "$SSH_KEY_RAW" ]; then
|
|
if printf '%s' "$SSH_KEY_RAW" | grep -q 'BEGIN .*PRIVATE KEY'; then
|
|
printf '%b\n' "$SSH_KEY_RAW" > ~/.ssh/id_ed25519
|
|
else
|
|
printf '%s' "$SSH_KEY_RAW" | base64 -d > ~/.ssh/id_ed25519
|
|
fi
|
|
else
|
|
echo "Missing DEPLOY_SSH_KEY_B64 or DEPLOY_SSH_KEY secret" >&2
|
|
exit 1
|
|
fi
|
|
sed -i 's/\r$//' ~/.ssh/id_ed25519
|
|
chmod 600 ~/.ssh/id_ed25519
|
|
ssh-keyscan -H "$DEPLOY_HOST" >> ~/.ssh/known_hosts 2>/dev/null || true
|
|
ADMIN_TEST_PASSWORD="${{ secrets.TAXBAIK_ADMIN_TEST_PASSWORD }}"
|
|
HOME_STATUS="000"
|
|
LOGIN_STATUS="000"
|
|
BLOG_STATUS="000"
|
|
BLOG_HEADERS=""
|
|
BLOG_BODY=""
|
|
BLOG_FINAL_URL=""
|
|
AUTH_BODY=""
|
|
for i in $(seq 1 12); do
|
|
HOME_STATUS=$(ssh -i ~/.ssh/id_ed25519 -o StrictHostKeyChecking=yes "$DEPLOY_USER@$DEPLOY_HOST" "curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:5001/taxbaik/" || echo "000")
|
|
LOGIN_STATUS=$(ssh -i ~/.ssh/id_ed25519 -o StrictHostKeyChecking=yes "$DEPLOY_USER@$DEPLOY_HOST" "curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:5001/taxbaik/admin/login" || echo "000")
|
|
BLOG_STATUS_AND_URL=$(ssh -i ~/.ssh/id_ed25519 -o StrictHostKeyChecking=yes "$DEPLOY_USER@$DEPLOY_HOST" "curl -s -L -D /tmp/taxbaik_blog_check.headers -o /tmp/taxbaik_blog_check.html -w '%{http_code} %{url_effective}' http://127.0.0.1:5001/taxbaik/blog/accountant-mistakes-5" || echo "000")
|
|
BLOG_STATUS=$(printf '%s' "$BLOG_STATUS_AND_URL" | awk '{print $1}')
|
|
BLOG_FINAL_URL=$(printf '%s' "$BLOG_STATUS_AND_URL" | awk '{print $2}')
|
|
BLOG_HEADERS=$(ssh -i ~/.ssh/id_ed25519 -o StrictHostKeyChecking=yes "$DEPLOY_USER@$DEPLOY_HOST" "sed -n '1,12p' /tmp/taxbaik_blog_check.headers | tr '\n' ' '" || echo "")
|
|
BLOG_BODY=$(ssh -i ~/.ssh/id_ed25519 -o StrictHostKeyChecking=yes "$DEPLOY_USER@$DEPLOY_HOST" "sed -n '1,12p' /tmp/taxbaik_blog_check.html | tr '\n' ' '" || echo "")
|
|
if [ "$HOME_STATUS" = "200" ] && [ "$LOGIN_STATUS" = "200" ] && [ "$BLOG_STATUS" = "200" ]; then
|
|
AUTH_BODY=$(ssh -i ~/.ssh/id_ed25519 -o StrictHostKeyChecking=yes "$DEPLOY_USER@$DEPLOY_HOST" "python3 -c \"import json, urllib.request; req = urllib.request.Request('http://127.0.0.1:5001/taxbaik/api/auth/login', data=json.dumps({'username':'admin','password':'${ADMIN_TEST_PASSWORD}'}).encode(), headers={'Content-Type':'application/json'}, method='POST'); print(urllib.request.urlopen(req, timeout=20).read().decode())\"" || echo "")
|
|
if echo "$AUTH_BODY" | grep -q '"token"'; then
|
|
echo "Home Status: $HOME_STATUS"
|
|
echo "Login Status: $LOGIN_STATUS"
|
|
echo "Blog Status: $BLOG_STATUS"
|
|
echo "Auth Body: $AUTH_BODY"
|
|
echo "✓ Service is running"
|
|
exit 0
|
|
fi
|
|
fi
|
|
sleep 5
|
|
done
|
|
echo "Home Status: $HOME_STATUS"
|
|
echo "Login Status: $LOGIN_STATUS"
|
|
echo "Blog Status: $BLOG_STATUS"
|
|
echo "Blog Final URL: $BLOG_FINAL_URL"
|
|
echo "Blog Headers: $BLOG_HEADERS"
|
|
echo "Blog Body: $BLOG_BODY"
|
|
echo "Auth Body: $AUTH_BODY"
|
|
echo "Service verification failed; collecting remote service diagnostics..." >&2
|
|
ssh -i ~/.ssh/id_ed25519 -o StrictHostKeyChecking=yes "$DEPLOY_USER@$DEPLOY_HOST" "systemctl is-active taxbaik; systemctl status taxbaik --no-pager -l | sed -n '1,120p'; journalctl -u taxbaik --no-pager -n 120" || true
|
|
exit 1
|