diff --git a/.github/workflows/cleanup-preview.yaml b/.github/workflows/cleanup-preview.yaml new file mode 100644 index 0000000..e42d219 --- /dev/null +++ b/.github/workflows/cleanup-preview.yaml @@ -0,0 +1,48 @@ +# This workflow destroys the preview environment/deployment when a PR is closed. +# It prevents preview resources from leaking/stale after close. + +name: Cleanup Preview +on: + pull_request: + branches: + - main + types: + - closed +concurrency: + group: cleanup-preview-${{ github.ref }} + cancel-in-progress: false +env: + NODE_VERSION: '24.11.1' + PNPM_VERSION: '10.23.0' + STAGE: ${{ format('preview-{0}', github.event.number) }} +jobs: + cleanup: + runs-on: ubuntu-latest + permissions: + id-token: write + contents: read + pull-requests: write + steps: + - uses: actions/checkout@v4 + - name: Setup pnpm + uses: pnpm/action-setup@v4 + with: + version: ${{ env.PNPM_VERSION }} + run_install: false + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: ${{ env.NODE_VERSION }} + cache: pnpm + - name: Install dependencies + run: pnpm install + - name: Destroy Preview Environment + run: pnpm alchemy destroy --stage ${{ env.STAGE }} + env: + # Alchemy + HOSTNAME: ${{ vars.HOSTNAME }} + ALCHEMY_SECRET: ${{ secrets.ALCHEMY_SECRET }} + ALCHEMY_STATE_TOKEN: ${{ secrets.ALCHEMY_STATE_TOKEN }} + CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} + CLOUDFLARE_EMAIL: ${{ secrets.CLOUDFLARE_EMAIL }} + PULL_REQUEST: ${{ github.event.number }} diff --git a/.github/workflows/deployment.yml b/.github/workflows/deployment-preview.yaml similarity index 50% rename from .github/workflows/deployment.yml rename to .github/workflows/deployment-preview.yaml index e082841..05be620 100644 --- a/.github/workflows/deployment.yml +++ b/.github/workflows/deployment-preview.yaml @@ -1,8 +1,9 @@ -name: Deployment +# Deploys a per-PR preview environment for this repository. +# Triggered when a PR targeting main (commonly from release/* or hotfix/*) is opened, reopened, or updated (synchronize). +# Deploys to the "preview" environment with stage name "preview-" . + +name: Deployment (Preview) on: - push: - branches: - - main pull_request: branches: - main @@ -10,20 +11,18 @@ on: - opened - reopened - synchronize - - closed concurrency: - group: deployment-${{ github.ref }} + group: deployment-preview-${{ github.ref }} cancel-in-progress: false env: NODE_VERSION: '24.11.1' PNPM_VERSION: '10.23.0' - STAGE: ${{ github.event_name == 'pull_request' && format('preview-{0}', github.event.number) || (github.ref == 'refs/heads/main' && 'production' || github.ref_name) }} + STAGE: ${{ format('preview-{0}', github.event.number) }} jobs: deploy: - if: ${{ github.event.action != 'closed' }} runs-on: ubuntu-latest environment: - name: ${{ github.ref == 'refs/heads/main' && 'production' || 'preview' }} + name: preview permissions: contents: read pull-requests: write @@ -62,42 +61,3 @@ jobs: POSTHOG_CLI_HOST: ${{ vars.POSTHOG_CLI_HOST }} POSTHOG_CLI_ENV_ID: ${{ secrets.POSTHOG_CLI_ENV_ID }} POSTHOG_CLI_TOKEN: ${{ secrets.POSTHOG_CLI_TOKEN }} - cleanup: - if: ${{ github.event_name == 'pull_request' && github.event.action == 'closed' }} - runs-on: ubuntu-latest - environment: - name: ${{ github.ref == 'refs/heads/main' && 'production' || 'preview' }} - permissions: - id-token: write - contents: read - pull-requests: write - steps: - - uses: actions/checkout@v4 - - name: Setup pnpm - uses: pnpm/action-setup@v4 - with: - version: ${{ env.PNPM_VERSION }} - run_install: false - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: ${{ env.NODE_VERSION }} - cache: pnpm - - name: Install dependencies - run: pnpm install - - name: Safety Check - run: |- - if [ "${{ env.STAGE }}" = "production" ]; then - echo "ERROR: Cannot destroy production environment in cleanup job" - exit 1 - fi - - name: Destroy Preview Environment - run: pnpm alchemy destroy --stage ${{ env.STAGE }} - env: - # Alchemy - HOSTNAME: ${{ vars.HOSTNAME }} - ALCHEMY_SECRET: ${{ secrets.ALCHEMY_SECRET }} - ALCHEMY_STATE_TOKEN: ${{ secrets.ALCHEMY_STATE_TOKEN }} - CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} - CLOUDFLARE_EMAIL: ${{ secrets.CLOUDFLARE_EMAIL }} - PULL_REQUEST: ${{ github.event.number }} diff --git a/.github/workflows/deployment-production.yaml b/.github/workflows/deployment-production.yaml new file mode 100644 index 0000000..d0492ed --- /dev/null +++ b/.github/workflows/deployment-production.yaml @@ -0,0 +1,54 @@ +# Deploys the main branch to the production environment on every push to main. +# Deploys to the GitHub environment "production" with stage name "production". + +name: Deployment (Production) +on: + push: + branches: + - main +concurrency: + group: deployment-production-${{ github.ref }} + cancel-in-progress: false +env: + NODE_VERSION: '24.11.1' + PNPM_VERSION: '10.23.0' + STAGE: 'production' +jobs: + deploy: + runs-on: ubuntu-latest + environment: + name: production + permissions: + contents: read + steps: + - uses: actions/checkout@v4 + - name: Setup pnpm + uses: pnpm/action-setup@v4 + with: + version: ${{ env.PNPM_VERSION }} + run_install: false + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: ${{ env.NODE_VERSION }} + cache: pnpm + - name: Install dependencies + run: pnpm install + - name: Build and deploy + run: pnpm alchemy deploy --stage ${{ env.STAGE }} + env: + # Alchemy + HOSTNAME: ${{ vars.HOSTNAME }} + ALCHEMY_SECRET: ${{ secrets.ALCHEMY_SECRET }} + ALCHEMY_STATE_TOKEN: ${{ secrets.ALCHEMY_STATE_TOKEN }} + CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} + CLOUDFLARE_EMAIL: ${{ secrets.CLOUDFLARE_EMAIL }} + # Build + VITE_PUBLIC_POSTHOG_HOST: ${{ vars.VITE_PUBLIC_POSTHOG_HOST }} + VITE_PUBLIC_POSTHOG_KEY: ${{ secrets.VITE_PUBLIC_POSTHOG_KEY }} + VITE_PUBLIC_POSTHOG_DEBUG: ${{ vars.VITE_PUBLIC_POSTHOG_DEBUG }} + VITE_PUBLIC_POSTHOG_ENABLED: ${{ vars.VITE_PUBLIC_POSTHOG_ENABLED }} + # Sourcemap inject and upload + POSTHOG_CLI_HOST: ${{ vars.POSTHOG_CLI_HOST }} + POSTHOG_CLI_ENV_ID: ${{ secrets.POSTHOG_CLI_ENV_ID }} + POSTHOG_CLI_TOKEN: ${{ secrets.POSTHOG_CLI_TOKEN }}