📝 Add agent architecture guidance #43
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: Deploy | |
| on: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| branches: [main] | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| env: | |
| CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} | |
| CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} | |
| jobs: | |
| deploy: | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| deployments: write | |
| pull-requests: write | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| - name: Install dependencies | |
| run: npm install | |
| - name: Build | |
| run: npm run build | |
| env: | |
| NOTION_TOKEN: ${{ secrets.NOTION_TOKEN }} | |
| NOTION_CLIMBS_DB_ID: ${{ secrets.NOTION_CLIMBS_DB_ID }} | |
| NOTION_PEAKS_DB_ID: ${{ secrets.NOTION_PEAKS_DB_ID }} | |
| NOTION_GEAR_DB_ID: ${{ secrets.NOTION_GEAR_DB_ID }} | |
| NOTION_PHOTOS_DB_ID: ${{ secrets.NOTION_PHOTOS_DB_ID }} | |
| # Preview deployment for PRs | |
| - name: Create Preview Deployment | |
| if: github.event_name == 'pull_request' | |
| id: preview-deployment | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const deployment = await github.rest.repos.createDeployment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| ref: context.payload.pull_request.head.sha, | |
| environment: 'preview', | |
| auto_merge: false, | |
| required_contexts: [], | |
| description: `Preview deployment for PR #${context.payload.pull_request.number}` | |
| }); | |
| return deployment.data.id; | |
| result-encoding: string | |
| - name: generate preview name from pr title | |
| if: github.event_name == 'pull_request' | |
| id: slug | |
| run: | | |
| TITLE="${{ github.event.pull_request.title }}" | |
| WORD=$(echo "$TITLE" | sed -E 's/^(fix|feat|chore|docs|refactor|test|ci|style|perf|build|revert|rewrite|add|update|remove|delete)(\([^)]*\))?[\:!]?\s*//i' | awk '{print $1}' | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9-]//g' | cut -c1-12) | |
| [ -z "$WORD" ] && WORD="pr${{ github.event.pull_request.number }}" | |
| echo "name=climb-log-${WORD}-${{ github.event.pull_request.number }}" >> $GITHUB_OUTPUT | |
| - name: generate preview config | |
| if: github.event_name == 'pull_request' | |
| run: | | |
| # Astro builds worker output to dist/server/ with static assets in dist/client/ | |
| # We need main pointing to the worker entry and assets to the client directory | |
| # NOTE: Secrets are set via `wrangler secret put`, NOT in vars (which are plaintext) | |
| jq --arg name "${{ steps.slug.outputs.name }}" ' | |
| .name = $name | |
| | .main = "./dist/server/entry.mjs" | |
| | .assets.directory = "./dist/client" | |
| | .d1_databases[0].database_id = "c0e56b31-fbfd-46f9-992e-af369d9c2cb9" | |
| | .d1_databases[0].database_name = "climb-log-db-preview" | |
| | .vars.NOTION_CLIMBS_DB_ID = "${{ secrets.NOTION_CLIMBS_DB_ID }}" | |
| | .vars.NOTION_PEAKS_DB_ID = "${{ secrets.NOTION_PEAKS_DB_ID }}" | |
| | .vars.NOTION_GEAR_DB_ID = "${{ secrets.NOTION_GEAR_DB_ID }}" | |
| | .vars.NOTION_PHOTOS_DB_ID = "${{ secrets.NOTION_PHOTOS_DB_ID }}" | |
| | del(.env) | |
| ' wrangler.jsonc > wrangler-preview.jsonc | |
| - name: Deploy to Preview | |
| if: github.event_name == 'pull_request' | |
| id: deploy-preview | |
| run: | | |
| START_TIME=$(date +%s) | |
| set +e | |
| npx wrangler deploy --config wrangler-preview.jsonc 2>&1 | |
| EXIT_CODE=$? | |
| set -e | |
| END_TIME=$(date +%s) | |
| DEPLOY_TIME=$((END_TIME - START_TIME)) | |
| echo "deploy_time=${DEPLOY_TIME}s" >> $GITHUB_OUTPUT | |
| echo "preview_url=https://${{ steps.slug.outputs.name }}.kylieski.workers.dev" >> $GITHUB_OUTPUT | |
| exit $EXIT_CODE | |
| - name: Set preview secrets | |
| if: github.event_name == 'pull_request' | |
| run: | | |
| # Set secrets via wrangler secret put (not plaintext vars) | |
| echo "${{ secrets.NOTION_TOKEN }}" | npx wrangler secret put NOTION_TOKEN --config wrangler-preview.jsonc | |
| echo "${{ secrets.CRON_SECRET }}" | npx wrangler secret put CRON_SECRET --config wrangler-preview.jsonc | |
| - name: apply migrations to preview db | |
| if: github.event_name == 'pull_request' | |
| run: | | |
| npx wrangler d1 migrations apply climb-log-db-preview --remote --config wrangler-preview.jsonc | |
| env: | |
| CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} | |
| - name: seed preview db | |
| if: github.event_name == 'pull_request' | |
| run: | | |
| npx tsx db/seed.ts | |
| npx wrangler d1 execute climb-log-db-preview --remote --file=db/seed.sql | |
| env: | |
| CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} | |
| - name: Update Preview Deployment Status | |
| if: github.event_name == 'pull_request' | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const deploymentId = ${{ steps.preview-deployment.outputs.result }}; | |
| const previewUrl = '${{ steps.deploy-preview.outputs.preview_url }}'; | |
| await github.rest.repos.createDeploymentStatus({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| deployment_id: deploymentId, | |
| state: 'success', | |
| environment_url: previewUrl, | |
| description: 'Preview deployment successful' | |
| }); | |
| - name: comment preview url | |
| if: github.event_name == 'pull_request' && !startsWith(github.head_ref, 'blog/') && !startsWith(github.head_ref, 'post/') | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const marker = '<!-- climb-log-preview-bot -->'; | |
| const isNew = context.payload.action === 'opened'; | |
| const verb = isNew ? 'deployed' : 'updated'; | |
| const emoji = isNew ? '🚀' : '⛰️'; | |
| const dbUrl = 'https://dash.cloudflare.com/bb52c0e5f3a93fc72779915d7dc6982b/workers/d1/databases/c0e56b31-fbfd-46f9-992e-af369d9c2cb9'; | |
| const previewUrl = '${{ steps.deploy-preview.outputs.preview_url }}'; | |
| const deployTime = '${{ steps.deploy-preview.outputs.deploy_time }}'; | |
| const commitSha = '${{ github.event.pull_request.head.sha }}'.substring(0, 7); | |
| const body = `${marker}\n${emoji} Preview ${verb}!\n\n| | |\n|------|------|\n| 🔗 Preview | ${previewUrl} |\n| 📊 Database | [climb-log-db-preview](${dbUrl}) |\n| ⏱️ Deploy Time | ${deployTime} |\n| 📝 Commit | \`${commitSha}\` |\n\n_This preview updates automatically with each push._`; | |
| const { data: comments } = await github.rest.issues.listComments({ | |
| issue_number: context.issue.number, | |
| owner: context.repo.owner, | |
| repo: context.repo.repo | |
| }); | |
| const existing = comments.find(c => c.body && c.body.includes(marker)); | |
| if (existing) { | |
| await github.rest.issues.updateComment({ | |
| comment_id: existing.id, | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| body: body | |
| }); | |
| } else { | |
| await github.rest.issues.createComment({ | |
| issue_number: context.issue.number, | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| body: body | |
| }); | |
| } | |
| # Production deployment on push to main | |
| - name: Create Production Deployment | |
| if: github.event_name == 'push' && github.ref == 'refs/heads/main' | |
| id: prod-deployment | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const deployment = await github.rest.repos.createDeployment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| ref: context.sha, | |
| environment: 'production', | |
| auto_merge: false, | |
| required_contexts: [], | |
| description: 'Production deployment' | |
| }); | |
| return deployment.data.id; | |
| result-encoding: string | |
| - name: Deploy to Production | |
| if: github.event_name == 'push' && github.ref == 'refs/heads/main' | |
| id: deploy-prod | |
| run: | | |
| npx wrangler deploy | |
| echo "prod_url=https://climb-log.kylieski.workers.dev" >> $GITHUB_OUTPUT | |
| - name: Update Production Deployment Status | |
| if: github.event_name == 'push' && github.ref == 'refs/heads/main' | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const deploymentId = ${{ steps.prod-deployment.outputs.result }}; | |
| await github.rest.repos.createDeploymentStatus({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| deployment_id: deploymentId, | |
| state: 'success', | |
| environment_url: 'https://climb-log.kylieski.workers.dev', | |
| description: 'Production deployment successful' | |
| }); | |
| - name: Handle Deployment Failure | |
| if: failure() | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| let deploymentId; | |
| if (context.eventName === 'pull_request') { | |
| deploymentId = '${{ steps.preview-deployment.outputs.result }}'; | |
| } else { | |
| deploymentId = '${{ steps.prod-deployment.outputs.result }}'; | |
| } | |
| if (deploymentId && deploymentId !== '') { | |
| await github.rest.repos.createDeploymentStatus({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| deployment_id: parseInt(deploymentId), | |
| state: 'failure', | |
| description: 'Deployment failed' | |
| }); | |
| } |