name: Deploy to Production on: workflow_dispatch: inputs: version: description: 'Leave as "auto" to bump from latest git tag, or enter a specific version (e.g. v0.1.2)' required: false default: 'auto' type: string jobs: deploy: name: Build and deploy runs-on: ubuntu-latest steps: - name: Checkout repository run: | git init git remote add origin https://x-access-token:${FORGEJO_TOKEN}@srvr.nu/git/hermes/jobhunt-platform.git git fetch --depth 1 origin ${GITHUB_SHA} git checkout FETCH_HEAD - name: Resolve version run: | INPUT_VERSION="${{ github.event.inputs.version }}" if [ -z "$INPUT_VERSION" ] || [ "$INPUT_VERSION" = "auto" ]; then git fetch --tags origin LATEST=$(git tag --list 'v*' --sort=-v:refname | head -1) if [ -z "$LATEST" ]; then LATEST="v0.0.0"; fi BASE="${LATEST#v}" MAJOR=$(echo "$BASE" | cut -d. -f1) MINOR=$(echo "$BASE" | cut -d. -f2) PATCH=$(echo "$BASE" | cut -d. -f3) PATCH=$(( ${PATCH:-0} + 1 )) VERSION="v${MAJOR:-0}.${MINOR:-0}.${PATCH}" echo "Latest tag: $LATEST → auto-bumped to $VERSION" else VERSION="$INPUT_VERSION" echo "Using manual version: $VERSION" fi if ! echo "$VERSION" | grep -qE '^v[0-9]+\.[0-9]+\.[0-9]+$'; then echo "ERROR: resolved version '$VERSION' is not valid semver (expected vX.Y.Z)" exit 1 fi echo "VERSION=$VERSION" >> "$GITHUB_ENV" - name: Tag version run: | git tag -d ${{ env.VERSION }} 2>/dev/null || true git push origin --delete ${{ env.VERSION }} 2>/dev/null || true git tag ${{ env.VERSION }} git push origin ${{ env.VERSION }} - name: Write production .env env: LLM_PRIMARY_KEY: ${{ secrets.LLM_PRIMARY_KEY }} run: | { printf 'DATABASE_URL=%s\n' 'postgresql://jobhunt:jobhunt@postgres:5432/jobhunt' printf 'LLM_PRIMARY_BASE_URL=%s\n' 'https://ollama.com/v1' printf 'LLM_PRIMARY_KEY=%s\n' "$LLM_PRIMARY_KEY" printf 'LLM_PRIMARY_MODEL=%s\n' 'glm-5.2' printf 'LLM_CHEAP_MODEL=%s\n' 'glm-5.2' printf 'LLM_STRONG_MODEL=%s\n' 'glm-5.2' printf 'VITE_API_BASE=%s\n' '/api' } > .env - name: Build and start production stack run: | docker compose -p jobhunt -f docker-compose.prod.yml down docker compose -p jobhunt -f docker-compose.prod.yml up --build -d - name: Health checks with rollback run: | echo "Waiting for services to start..." sleep 15 API_OK=false for i in 1 2 3 4 5 6 7 8 9 10; do if docker run --rm --network jobhunt_default curlimages/curl:8.5.0 \ -sf http://jobhunt-api:8000/api/health > /dev/null; then echo "API is healthy" API_OK=true break fi echo "API check attempt $i failed, retrying in 5s..." sleep 5 done WEB_OK=false for i in 1 2 3 4 5; do if docker run --rm --network jobhunt_default curlimages/curl:8.5.0 \ -sf http://jobhunt-web/ > /dev/null; then echo "Frontend is serving" WEB_OK=true break fi echo "Frontend check attempt $i failed, retrying in 5s..." sleep 5 done if [ "$API_OK" != "true" ] || [ "$WEB_OK" != "true" ]; then echo "" echo "═══════════════════════════════════════════════════" echo " HEALTH CHECK FAILED — DIAGNOSTICS" echo "═══════════════════════════════════════════════════" echo "" docker compose -p jobhunt -f docker-compose.prod.yml ps echo "" echo "--- API logs ---" docker logs jobhunt-api 2>&1 | tail -80 || true echo "" echo "--- Postgres logs ---" docker logs jobhunt-postgres 2>&1 | tail -30 || true echo "" echo "═══════════════════════════════════════════════════" echo " ROLLING BACK DEPLOYMENT" echo "═══════════════════════════════════════════════════" echo "" docker compose -p jobhunt -f docker-compose.prod.yml down echo "" echo "Rolled back. Containers stopped. DB volume preserved." echo "Read API logs above to find the root cause before redeploying." exit 1 fi - name: Seed demo data (idempotent) run: | docker run --rm --network jobhunt_default curlimages/curl:8.5.0 \ -sf -X POST http://jobhunt-api:8000/api/concierge/seed-demo || \ echo "WARN: demo seed failed (non-fatal)" - name: Print deploy status run: | echo "" echo "═══════════════════════════════════════════════════" echo " Deployed ${{ env.VERSION }} to production" echo "═══════════════════════════════════════════════════" echo "" docker compose -p jobhunt -f docker-compose.prod.yml ps echo "" echo "Web UI: http://tocke:8085" echo "API: http://tocke:8000/api/health" echo ""