feat: promote development to main #223
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: PR Gates | |
| on: | |
| pull_request: | |
| push: | |
| branches: [development] | |
| concurrency: | |
| group: pr-gates-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| changes: | |
| name: Detect backend-impacting changes | |
| runs-on: ubuntu-latest | |
| outputs: | |
| backend: ${{ steps.filter.outputs.backend }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Filter changed paths | |
| id: filter | |
| uses: dorny/paths-filter@v3 | |
| with: | |
| filters: | | |
| backend: | |
| - "backend/**" | |
| - "Dockerfile" | |
| - "docker-compose.yaml" | |
| - "docker-compose.prod.yaml" | |
| - "docker-compose.prod.split.yaml" | |
| backend-lint-types: | |
| name: Backend Lint + API Types | |
| needs: scope | |
| if: ${{ github.event_name != 'pull_request' || needs.scope.outputs.docs_only != 'true' }} | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: "3.14" | |
| - name: Install uv | |
| run: python -m pip install --upgrade pip uv | |
| - name: Sync backend environment | |
| working-directory: backend | |
| run: uv sync --frozen | |
| - name: Set up Node | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: "22" | |
| cache: npm | |
| cache-dependency-path: frontend/package-lock.json | |
| - name: Install frontend dependencies | |
| run: npm --prefix frontend ci | |
| - name: Run backend lint and API type generation | |
| working-directory: backend | |
| run: | | |
| uv run ade api lint | |
| uv run ade api types | |
| - name: Assert generated API artifacts are committed | |
| run: | | |
| git diff --exit-code -- backend/src/ade_api/openapi.json frontend/src/types/generated/openapi.d.ts | |
| backend-unit: | |
| name: Backend Unit Tests | |
| needs: changes | |
| if: ${{ needs.changes.outputs.backend == 'true' }} | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: "3.14" | |
| - name: Install uv | |
| run: python -m pip install --upgrade pip uv | |
| - name: Sync backend environment | |
| working-directory: backend | |
| run: uv sync --frozen | |
| - name: Run backend unit suites | |
| working-directory: backend | |
| run: | | |
| uv run ade api test | |
| uv run ade worker test | |
| backend-api-integration: | |
| name: Backend API Integration | |
| needs: changes | |
| if: ${{ needs.changes.outputs.backend == 'true' }} | |
| runs-on: ubuntu-latest | |
| services: | |
| postgres: | |
| image: postgres:16 | |
| env: | |
| POSTGRES_USER: postgres | |
| POSTGRES_PASSWORD: postgres | |
| POSTGRES_DB: ade_test | |
| ports: | |
| - 5432:5432 | |
| options: >- | |
| --health-cmd "pg_isready -U postgres" | |
| --health-interval 5s | |
| --health-timeout 5s | |
| --health-retries 20 | |
| env: | |
| CI: "true" | |
| ADE_TEST_DATABASE_URL: postgresql+psycopg://postgres:postgres@127.0.0.1:5432/ade_test?sslmode=disable | |
| ADE_TEST_BLOB_CONNECTION_STRING: DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://127.0.0.1:10000/devstoreaccount1; | |
| ADE_TEST_DATABASE_NAME_PREFIX: ade_api_test | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: "3.14" | |
| - name: Install uv | |
| run: python -m pip install --upgrade pip uv | |
| - name: Sync backend environment | |
| working-directory: backend | |
| run: uv sync --frozen | |
| - name: Start Azurite blob emulator | |
| run: | | |
| docker run --detach \ | |
| --name azurite \ | |
| --publish 10000:10000 \ | |
| mcr.microsoft.com/azure-storage/azurite:3.35.0 \ | |
| azurite-blob --silent --location /data --blobHost 0.0.0.0 --blobPort 10000 --disableTelemetry --skipApiVersionCheck | |
| if ! python - <<'PY' | |
| import socket | |
| import subprocess | |
| import sys | |
| import time | |
| deadline = time.time() + 30 | |
| last_error = "unknown" | |
| while time.time() < deadline: | |
| inspect = subprocess.run( | |
| ["docker", "inspect", "-f", "{{.State.Running}}", "azurite"], | |
| check=False, | |
| capture_output=True, | |
| text=True, | |
| ) | |
| if inspect.returncode != 0: | |
| last_error = inspect.stderr.strip() or "docker inspect failed" | |
| time.sleep(1) | |
| continue | |
| if inspect.stdout.strip() != "true": | |
| last_error = "container stopped" | |
| time.sleep(1) | |
| continue | |
| with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: | |
| sock.settimeout(1) | |
| try: | |
| sock.connect(("127.0.0.1", 10000)) | |
| except OSError as exc: | |
| last_error = str(exc) | |
| time.sleep(1) | |
| continue | |
| sys.exit(0) | |
| print(f"Azurite readiness probe failed: {last_error}", file=sys.stderr) | |
| sys.exit(1) | |
| PY | |
| then | |
| docker logs azurite --tail 200 || true | |
| docker ps -a || true | |
| exit 1 | |
| fi | |
| - name: Run API integration tests | |
| working-directory: backend | |
| run: uv run ade api test integration | |
| backend-worker-integration: | |
| name: Backend Worker Integration | |
| needs: changes | |
| if: ${{ needs.changes.outputs.backend == 'true' }} | |
| runs-on: ubuntu-latest | |
| services: | |
| postgres: | |
| image: postgres:16 | |
| env: | |
| POSTGRES_USER: postgres | |
| POSTGRES_PASSWORD: postgres | |
| POSTGRES_DB: ade_test | |
| ports: | |
| - 5432:5432 | |
| options: >- | |
| --health-cmd "pg_isready -U postgres" | |
| --health-interval 5s | |
| --health-timeout 5s | |
| --health-retries 20 | |
| env: | |
| CI: "true" | |
| ADE_TEST_DATABASE_URL: postgresql+psycopg://postgres:postgres@127.0.0.1:5432/ade_test?sslmode=disable | |
| ADE_TEST_BLOB_CONNECTION_STRING: DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://127.0.0.1:10000/devstoreaccount1; | |
| ADE_TEST_DATABASE_NAME_PREFIX: ade_worker_test | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: "3.14" | |
| - name: Install uv | |
| run: python -m pip install --upgrade pip uv | |
| - name: Sync backend environment | |
| working-directory: backend | |
| run: uv sync --frozen | |
| - name: Start Azurite blob emulator | |
| run: | | |
| docker run --detach \ | |
| --name azurite \ | |
| --publish 10000:10000 \ | |
| mcr.microsoft.com/azure-storage/azurite:3.35.0 \ | |
| azurite-blob --silent --location /data --blobHost 0.0.0.0 --blobPort 10000 --disableTelemetry --skipApiVersionCheck | |
| if ! python - <<'PY' | |
| import socket | |
| import subprocess | |
| import sys | |
| import time | |
| deadline = time.time() + 30 | |
| last_error = "unknown" | |
| while time.time() < deadline: | |
| inspect = subprocess.run( | |
| ["docker", "inspect", "-f", "{{.State.Running}}", "azurite"], | |
| check=False, | |
| capture_output=True, | |
| text=True, | |
| ) | |
| if inspect.returncode != 0: | |
| last_error = inspect.stderr.strip() or "docker inspect failed" | |
| time.sleep(1) | |
| continue | |
| if inspect.stdout.strip() != "true": | |
| last_error = "container stopped" | |
| time.sleep(1) | |
| continue | |
| with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: | |
| sock.settimeout(1) | |
| try: | |
| sock.connect(("127.0.0.1", 10000)) | |
| except OSError as exc: | |
| last_error = str(exc) | |
| time.sleep(1) | |
| continue | |
| sys.exit(0) | |
| print(f"Azurite readiness probe failed: {last_error}", file=sys.stderr) | |
| sys.exit(1) | |
| PY | |
| then | |
| docker logs azurite --tail 200 || true | |
| docker ps -a || true | |
| exit 1 | |
| fi | |
| - name: Run worker integration tests | |
| working-directory: backend | |
| run: uv run ade worker test integration | |
| frontend-checks: | |
| name: Frontend Checks | |
| needs: scope | |
| if: ${{ github.event_name != 'pull_request' || needs.scope.outputs.docs_only != 'true' }} | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: "3.14" | |
| - name: Install uv | |
| run: python -m pip install --upgrade pip uv | |
| - name: Sync backend environment | |
| working-directory: backend | |
| run: uv sync --frozen | |
| - name: Set up Node | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: "22" | |
| cache: npm | |
| cache-dependency-path: frontend/package-lock.json | |
| - name: Install frontend dependencies | |
| run: npm --prefix frontend ci | |
| - name: Run frontend checks | |
| working-directory: backend | |
| run: | | |
| uv run ade web lint | |
| uv run ade web typecheck | |
| uv run ade web test | |
| infra-azure-validation: | |
| name: Infra Azure Validation | |
| needs: scope | |
| if: ${{ (github.event_name != 'pull_request' || needs.scope.outputs.docs_only != 'true') && needs.scope.outputs.infra_azure_changed == 'true' }} | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Ensure Azure CLI and Bicep are available | |
| run: | | |
| az version | |
| az bicep upgrade | |
| - name: Validate Azure infra templates and scripts | |
| run: bash infra/azure/validate.sh | |
| scope: | |
| name: Detect docs and infra changes | |
| runs-on: ubuntu-latest | |
| outputs: | |
| docs_only: ${{ steps.scope.outputs.docs_only }} | |
| infra_azure_changed: ${{ steps.scope.outputs.infra_azure_changed }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Classify change scope | |
| id: scope | |
| env: | |
| EVENT_NAME: ${{ github.event_name }} | |
| PR_BASE_SHA: ${{ github.event.pull_request.base.sha }} | |
| PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }} | |
| PUSH_BEFORE_SHA: ${{ github.event.before }} | |
| PUSH_AFTER_SHA: ${{ github.sha }} | |
| run: | | |
| set -euo pipefail | |
| if [[ "$EVENT_NAME" == "pull_request" ]]; then | |
| from_sha="$PR_BASE_SHA" | |
| to_sha="$PR_HEAD_SHA" | |
| else | |
| from_sha="$PUSH_BEFORE_SHA" | |
| to_sha="$PUSH_AFTER_SHA" | |
| fi | |
| if [[ -z "${from_sha:-}" || "$from_sha" == "0000000000000000000000000000000000000000" ]]; then | |
| echo "docs_only=false" >> "$GITHUB_OUTPUT" | |
| echo "infra_azure_changed=true" >> "$GITHUB_OUTPUT" | |
| exit 0 | |
| fi | |
| changed_files="$(git diff --name-only "$from_sha" "$to_sha")" | |
| if [[ -z "$changed_files" ]]; then | |
| echo "docs_only=false" >> "$GITHUB_OUTPUT" | |
| echo "infra_azure_changed=false" >> "$GITHUB_OUTPUT" | |
| exit 0 | |
| fi | |
| docs_only=true | |
| infra_azure_changed=false | |
| while IFS= read -r file; do | |
| if [[ "$file" =~ ^docs/ ]] || \ | |
| [[ "$file" =~ ^README\.md$ ]] || \ | |
| [[ "$file" =~ ^CONTRIBUTING\.md$ ]] || \ | |
| [[ "$file" =~ ^CHANGELOG\.md$ ]] || \ | |
| [[ "$file" =~ ^\.github/pull_request_template\.md$ ]] || \ | |
| [[ "$file" =~ ^\.github/ISSUE_TEMPLATE/ ]]; then | |
| : | |
| else | |
| docs_only=false | |
| fi | |
| if [[ "$file" =~ ^infra/azure/ ]]; then | |
| infra_azure_changed=true | |
| fi | |
| done <<< "$changed_files" | |
| echo "docs_only=$docs_only" >> "$GITHUB_OUTPUT" | |
| echo "infra_azure_changed=$infra_azure_changed" >> "$GITHUB_OUTPUT" | |
| echo "docs_only=$docs_only" | |
| echo "infra_azure_changed=$infra_azure_changed" | |
| echo "changed files:" | |
| echo "$changed_files" |