Repository navigation
Merge pull request #34 from firtoz/chore/remove-renovate-dependabot #41
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
| # **`push`** **`main`**: **Quality** (**`quality-reusable.yml`**) then **staging** deploy + optional **main → production** PR. | |
| # | |
| # Operators: **`bun run github:sync:staging`** syncs **`staging`** + repo policy from **`config/github.policy.ts`**. | |
| name: Main | |
| env: | |
| TURBO_TELEMETRY_DISABLED: "1" | |
| on: | |
| push: | |
| branches: [main] | |
| concurrency: | |
| group: staging-deploy | |
| cancel-in-progress: false | |
| permissions: | |
| contents: read | |
| jobs: | |
| quality: | |
| uses: ./.github/workflows/quality-reusable.yml | |
| with: | |
| concurrency_group_suffix: ${{ github.workflow }}-${{ github.ref }} | |
| quality_ruleset_gate: | |
| name: Quality checks | |
| needs: quality | |
| if: always() | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| steps: | |
| - name: Require reusable Quality workflow succeeded | |
| env: | |
| QUALITY_RESULT: ${{ needs.quality.result }} | |
| run: | | |
| set -euo pipefail | |
| if [[ "$QUALITY_RESULT" != "success" ]]; then | |
| echo "::error::Reusable Quality workflow finished with result ${QUALITY_RESULT}." | |
| exit 1 | |
| fi | |
| echo "Quality gate: reusable workflow succeeded." | |
| deploy: | |
| name: Deploy to staging | |
| needs: quality_ruleset_gate | |
| outputs: | |
| did_staging_deploy: ${{ steps.deploy_result.outputs.did_staging_deploy }} | |
| auto_production_pr: ${{ steps.deploy_result.outputs.auto_production_pr }} | |
| runs-on: ubuntu-latest | |
| environment: staging | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| ref: ${{ github.sha }} | |
| persist-credentials: false | |
| - uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 | |
| with: | |
| bun-version: 1.3.13 | |
| - name: Install dependencies | |
| run: bun install --frozen-lockfile | |
| - name: Deploy preflight | |
| id: preflight | |
| env: | |
| CI: true | |
| STAGE: staging | |
| DEPLOY_ENABLED: ${{ vars.DEPLOY_ENABLED }} | |
| ALCHEMY_PASSWORD: ${{ secrets.ALCHEMY_PASSWORD }} | |
| ALCHEMY_STATE_TOKEN: ${{ secrets.ALCHEMY_STATE_TOKEN }} | |
| CHATROOM_INTERNAL_SECRET: ${{ secrets.CHATROOM_INTERNAL_SECRET }} | |
| CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} | |
| CLOUDFLARE_ACCOUNT_ID: ${{ vars.CLOUDFLARE_ACCOUNT_ID }} | |
| BETTER_AUTH_SECRET: ${{ secrets.BETTER_AUTH_SECRET }} | |
| AUTH_ADMIN_SECRET: ${{ secrets.AUTH_ADMIN_SECRET }} | |
| run: bun run deploy:preflight:staging | |
| - name: Turbo deploy (staging) | |
| id: deploy | |
| if: steps.preflight.outputs.deploy_enabled == 'true' | |
| env: | |
| CI: true | |
| STAGE: staging | |
| ALCHEMY_PASSWORD: ${{ secrets.ALCHEMY_PASSWORD }} | |
| ALCHEMY_STATE_TOKEN: ${{ secrets.ALCHEMY_STATE_TOKEN }} | |
| CHATROOM_INTERNAL_SECRET: ${{ secrets.CHATROOM_INTERNAL_SECRET }} | |
| CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} | |
| CLOUDFLARE_ACCOUNT_ID: ${{ vars.CLOUDFLARE_ACCOUNT_ID }} | |
| BETTER_AUTH_SECRET: ${{ secrets.BETTER_AUTH_SECRET }} | |
| AUTH_ADMIN_SECRET: ${{ secrets.AUTH_ADMIN_SECRET }} | |
| AUTH_BOOTSTRAP_ADMIN_EMAILS: ${{ vars.AUTH_BOOTSTRAP_ADMIN_EMAILS }} | |
| GOOGLE_CLIENT_ID: ${{ vars.GOOGLE_CLIENT_ID }} | |
| GOOGLE_CLIENT_SECRET: ${{ secrets.GOOGLE_CLIENT_SECRET }} | |
| GH_CLIENT_ID: ${{ vars.GH_CLIENT_ID }} | |
| GH_CLIENT_SECRET: ${{ secrets.GH_CLIENT_SECRET }} | |
| AUTH_DOMAINS: ${{ vars.AUTH_DOMAINS }} | |
| WEB_DOMAINS: ${{ vars.WEB_DOMAINS }} | |
| WEB_ROUTES: ${{ vars.WEB_ROUTES }} | |
| WEB_ZONE_ID: ${{ vars.WEB_ZONE_ID }} | |
| WEB_DOMAIN_OVERRIDE_EXISTING_ORIGIN: ${{ vars.WEB_DOMAIN_OVERRIDE_EXISTING_ORIGIN }} | |
| POSTHOG_KEY: ${{ vars.POSTHOG_KEY }} | |
| POSTHOG_HOST: ${{ vars.POSTHOG_HOST }} | |
| POSTHOG_REGION: ${{ vars.POSTHOG_REGION }} | |
| POSTHOG_UI_HOST: ${{ vars.POSTHOG_UI_HOST }} | |
| POSTHOG_SITE: ${{ vars.POSTHOG_SITE }} | |
| POSTHOG_CLI_TOKEN: ${{ secrets.POSTHOG_CLI_TOKEN }} | |
| POSTHOG_CLI_ENV_ID: ${{ vars.POSTHOG_CLI_ENV_ID }} | |
| POSTHOG_CLI_HOST: ${{ vars.POSTHOG_CLI_HOST }} | |
| POSTHOG_RELEASE_VERSION: ${{ github.sha }} | |
| run: | | |
| set -o pipefail | |
| bun run deploy:staging 2>&1 | tee deploy-output.txt | |
| deploy_status=${PIPESTATUS[0]} | |
| URL_FILE="$GITHUB_WORKSPACE/.alchemy/ci/web-deploy-url.txt" | |
| WEB_URL="" | |
| if [[ -f "$URL_FILE" ]]; then | |
| IFS= read -r WEB_URL <"$URL_FILE" || true | |
| fi | |
| echo "web_url=$WEB_URL" >> "$GITHUB_OUTPUT" | |
| exit "$deploy_status" | |
| - name: Sync bootstrap admins | |
| if: steps.preflight.outputs.deploy_enabled == 'true' && steps.deploy.outcome == 'success' | |
| env: | |
| STAGE: staging | |
| AUTH_ADMIN_SECRET: ${{ secrets.AUTH_ADMIN_SECRET }} | |
| AUTH_BOOTSTRAP_ADMIN_EMAILS: ${{ vars.AUTH_BOOTSTRAP_ADMIN_EMAILS }} | |
| run: bun run auth:sync-bootstrap-admins | |
| - name: Deploy summary | |
| if: always() | |
| env: | |
| WORKFLOW_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} | |
| WEB_URL_FROM_STEP: ${{ steps.deploy.outputs.web_url }} | |
| PF_OUT: ${{ steps.preflight.outcome }} | |
| DE_OUT: ${{ steps.deploy.outcome }} | |
| EN: ${{ steps.preflight.outputs.deploy_enabled }} | |
| run: | | |
| WEB_URL="$WEB_URL_FROM_STEP" | |
| URL_FILE="$GITHUB_WORKSPACE/.alchemy/ci/web-deploy-url.txt" | |
| if [[ -z "$WEB_URL" && -f "$URL_FILE" ]]; then | |
| IFS= read -r WEB_URL <"$URL_FILE" || true | |
| fi | |
| { | |
| echo "## Staging deploy" | |
| echo "" | |
| if [[ "$PF_OUT" == "failure" ]]; then | |
| echo "**Status:** preflight failed — see **Deploy preflight**." | |
| elif [[ "$PF_OUT" == "skipped" ]]; then | |
| echo "**Status:** skipped before preflight." | |
| elif [[ "$EN" != "true" ]]; then | |
| echo "**Status:** skipped — \`DEPLOY_ENABLED\` is not \`true\` on GitHub Environment **staging**." | |
| elif [[ "$DE_OUT" == "success" ]]; then | |
| echo "**Status:** success" | |
| if [[ -n "$WEB_URL" ]]; then | |
| echo "**App (workers.dev):** [$WEB_URL]($WEB_URL)" | |
| fi | |
| elif [[ "$DE_OUT" == "failure" ]]; then | |
| echo "**Status:** Turbo deploy failed — inspect logs." | |
| else | |
| echo "**Status:** inspect [run]($WORKFLOW_URL)." | |
| fi | |
| } >> "$GITHUB_STEP_SUMMARY" | |
| bash "$GITHUB_WORKSPACE/.github/scripts/posthog-sourcemaps-step-summary.sh" | |
| - name: Record staging deploy outcome | |
| id: deploy_result | |
| if: always() | |
| env: | |
| AUTO_PRODUCTION_PR: ${{ vars.AUTO_PRODUCTION_PR }} | |
| PF_DEPLOY_ENABLED: ${{ steps.preflight.outputs.deploy_enabled }} | |
| DE_OUTCOME: ${{ steps.deploy.outcome }} | |
| run: | | |
| pf="${PF_DEPLOY_ENABLED}" | |
| de="${DE_OUTCOME}" | |
| if [[ "${pf:-}" == "true" && "${de:-}" == "success" ]]; then | |
| echo "did_staging_deploy=true" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "did_staging_deploy=false" >> "$GITHUB_OUTPUT" | |
| fi | |
| if [[ "${AUTO_PRODUCTION_PR:-}" == "true" ]]; then | |
| echo "auto_production_pr=true" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "auto_production_pr=false" >> "$GITHUB_OUTPUT" | |
| fi | |
| maybe_production_pr: | |
| name: Open or reuse production PR | |
| needs: deploy | |
| if: >- | |
| needs.deploy.outputs.did_staging_deploy == 'true' && | |
| needs.deploy.outputs.auto_production_pr == 'true' | |
| runs-on: ubuntu-latest | |
| environment: staging | |
| permissions: | |
| contents: read | |
| pull-requests: write | |
| checks: write | |
| steps: | |
| - name: Create or note existing PR (main → production) | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| PRODUCTION_PR_HEAD_RAW: ${{ vars.PRODUCTION_PR_HEAD }} | |
| run: | | |
| set -euo pipefail | |
| REPO="${{ github.repository }}" | |
| PROD_PR_HEAD="${PRODUCTION_PR_HEAD_RAW:-main}" | |
| RUN_URL="${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" | |
| # Invisible marker: only PRs created (or previously updated) by this job get description refreshes. | |
| AUTO_PRODUCTION_PR_MARKER='<!-- github-actions:main-push.yml:auto-production-pr -->' | |
| # gh pr list --head accepts the branch name only; "owner:branch" is not supported | |
| # (see gh pr list --help). Prefer same-repo rows when multiple PRs share the head ref. | |
| production_pr_body() { | |
| printf '%s\n\n%s\n\n%s' \ | |
| "Staging deploy succeeded: ${RUN_URL}" \ | |
| "Merge this PR to deploy **production** (see \`.github/workflows/prod-deploy.yml\`)." \ | |
| "${AUTO_PRODUCTION_PR_MARKER}" | |
| } | |
| fetch_same_repo_production_pr() { | |
| local raw | |
| raw="$(gh pr list --repo "${REPO}" --base production --head "${PROD_PR_HEAD}" --state open \ | |
| --json number,url,body,headRefOid,isCrossRepository 2>/dev/null || true)" | |
| [[ -z "${raw}" ]] && raw='[]' | |
| echo "${raw}" | jq -c '[.[] | select(.isCrossRepository | not)][0] // empty' | |
| } | |
| # The **Production merge source** required check is normally produced by | |
| # restrict-production-pr-source.yml on pull_request. Events raised with | |
| # GITHUB_TOKEN (including PRs opened by Actions) do not start new workflow | |
| # runs, so that check never appears. Recreate the same check conclusion via | |
| # the Checks API so production rulesets can merge. | |
| post_production_merge_source_check() { | |
| local sha="${1:-}" | |
| if [[ -z "${sha}" ]]; then | |
| sha="$(gh pr list --repo "${REPO}" --base production --head "${PROD_PR_HEAD}" --state open \ | |
| --json headRefOid,isCrossRepository 2>/dev/null | jq -r '[.[] | select(.isCrossRepository | not)][0].headRefOid // empty' || true)" | |
| fi | |
| if [[ -z "${sha}" ]]; then | |
| echo "::warning::Production merge source: could not resolve PR head SHA; check run not posted." | |
| return 0 | |
| fi | |
| gh api --method POST "/repos/${REPO}/check-runs" \ | |
| -f name="Production merge source" \ | |
| -f head_sha="${sha}" \ | |
| -f status="completed" \ | |
| -f conclusion="success" | |
| } | |
| if ! gh api "repos/${REPO}/branches/production" --silent 2>/dev/null; then | |
| { | |
| echo "## Production PR" | |
| echo "" | |
| echo "**Skipped:** remote branch \`production\` does not exist yet." | |
| echo "Create it once (for example push \`main\` to \`production\`), then rerun this workflow or open a PR manually." | |
| } >> "$GITHUB_STEP_SUMMARY" | |
| exit 0 | |
| fi | |
| prod_pr="$(fetch_same_repo_production_pr)" | |
| REFRESHED=false | |
| JUST_CREATED=false | |
| PR_SUMMARY_LABEL="Already open" | |
| if [[ -z "${prod_pr}" ]]; then | |
| PR_SUMMARY_LABEL="Opened" | |
| set +e | |
| CREATE_ERR="$(gh pr create --repo "${REPO}" --base production --head "${PROD_PR_HEAD}" \ | |
| --title "Deploy staging to production" \ | |
| --body "$(production_pr_body)" 2>&1)" | |
| CREATE_RC=$? | |
| set -e | |
| if [[ "${CREATE_RC}" -ne 0 ]]; then | |
| if echo "${CREATE_ERR}" | grep -qF 'already exists'; then | |
| echo "::notice::Production PR already exists; continuing." | |
| PR_SUMMARY_LABEL="Already open" | |
| else | |
| echo "${CREATE_ERR}" >&2 | |
| exit "${CREATE_RC}" | |
| fi | |
| else | |
| JUST_CREATED=true | |
| fi | |
| prod_pr="$(fetch_same_repo_production_pr)" | |
| fi | |
| if [[ -z "${prod_pr}" ]]; then | |
| echo "::error::Could not resolve ${PROD_PR_HEAD} → production PR after create." | |
| exit 1 | |
| fi | |
| PR_NUMBER="$(echo "${prod_pr}" | jq -r '.number // empty')" | |
| PR_URL="$(echo "${prod_pr}" | jq -r '.url // empty')" | |
| PR_BODY="$(echo "${prod_pr}" | jq -r '.body // ""')" | |
| PR_SHA="$(echo "${prod_pr}" | jq -r '.headRefOid // empty')" | |
| if [[ "${JUST_CREATED}" != "true" ]] && echo "${PR_BODY}" | grep -qF "${AUTO_PRODUCTION_PR_MARKER}"; then | |
| gh pr edit "${PR_NUMBER}" --repo "${REPO}" --body "$(production_pr_body)" | |
| REFRESHED=true | |
| fi | |
| { | |
| echo "## Production PR" | |
| if [[ -n "${PR_URL}" ]]; then | |
| echo "**${PR_SUMMARY_LABEL}:** [${PR_URL}](${PR_URL}) (**${PROD_PR_HEAD}** → **production**)." | |
| else | |
| echo "${PR_SUMMARY_LABEL} **${PROD_PR_HEAD}** → **production** (PR URL unavailable — check the **Pull requests** tab)." | |
| fi | |
| echo "" | |
| echo "Merge this PR to deploy **production**." | |
| if [[ "${REFRESHED}" == "true" ]]; then | |
| echo "" | |
| echo "Refreshed the PR description (marker-managed auto body) with the latest staging deploy link." | |
| fi | |
| } >> "$GITHUB_STEP_SUMMARY" | |
| post_production_merge_source_check "${PR_SHA}" |