name: Verify and deploy API on: push: branches: [main] pull_request: workflow_dispatch: concurrency: group: pk-lab-server-production cancel-in-progress: true jobs: verify-deploy: runs-on: ubuntu-latest container: image: docker:27-cli timeout-minutes: 30 env: SOURCE_SERVER: ${{ gitea.server_url }} SOURCE_REPOSITORY: ${{ gitea.repository }} SOURCE_REVISION: ${{ gitea.sha }} PUBLIC_BASE_URL: ${{ vars.PUBLIC_BASE_URL || '' }} CORS_ORIGINS: ${{ vars.CORS_ORIGINS || '' }} TEST_AUTH_ENABLED: ${{ vars.TEST_AUTH_ENABLED || 'true' }} POSTGRES_PASSWORD: ${{ secrets.POSTGRES_PASSWORD }} XHS_HUB_APP_ID: ${{ secrets.XHS_HUB_APP_ID }} XHS_HUB_APP_SECRET: ${{ secrets.XHS_HUB_APP_SECRET }} XHS_RICE_APP_ID: ${{ secrets.XHS_RICE_APP_ID }} XHS_RICE_APP_SECRET: ${{ secrets.XHS_RICE_APP_SECRET }} steps: - name: Prepare runner and fetch exact revision env: SOURCE_TOKEN: ${{ secrets.GITEA_TOKEN || gitea.token }} run: | set -eu apk add --no-cache python3 curl docker info >/dev/null python3 - <<'PY' import io, os, shutil, tarfile, tempfile, urllib.request from pathlib import Path url = f"{os.environ['SOURCE_SERVER'].rstrip('/')}/api/v1/repos/{os.environ['SOURCE_REPOSITORY']}/archive/{os.environ['SOURCE_REVISION']}.tar.gz" request = urllib.request.Request(url, headers={'Authorization': 'token ' + os.environ['SOURCE_TOKEN']}) with urllib.request.urlopen(request, timeout=60) as response: data = response.read() with tempfile.TemporaryDirectory() as directory: with tarfile.open(fileobj=io.BytesIO(data), mode='r:gz') as archive: archive.extractall(directory, filter='data') roots = list(Path(directory).iterdir()) if len(roots) != 1: raise RuntimeError('Unexpected archive structure') shutil.copytree(roots[0], Path.cwd(), dirs_exist_ok=True) PY - name: Run checks in image build run: docker build --target test --tag "pk-lab-server:$SOURCE_REVISION-test" . - name: Build runtime image if: gitea.ref == 'refs/heads/main' && gitea.event_name != 'pull_request' run: docker build --target runtime --tag "pk-lab-server:$SOURCE_REVISION" . - name: Update permanent stack without deleting data if: gitea.ref == 'refs/heads/main' && gitea.event_name != 'pull_request' run: | set -eu test -n "$POSTGRES_PASSWORD" export DEPLOY_IMAGE="pk-lab-server:$SOURCE_REVISION" sh scripts/deploy.sh docker compose -p pk-lab-production exec -T api python -c "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8000/health', timeout=3)" for container in pk-lab-xhs-preview rice-pk-xhs-preview; do if docker inspect "$container" >/dev/null 2>&1; then ready=false for i in 1 2 3 4 5 6 7 8 9 10; do if docker exec "$container" wget -q -O- http://127.0.0.1:8080/api/v1/tests >/dev/null; then ready=true break fi sleep 2 done [ "$ready" = true ] fi done - name: Probe public endpoint if: gitea.ref == 'refs/heads/main' && gitea.event_name != 'pull_request' && env.PUBLIC_BASE_URL != '' run: curl --fail --silent --show-error --connect-timeout 10 --max-time 20 "${PUBLIC_BASE_URL%/}/health"