-
Notifications
You must be signed in to change notification settings - Fork 648
Set up temporary Fly deployments for PRs #546
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
kentcdodds
wants to merge
12
commits into
main
Choose a base branch
from
cursor/set-up-temporary-fly-deployments-for-prs-1d1f
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 7 commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
4f8588a
Add GitHub Actions workflow for PR preview deployments on Fly.io
cursoragent 713dddd
Modify PR preview workflow to use standalone LiteFS configuration
cursoragent 9e91f74
Refactor PR preview workflow to simplify configuration and deployment
cursoragent 2957983
Add app creation step to PR preview workflow
cursoragent 418b29a
Modify LiteFS config for PR preview to use static lease type
cursoragent 74b01ce
Configure LiteFS static lease for PR preview isolation
cursoragent a11eadb
Refactor PR preview setup into a Node.js script for better configurat…
cursoragent 0ff6cde
Refactor PR preview setup script with error handling and js-yaml
cursoragent 734f4b8
Configure PR preview with mocks mode and environment variables
cursoragent 0fca57d
Add deployable changes check and comment for content-only PRs
cursoragent 98fcb75
Add build arg to install dev dependencies for PR previews
cursoragent c9757b0
Optimize PR preview workflow and Dockerfile for faster, more reliable…
cursoragent File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,128 @@ | ||
| name: 🔍 PR Preview Deploy | ||
|
|
||
| on: | ||
| pull_request: | ||
| types: [opened, synchronize, reopened, closed] | ||
|
|
||
| env: | ||
| FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }} | ||
|
|
||
| jobs: | ||
| deploy-pr: | ||
| name: 🚀 Deploy PR Preview | ||
| runs-on: ubuntu-latest | ||
| if: github.event.action != 'closed' | ||
|
|
||
| steps: | ||
| - name: ⬇️ Checkout repo | ||
| uses: actions/checkout@v4 | ||
|
|
||
| - name: 🎈 Setup Fly | ||
| uses: superfly/flyctl-actions/[email protected] | ||
|
|
||
| - name: 🏷️ Generate app name | ||
| id: app-name | ||
| run: | | ||
| # Create a unique app name for this PR | ||
| APP_NAME="kcd-pr-${{ github.event.number }}" | ||
| echo "app_name=$APP_NAME" >> $GITHUB_OUTPUT | ||
| echo "url=https://$APP_NAME.fly.dev" >> $GITHUB_OUTPUT | ||
|
|
||
| - name: 📝 Setup PR-specific configurations | ||
| run: | | ||
| # Make script executable and run it | ||
| chmod +x other/setup-pr-preview.js | ||
| node other/setup-pr-preview.js "${{ steps.app-name.outputs.app_name }}" | ||
|
|
||
| echo "=== Modified fly.toml ===" | ||
| cat fly.toml | ||
| echo "=== Modified litefs.yml ===" | ||
| cat other/litefs.yml | ||
|
|
||
| - name: 🏗️ Create PR app | ||
| run: | | ||
| flyctl apps create ${{ steps.app-name.outputs.app_name }} --org personal || echo "App already exists" | ||
|
|
||
| - name: 🚀 Deploy PR app | ||
| run: | | ||
| flyctl deploy --depot --remote-only --build-arg COMMIT_SHA=${{ github.sha }} --app ${{ steps.app-name.outputs.app_name }} | ||
|
|
||
| - name: 💬 Comment on PR | ||
| uses: actions/github-script@v7 | ||
| with: | ||
| script: | | ||
| const { data: comments } = await github.rest.issues.listComments({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| issue_number: context.issue.number, | ||
| }); | ||
|
|
||
| const botComment = comments.find(comment => | ||
| comment.user.type === 'Bot' && comment.body.includes('PR Preview') | ||
| ); | ||
|
|
||
| const commentBody = `🚀 **PR Preview Deployed** | ||
|
|
||
| Your pull request has been deployed to a temporary Fly machine: | ||
|
|
||
| 🔗 **Preview URL**: ${{ steps.app-name.outputs.url }} | ||
| 📱 **App Name**: \`${{ steps.app-name.outputs.app_name }}\` | ||
|
|
||
| This preview will automatically scale to zero when not in use to save costs. | ||
| The app will be automatically deleted when this PR is closed or merged. | ||
|
|
||
| --- | ||
| <sub>Updated: ${new Date().toISOString()}</sub>`; | ||
|
|
||
| if (botComment) { | ||
| github.rest.issues.updateComment({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| comment_id: botComment.id, | ||
| body: commentBody | ||
| }); | ||
| } else { | ||
| github.rest.issues.createComment({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| issue_number: context.issue.number, | ||
| body: commentBody | ||
| }); | ||
| } | ||
|
|
||
| cleanup-pr: | ||
| name: 🧹 Cleanup PR Preview | ||
| runs-on: ubuntu-latest | ||
| if: github.event.action == 'closed' | ||
|
|
||
| steps: | ||
| - name: 🎈 Setup Fly | ||
| uses: superfly/flyctl-actions/[email protected] | ||
|
|
||
| - name: 🏷️ Generate app name | ||
| id: app-name | ||
| run: | | ||
| APP_NAME="kcd-pr-${{ github.event.number }}" | ||
| echo "app_name=$APP_NAME" >> $GITHUB_OUTPUT | ||
|
|
||
| - name: 🗑️ Delete PR app | ||
| run: | | ||
| flyctl apps destroy ${{ steps.app-name.outputs.app_name }} --yes || echo "App doesn't exist or already deleted" | ||
|
|
||
coderabbitai[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| - name: 💬 Comment on PR | ||
| uses: actions/github-script@v7 | ||
| with: | ||
| script: | | ||
| const commentBody = `🧹 **PR Preview Cleaned Up** | ||
|
|
||
| The temporary Fly machine for this PR has been deleted. | ||
|
|
||
| --- | ||
| <sub>Cleaned up: ${new Date().toISOString()}</sub>`; | ||
|
|
||
| github.rest.issues.createComment({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| issue_number: context.issue.number, | ||
| body: commentBody | ||
| }); | ||
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,97 @@ | ||
| #!/usr/bin/env node | ||
|
|
||
| const fs = require('fs'); | ||
| const path = require('path'); | ||
coderabbitai[bot] marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| function setupPRPreview() { | ||
| const appName = process.argv[2]; | ||
| if (!appName) { | ||
| console.error('Usage: node setup-pr-preview.js <app-name>'); | ||
| process.exit(1); | ||
| } | ||
|
|
||
| console.log(`Setting up PR preview for app: ${appName}`); | ||
|
|
||
| // Modify fly.toml | ||
| setupFlyToml(appName); | ||
|
|
||
| // Modify litefs.yml | ||
| setupLitefsYml(); | ||
|
|
||
| console.log('PR preview configuration complete!'); | ||
| } | ||
|
|
||
| function setupFlyToml(appName) { | ||
| const flyTomlPath = 'fly.toml'; | ||
| const backupPath = 'fly.toml.backup'; | ||
|
|
||
| console.log('Modifying fly.toml...'); | ||
|
|
||
| // Create backup | ||
| fs.copyFileSync(flyTomlPath, backupPath); | ||
coderabbitai[bot] marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| // Read and modify fly.toml | ||
| let flyToml = fs.readFileSync(flyTomlPath, 'utf8'); | ||
|
|
||
| // Update app name | ||
| flyToml = flyToml.replace(/^app = .*/m, `app = "${appName}"`); | ||
|
|
||
| // Remove consul from experimental section | ||
| flyToml = flyToml.replace(/^\s*enable_consul = true.*$/m, ''); | ||
|
|
||
| // Add auto-scaling configuration to services section | ||
| // Find [[services]] section and add auto-scaling after internal_port | ||
| const servicesRegex = /(\[\[services\]\][\s\S]*?internal_port = \d+)/; | ||
| if (servicesRegex.test(flyToml)) { | ||
| flyToml = flyToml.replace( | ||
| servicesRegex, | ||
| `$1 | ||
| auto_stop_machines = true | ||
| auto_start_machines = true | ||
| min_machines_running = 0 | ||
| processes = ["app"]` | ||
| ); | ||
| } | ||
|
|
||
| // Write modified fly.toml | ||
| fs.writeFileSync(flyTomlPath, flyToml); | ||
| console.log('✓ fly.toml updated'); | ||
| } | ||
|
|
||
| function setupLitefsYml() { | ||
| const litefsPath = 'other/litefs.yml'; | ||
| const backupPath = 'other/litefs.yml.backup'; | ||
|
|
||
| console.log('Modifying litefs.yml...'); | ||
|
|
||
| // Create backup | ||
| fs.copyFileSync(litefsPath, backupPath); | ||
|
|
||
| // Read litefs.yml | ||
| let litefsYml = fs.readFileSync(litefsPath, 'utf8'); | ||
|
|
||
| // Replace the lease section with static lease | ||
| // Find the lease section and replace it with static configuration | ||
| const leaseRegex = /^lease:[\s\S]*?(?=^exec:)/m; | ||
| const staticLeaseConfig = `lease: | ||
| type: 'static' | ||
|
|
||
| `; | ||
|
|
||
| litefsYml = litefsYml.replace(leaseRegex, staticLeaseConfig); | ||
|
|
||
| // Add explanatory comment before the lease section | ||
| litefsYml = litefsYml.replace( | ||
| /^lease:/m, | ||
| `# PR Preview: Using static lease type for standalone instance | ||
| # This prevents syncing with production data | ||
| lease:` | ||
| ); | ||
coderabbitai[bot] marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| // Write modified litefs.yml | ||
| fs.writeFileSync(litefsPath, litefsYml); | ||
| console.log('✓ litefs.yml updated'); | ||
| } | ||
|
|
||
| // Run the setup | ||
| setupPRPreview(); | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.