name: Deploy CV Site (andreknie.de) on: push: branches: - master - main workflow_dispatch: jobs: deploy: runs-on: ubuntu-latest steps: - name: Checkout Code uses: actions/checkout@v3 - name: Install & Build Frontend run: | npm ci npm run build node scripts/check-bundle.mjs test -s dist/index.html test -d dist/assets test -n "$(find dist/assets -type f -print -quit)" - name: Copy project files to VM uses: appleboy/scp-action@v0.1.7 with: host: ${{ secrets.DEPLOY_SSH_HOST }} username: ${{ secrets.DEPLOY_SSH_USER }} key: ${{ secrets.DEPLOY_SSH_KEY }} source: "Caddyfile,docker-compose.yml,Dockerfile,server/**,package.json,package-lock.json,dist/**,dist/.*" target: "/opt/orchestrator/privat/CV/andreknie.de" - name: Execute Deployment on VM uses: appleboy/ssh-action@v1.0.3 with: host: ${{ secrets.DEPLOY_SSH_HOST }} username: ${{ secrets.DEPLOY_SSH_USER }} key: ${{ secrets.DEPLOY_SSH_KEY }} script: | set -Eeuo pipefail cd /opt/orchestrator/privat/CV/andreknie.de # 1. Sichere .env aus den Gitea Secrets generieren cat < .env PORT=3003 NODE_ENV=production BASE_URL=https://andreknie.de SMTP_HOST=smtp.ionos.de SMTP_PORT=587 SMTP_USER=${{ secrets.SMTP_USER }} SMTP_PASS=${{ secrets.SMTP_PASS }} STAKEHOLDER_EMAIL=kontakt@d-hive.de DATABASE_URL=postgresql://umami:${{ secrets.UMAMI_DB_PASS }}@umami-db:5432/umami POSTGRES_DB=umami POSTGRES_USER=umami POSTGRES_PASSWORD=${{ secrets.UMAMI_DB_PASS }} HASH_SALT=${{ secrets.UMAMI_HASH_SALT }} EOF # 2. Vollständiges Frontend als begrenztes Release vorbereiten. # Die Release-ID stammt aus dem Commit und bleibt rückverfolgbar. test -s dist/index.html test -d dist/assets release_id="${{ github.sha }}" test -n "$release_id" case "$release_id" in (*[!A-Za-z0-9._-]*) echo "Ungültige Release-ID"; exit 1 ;; esac release_dir="releases/release-${release_id}" previous_dir="releases/previous" mkdir -p releases if [ -e "$release_dir" ]; then rm -rf -- "$release_dir"; fi mkdir -p "$release_dir" cp -a dist/. "$release_dir/" test -s "$release_dir/index.html" test -n "$(find "$release_dir/assets" -type f -print -quit)" rollback() { if [ -d "$previous_dir" ]; then rm -rf -- site mv -- "$previous_dir" site echo "Rollback auf das vorherige Release ausgeführt." fi } trap rollback ERR if [ -e site ]; then rm -rf -- "$previous_dir" mv -- site "$previous_dir" fi mv -- "$release_dir" site # Debugging: Zeige an, ob die Dateien wirklich da sind echo "INHALT VON SITE:" ls -la site/ # 3. Docker Container neustarten docker compose up -d --build echo "CADDYFILE CSP AUF HOST:" grep -n "Content-Security-Policy" Caddyfile echo "CADDYFILE CSP IM CONTAINER:" docker compose exec -T caddy grep -n "Content-Security-Policy" /etc/caddy/Caddyfile docker compose exec -T caddy caddy reload --config /etc/caddy/Caddyfile || true docker compose up -d --force-recreate caddy trap - ERR # Abgebrochene temporäre Releases entfernen. Neben site bleibt # höchstens ein klar benannter Rollback-Stand erhalten. find releases -mindepth 1 -maxdepth 1 -type d -name 'release-*' -exec rm -rf -- {} +