fix: preserve verdict state and skip cancelled preview gates #4166
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 Preview | |
| on: | |
| pull_request: | |
| types: | |
| - opened | |
| - reopened | |
| - synchronize | |
| - closed | |
| concurrency: | |
| group: pr-preview-${{ github.event.pull_request.number }} | |
| cancel-in-progress: true | |
| jobs: | |
| detect-changes: | |
| name: Detect preview changes | |
| # Promotion pull requests (staging -> main) provision nothing: the staging | |
| # environment already serves the exact commit under review, so a per-PR | |
| # copy duplicates it. The required gate below still reports for them. | |
| if: >- | |
| github.event.action != 'closed' && | |
| github.event.pull_request.head.repo.full_name == github.repository && | |
| github.event.pull_request.head.ref != 'staging' | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| actions: read | |
| outputs: | |
| deploy_backend: ${{ steps.compute.outputs.deploy_backend }} | |
| run_migrations: ${{ steps.compute.outputs.run_migrations }} | |
| deploy_frontend: ${{ steps.compute.outputs.deploy_frontend }} | |
| any_change: ${{ steps.compute.outputs.any_change }} | |
| preview_backend_live: ${{ steps.compute.outputs.preview_backend_live }} | |
| preview_api_url: ${{ format('https://abundant-ai-preview--oddish-pr-{0}-api.modal.run', github.event.pull_request.number) }} | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v5 | |
| # find_last_deploys.py emits all the change signals (see its docstring): | |
| # - pr_{backend,migrations,frontend}: does the whole PR touch each | |
| # component (diffed vs the PR base branch) -- used on opened/reopened | |
| # and as the no-base fallback. | |
| # - On synchronize: backend_base/migrations_base (last successful deploy | |
| # SHAs) + {backend,migrations,workflow}_changed (only this push's | |
| # files, diffed vs that base / the previous push). | |
| # We compute these via the GitHub compare API instead of dorny/paths-filter | |
| # because that action ignores its `base` input on pull_request events (so | |
| # it diffs the whole PR) and, under its default `some` quantifier, its | |
| # negated excludes match almost anything -- both forced the DB seed. | |
| - name: Detect preview component changes | |
| id: last_deployed | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| OWNER_REPO: ${{ github.repository }} | |
| EVENT_ACTION: ${{ github.event.action }} | |
| HEAD_REF: ${{ github.event.pull_request.head.ref }} | |
| HEAD_SHA: ${{ github.event.pull_request.head.sha }} | |
| PR_BASE_SHA: ${{ github.event.pull_request.base.sha }} | |
| BEFORE_SHA: ${{ github.event.before }} | |
| run: python "$GITHUB_WORKSPACE/.github/scripts/preview/find_last_deploys.py" | |
| - name: Compute deployment plan | |
| id: compute | |
| env: | |
| EVENT_ACTION: ${{ github.event.action }} | |
| BACKEND_BASE: ${{ steps.last_deployed.outputs.backend_base }} | |
| MIGRATIONS_BASE: ${{ steps.last_deployed.outputs.migrations_base }} | |
| BACKEND_CHANGED: ${{ steps.last_deployed.outputs.backend_changed }} | |
| MIGRATIONS_CHANGED: ${{ steps.last_deployed.outputs.migrations_changed }} | |
| PR_BACKEND_CHANGED: ${{ steps.last_deployed.outputs.pr_backend }} | |
| PR_MIGRATIONS_CHANGED: ${{ steps.last_deployed.outputs.pr_migrations }} | |
| PR_FRONTEND_CHANGED: ${{ steps.last_deployed.outputs.pr_frontend }} | |
| WORKFLOW_CHANGED: ${{ steps.last_deployed.outputs.workflow_changed }} | |
| run: bash "$GITHUB_WORKSPACE/.github/scripts/preview/compute_deployment_plan.sh" | |
| prepare-preview-database: | |
| name: Prepare preview database | |
| needs: | |
| - detect-changes | |
| # Backend-scoped PRs keep their Supabase preview branch smoke-tested on | |
| # later frontend-only pushes, so the required preview stays end-to-end. | |
| if: | | |
| always() && | |
| needs.detect-changes.result == 'success' && | |
| ( | |
| needs.detect-changes.outputs.preview_backend_live == 'true' || | |
| needs.detect-changes.outputs.deploy_backend == 'true' || | |
| needs.detect-changes.outputs.run_migrations == 'true' | |
| ) | |
| runs-on: ubuntu-latest | |
| # Covers the auto-heal worst case: incremental upgrade + retry, then a full | |
| # snapshot rebuild (restore + seed + upgrade) back-to-back. | |
| timeout-minutes: 20 | |
| permissions: | |
| contents: read | |
| packages: read | |
| outputs: | |
| branch_ref: ${{ steps.prepare.outputs.branch_ref }} | |
| branch_id: ${{ steps.prepare.outputs.branch_id }} | |
| branch_was_created: ${{ steps.prepare.outputs.branch_was_created }} | |
| container: | |
| image: ghcr.io/abundant-ai/oddish-ci-base:latest | |
| credentials: | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| env: | |
| MODAL_TOKEN_ID: ${{ secrets.MODAL_TOKEN_ID }} | |
| MODAL_TOKEN_SECRET: ${{ secrets.MODAL_TOKEN_SECRET }} | |
| MODAL_ENVIRONMENT: preview | |
| MODAL_APP_NAME: oddish-pr-${{ github.event.pull_request.number }} | |
| SUPABASE_ACCESS_TOKEN: ${{ secrets.SUPABASE_ACCESS_TOKEN }} | |
| SUPABASE_PROJECT_REF: ${{ vars.SUPABASE_PROJECT_REF }} | |
| UV_PROJECT_ENVIRONMENT: /opt/venvs/backend | |
| # Production DB URL, used strictly read-only as the source of the schema | |
| # snapshot + Alembic pointers (bootstrap_preview_db.py) and the sampled | |
| # seed data -- the preview's only data source. Deliberately NOT named | |
| # ODDISH_DATABASE_URL: that var is rebound to the branch DB by | |
| # wait_for_supabase_branch.sh in this job. | |
| PREVIEW_SAMPLE_SOURCE_DB_URL: ${{ secrets.ODDISH_DATABASE_URL }} | |
| defaults: | |
| run: | |
| working-directory: backend | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v5 | |
| - name: Sync backend dependencies | |
| run: uv sync --frozen | |
| - name: Prepare preview database | |
| id: prepare | |
| env: | |
| PR_NUMBER: ${{ github.event.pull_request.number }} | |
| DEPLOY_BACKEND: ${{ needs.detect-changes.outputs.deploy_backend }} | |
| RUN_MIGRATIONS: ${{ needs.detect-changes.outputs.run_migrations }} | |
| run: "$GITHUB_WORKSPACE/.github/scripts/preview/prepare_preview_database.sh" | |
| deploy-preview-backend: | |
| name: Deploy preview backend | |
| needs: | |
| - detect-changes | |
| - prepare-preview-database | |
| if: | | |
| always() && | |
| needs.prepare-preview-database.result == 'success' && | |
| ( | |
| needs.detect-changes.outputs.deploy_backend == 'true' || | |
| needs.prepare-preview-database.outputs.branch_was_created == 'true' | |
| ) | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| packages: read | |
| outputs: | |
| modal_api_url: ${{ steps.deploy.outputs.modal_api_url }} | |
| container: | |
| image: ghcr.io/abundant-ai/oddish-ci-base:latest | |
| credentials: | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| env: | |
| MODAL_TOKEN_ID: ${{ secrets.MODAL_TOKEN_ID }} | |
| MODAL_TOKEN_SECRET: ${{ secrets.MODAL_TOKEN_SECRET }} | |
| MODAL_ENVIRONMENT: preview | |
| MODAL_APP_NAME: oddish-pr-${{ github.event.pull_request.number }} | |
| MODAL_SECRET_ENVIRONMENT: main | |
| EXPECTED_MODAL_API_URL: ${{ needs.detect-changes.outputs.preview_api_url }} | |
| UV_PROJECT_ENVIRONMENT: /opt/venvs/backend | |
| ODDISH_MODAL_API_MIN_CONTAINERS: "0" | |
| ODDISH_MODAL_API_BUFFER_CONTAINERS: "0" | |
| ODDISH_MODAL_API_MAX_CONTAINERS: "2" | |
| ODDISH_MODAL_WORKER_MIN_CONTAINERS: "0" | |
| ODDISH_MODAL_WORKER_BUFFER_CONTAINERS: "0" | |
| ODDISH_MODAL_WORKER_MAX_CONTAINERS: "2" | |
| ODDISH_GATE_LLM_ON_BASELINES: "1" | |
| defaults: | |
| run: | |
| working-directory: backend | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v5 | |
| - name: Sync backend dependencies | |
| run: uv sync --frozen | |
| - name: Deploy preview backend | |
| id: deploy | |
| run: "$GITHUB_WORKSPACE/.github/scripts/preview/deploy_preview_backend.sh" | |
| update-vercel-preview: | |
| name: Update Vercel preview | |
| needs: | |
| - detect-changes | |
| - prepare-preview-database | |
| - deploy-preview-backend | |
| # Run for every open same-repository PR, not only frontend changes: the | |
| # branch ruleset requires a working Preview deployment before merge. | |
| if: | | |
| always() && | |
| needs.detect-changes.result == 'success' && | |
| ( | |
| needs.prepare-preview-database.result == 'success' || | |
| needs.prepare-preview-database.result == 'skipped' | |
| ) && | |
| ( | |
| needs.deploy-preview-backend.result == 'success' || | |
| needs.deploy-preview-backend.result == 'skipped' | |
| ) | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| packages: read | |
| container: | |
| image: ghcr.io/abundant-ai/oddish-ci-base:latest | |
| credentials: | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| env: | |
| VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }} | |
| VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} | |
| VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }} | |
| VERCEL_GIT_BRANCH: ${{ github.event.pull_request.head.ref }} | |
| VERCEL_GIT_COMMIT_SHA: ${{ github.event.pull_request.head.sha }} | |
| PR_URL: ${{ github.event.pull_request.html_url }} | |
| PR_TITLE: ${{ github.event.pull_request.title }} | |
| # Point the preview frontend at the preview backend whenever one is live | |
| # (deployed this run or a prior run), NOT only when it redeployed this push | |
| # -- otherwise a frontend-only follow-up push blanks this, and | |
| # update_vercel_preview.sh falls back to prod, so the preview frontend | |
| # starts querying production. Blank (-> prod fallback) only when no preview | |
| # backend was ever provisioned (frontend-only PRs). | |
| MODAL_API_URL: ${{ needs.detect-changes.outputs.preview_backend_live == 'true' && needs.detect-changes.outputs.preview_api_url || '' }} | |
| MODAL_APP_NAME: oddish-pr-${{ github.event.pull_request.number }} | |
| STAGING_API_URL: ${{ vars.ODDISH_STAGING_API_URL }} | |
| PROD_API_URL: ${{ vars.ODDISH_PROD_API_URL }} | |
| SUPABASE_BRANCH_REF: ${{ needs.prepare-preview-database.outputs.branch_ref }} | |
| PREVIEW_ALIAS_HOSTNAME: pr-${{ github.event.pull_request.number }}.oddish.app | |
| outputs: | |
| preview_url: ${{ steps.vercel.outputs.preview_url }} | |
| preview_alias_url: ${{ steps.vercel.outputs.preview_alias_url }} | |
| backend_api_url: ${{ steps.vercel.outputs.backend_api_url }} | |
| backend_label: ${{ steps.vercel.outputs.backend_label }} | |
| database_label: ${{ steps.vercel.outputs.database_label }} | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v5 | |
| - name: Update Vercel preview | |
| id: vercel | |
| run: "$GITHUB_WORKSPACE/.github/scripts/preview/update_vercel_preview.sh" | |
| require-working-preview: | |
| name: Require working preview | |
| needs: | |
| - detect-changes | |
| - prepare-preview-database | |
| - deploy-preview-backend | |
| - update-vercel-preview | |
| # `!cancelled()` rather than `always()`: the gate must still run when | |
| # upstream jobs are SKIPPED (fork and promotion paths), but a run that | |
| # cancel-in-progress superseded must not publish a failing check and a | |
| # failing deployment status for a commit whose replacement run is still | |
| # building. | |
| if: "!cancelled() && github.event.action != 'closed'" | |
| runs-on: ubuntu-latest | |
| # No job-level `environment:` key here: GitHub attributes that deployment | |
| # record to the person who triggered the run, so pull requests showed a | |
| # human as the deployer. The steps below create the same Preview record | |
| # through the API with the workflow token, so the deployer is | |
| # github-actions. The record still satisfies the staging ruleset's | |
| # required-deployments rule (same environment, same commit). | |
| permissions: | |
| deployments: write | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| # Same-repository condition included: a fork branch named `staging` | |
| # must not short-circuit the gate to success. | |
| PROMOTION_PR: ${{ github.event.pull_request.head.ref == 'staging' && github.event.pull_request.head.repo.full_name == github.repository }} | |
| DEPLOY_URL: ${{ (github.event.pull_request.head.ref == 'staging' && github.event.pull_request.head.repo.full_name == github.repository) && 'https://staging.oddish.app' || needs.update-vercel-preview.outputs.preview_alias_url || needs.update-vercel-preview.outputs.preview_url }} | |
| steps: | |
| - name: Create the Preview deployment record | |
| id: deployment | |
| # Fork PRs get a read-only token; skip so the verify step below can | |
| # fail with its clearer same-repository message. | |
| if: github.event.pull_request.head.repo.full_name == github.repository | |
| env: | |
| # The head commit, not GITHUB_SHA: on pull_request events GITHUB_SHA | |
| # is the temporary merge commit, and the required-deployments rule | |
| # and the pull request page key on the head commit. | |
| HEAD_SHA: ${{ github.event.pull_request.head.sha }} | |
| run: | | |
| set -euo pipefail | |
| deployment_id=$(jq -n --arg ref "$HEAD_SHA" \ | |
| '{ref: $ref, environment: "Preview", auto_merge: false, | |
| required_contexts: [], transient_environment: true, | |
| description: "PR preview gate"}' \ | |
| | gh api "repos/$GITHUB_REPOSITORY/deployments" --input - --jq '.id') | |
| gh api "repos/$GITHUB_REPOSITORY/deployments/$deployment_id/statuses" \ | |
| -f state=in_progress >/dev/null | |
| echo "id=$deployment_id" >> "$GITHUB_OUTPUT" | |
| - name: Verify preview deployment | |
| id: verify | |
| env: | |
| SAME_REPO: ${{ github.event.pull_request.head.repo.full_name == github.repository }} | |
| DETECT_RESULT: ${{ needs.detect-changes.result }} | |
| PREPARE_RESULT: ${{ needs.prepare-preview-database.result }} | |
| BACKEND_RESULT: ${{ needs.deploy-preview-backend.result }} | |
| VERCEL_RESULT: ${{ needs.update-vercel-preview.result }} | |
| DEPLOY_BACKEND: ${{ needs.detect-changes.outputs.deploy_backend }} | |
| RUN_MIGRATIONS: ${{ needs.detect-changes.outputs.run_migrations }} | |
| PREVIEW_BACKEND_LIVE: ${{ needs.detect-changes.outputs.preview_backend_live }} | |
| BRANCH_WAS_CREATED: ${{ needs.prepare-preview-database.outputs.branch_was_created }} | |
| DB_BRANCH_ID: ${{ needs.prepare-preview-database.outputs.branch_id }} | |
| DB_BRANCH_REF: ${{ needs.prepare-preview-database.outputs.branch_ref }} | |
| PREVIEW_URL: ${{ needs.update-vercel-preview.outputs.preview_url }} | |
| PREVIEW_ALIAS_URL: ${{ needs.update-vercel-preview.outputs.preview_alias_url }} | |
| BACKEND_API_URL: ${{ needs.update-vercel-preview.outputs.backend_api_url }} | |
| run: | | |
| set -euo pipefail | |
| { | |
| echo "## Required preview gate" | |
| echo | |
| } >> "$GITHUB_STEP_SUMMARY" | |
| fail() { | |
| echo "::error::$1" | |
| echo "- $1" >> "$GITHUB_STEP_SUMMARY" | |
| exit 1 | |
| } | |
| if [ "$PROMOTION_PR" = "true" ]; then | |
| echo "- Promotion pull request: staging is the preview environment." >> "$GITHUB_STEP_SUMMARY" | |
| echo "- https://staging.oddish.app runs this commit (see Staging Deploy)." >> "$GITHUB_STEP_SUMMARY" | |
| exit 0 | |
| fi | |
| preview_url="${PREVIEW_ALIAS_URL:-${PREVIEW_URL:-}}" | |
| backend_required=false | |
| db_required=false | |
| if [ "$PREVIEW_BACKEND_LIVE" = "true" ]; then | |
| backend_required=true | |
| db_required=true | |
| fi | |
| if [ "$DEPLOY_BACKEND" = "true" ] || [ "$RUN_MIGRATIONS" = "true" ]; then | |
| backend_required=true | |
| db_required=true | |
| fi | |
| if [ "$SAME_REPO" != "true" ]; then | |
| fail "PR preview deployments require a same-repository branch with access to preview secrets." | |
| fi | |
| if [ "$DETECT_RESULT" != "success" ]; then | |
| fail "Preview change detection did not succeed." | |
| fi | |
| if [ "$db_required" = "true" ]; then | |
| if [ "$PREPARE_RESULT" != "success" ]; then | |
| fail "Preview database preparation did not succeed." | |
| fi | |
| if [ -z "$DB_BRANCH_ID" ] || [ -z "$DB_BRANCH_REF" ]; then | |
| fail "Preview database branch was not produced." | |
| fi | |
| elif [ "$PREPARE_RESULT" != "success" ] && [ "$PREPARE_RESULT" != "skipped" ]; then | |
| fail "Preview database preparation did not succeed." | |
| fi | |
| if [ "$backend_required" = "true" ]; then | |
| if { [ "$DEPLOY_BACKEND" = "true" ] || [ "$BRANCH_WAS_CREATED" = "true" ]; } && | |
| [ "$BACKEND_RESULT" != "success" ]; then | |
| fail "Preview backend deployment did not succeed." | |
| fi | |
| if [ "$BACKEND_RESULT" != "success" ] && [ "$BACKEND_RESULT" != "skipped" ]; then | |
| fail "Preview backend deployment did not succeed." | |
| fi | |
| if [ -z "$BACKEND_API_URL" ]; then | |
| fail "Preview backend URL was not produced." | |
| fi | |
| fi | |
| if [ "$VERCEL_RESULT" != "success" ]; then | |
| fail "Vercel preview update did not succeed." | |
| fi | |
| if [ -z "$preview_url" ]; then | |
| fail "Vercel preview URL was not produced." | |
| fi | |
| for attempt in $(seq 1 36); do | |
| status="$(curl --silent --output /dev/null --write-out '%{http_code}' --max-time 10 "$preview_url" || true)" | |
| case "$status" in | |
| 2*|3*|401|403) | |
| echo "- Frontend preview is ready: $preview_url" >> "$GITHUB_STEP_SUMMARY" | |
| break | |
| ;; | |
| esac | |
| if [ "$attempt" = "36" ]; then | |
| fail "Frontend preview never became reachable at $preview_url." | |
| fi | |
| sleep 5 | |
| done | |
| if [ "$backend_required" = "true" ]; then | |
| readiness_url="${BACKEND_API_URL%/}/openapi.json" | |
| # --max-time must outlast a backend cold start (~30s+); a shorter | |
| # one abandons every attempt mid-boot so no retry count can pass. | |
| for attempt in $(seq 1 12); do | |
| body_file="$(mktemp)" | |
| status="$(curl --silent --output "$body_file" --write-out '%{http_code}' --max-time 120 "$readiness_url" || true)" | |
| if [ "$status" = "200" ] && [ -s "$body_file" ]; then | |
| rm -f "$body_file" | |
| echo "- Backend preview is ready: $readiness_url" >> "$GITHUB_STEP_SUMMARY" | |
| break | |
| fi | |
| rm -f "$body_file" | |
| if [ "$attempt" = "12" ]; then | |
| fail "Preview backend never became ready at $readiness_url." | |
| fi | |
| sleep 5 | |
| done | |
| fi | |
| { | |
| echo "- Backend required: \`$backend_required\`" | |
| echo "- Database required: \`$db_required\`" | |
| if [ "$db_required" = "true" ]; then | |
| echo "- Database preview branch: \`$DB_BRANCH_REF\`" | |
| fi | |
| } >> "$GITHUB_STEP_SUMMARY" | |
| - name: Publish the deployment result | |
| if: always() && steps.deployment.outputs.id != '' | |
| env: | |
| DEPLOYMENT_ID: ${{ steps.deployment.outputs.id }} | |
| VERIFY_OUTCOME: ${{ steps.verify.outcome }} | |
| run: | | |
| set -euo pipefail | |
| state=failure | |
| if [ "$VERIFY_OUTCOME" = "success" ]; then state=success; fi | |
| jq -n --arg state "$state" --arg url "${DEPLOY_URL:-}" \ | |
| '{state: $state} | |
| + (if $url != "" then {environment_url: $url} else {} end)' \ | |
| | gh api "repos/$GITHUB_REPOSITORY/deployments/$DEPLOYMENT_ID/statuses" \ | |
| --input - >/dev/null | |
| echo "deployment $DEPLOYMENT_ID marked $state" | |
| post-preview-links: | |
| name: Post preview links | |
| needs: | |
| - detect-changes | |
| - prepare-preview-database | |
| - deploy-preview-backend | |
| - update-vercel-preview | |
| if: | | |
| always() && | |
| needs.detect-changes.result == 'success' && | |
| needs.detect-changes.outputs.any_change == 'true' | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| issues: write | |
| pull-requests: write | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| PR_NUMBER: ${{ github.event.pull_request.number }} | |
| PREVIEW_COMMIT_SHA: ${{ github.event.pull_request.head.sha }} | |
| DEPLOY_BACKEND: ${{ needs.detect-changes.outputs.deploy_backend }} | |
| RUN_MIGRATIONS: ${{ needs.detect-changes.outputs.run_migrations }} | |
| DEPLOY_FRONTEND: ${{ needs.detect-changes.outputs.deploy_frontend }} | |
| VERCEL_PREVIEW_URL: ${{ needs.update-vercel-preview.outputs.preview_alias_url || needs.update-vercel-preview.outputs.preview_url }} | |
| VERCEL_DEPLOYMENT_URL: ${{ needs.update-vercel-preview.outputs.preview_url }} | |
| MODAL_API_URL: ${{ needs.deploy-preview-backend.outputs.modal_api_url || needs.update-vercel-preview.outputs.backend_api_url }} | |
| PREVIEW_BACKEND_LABEL: ${{ needs.update-vercel-preview.outputs.backend_label }} | |
| PREVIEW_DATABASE_LABEL: ${{ needs.update-vercel-preview.outputs.database_label }} | |
| SUPABASE_BRANCH_REF: ${{ needs.prepare-preview-database.outputs.branch_ref }} | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v5 | |
| - name: Post preview links | |
| run: python "$GITHUB_WORKSPACE/.github/scripts/preview/post_preview_links.py" | |
| stop-preview: | |
| name: Stop preview | |
| if: >- | |
| github.event.action == 'closed' && | |
| github.event.pull_request.head.repo.full_name == github.repository && | |
| github.event.pull_request.head.ref != 'staging' | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| packages: read | |
| container: | |
| image: ghcr.io/abundant-ai/oddish-ci-base:latest | |
| credentials: | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| env: | |
| MODAL_TOKEN_ID: ${{ secrets.MODAL_TOKEN_ID }} | |
| MODAL_TOKEN_SECRET: ${{ secrets.MODAL_TOKEN_SECRET }} | |
| MODAL_ENVIRONMENT: preview | |
| MODAL_APP_NAME: oddish-pr-${{ github.event.pull_request.number }} | |
| SUPABASE_ACCESS_TOKEN: ${{ secrets.SUPABASE_ACCESS_TOKEN }} | |
| SUPABASE_PROJECT_REF: ${{ vars.SUPABASE_PROJECT_REF }} | |
| VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }} | |
| VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} | |
| VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }} | |
| VERCEL_GIT_BRANCH: ${{ github.event.pull_request.head.ref }} | |
| PR_NUMBER: ${{ github.event.pull_request.number }} | |
| PREVIEW_ALIAS_HOSTNAME: pr-${{ github.event.pull_request.number }}.oddish.app | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v5 | |
| - name: Stop preview | |
| run: "$GITHUB_WORKSPACE/.github/scripts/preview/stop_preview.sh" |