Skip to content

feat: Miru 2.0 - Modern UI upgrade with Geist font and Ferrum PDF generation #10

feat: Miru 2.0 - Modern UI upgrade with Geist font and Ferrum PDF generation

feat: Miru 2.0 - Modern UI upgrade with Geist font and Ferrum PDF generation #10

Workflow file for this run

name: Deploy Review App
on:
pull_request:
types: [opened, synchronize, reopened]
jobs:
deploy:
runs-on: ubuntu-latest
if: github.event.pull_request.draft == false
steps:
- uses: actions/checkout@v4
- name: Setup Fly CLI
uses: superfly/flyctl-actions/setup-flyctl@master
- name: Generate App Name
id: app_name
run: |
BRANCH_SLUG=$(echo "${{ github.head_ref }}" | sed 's/[^a-zA-Z0-9-]/-/g' | tr '[:upper:]' '[:lower:]' | cut -c1-30)
APP_NAME="miru-pr-${{ github.event.pull_request.number }}-${BRANCH_SLUG}"
echo "name=${APP_NAME}" >> $GITHUB_OUTPUT
echo "url=https://${APP_NAME}.fly.dev" >> $GITHUB_OUTPUT
- name: Deploy to Fly.io
env:
FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}
run: |
# Create app if it doesn't exist
if ! fly apps list | grep -q "${{ steps.app_name.outputs.name }}"; then
fly apps create "${{ steps.app_name.outputs.name }}" --org personal
# Create PostgreSQL
fly postgres create --name "${{ steps.app_name.outputs.name }}-db" \
--region iad \
--initial-cluster-size 1 \
--vm-size shared-cpu-1x \
--volume-size 1 \
--no-replicas
# Attach database
fly postgres attach "${{ steps.app_name.outputs.name }}-db" \
--app "${{ steps.app_name.outputs.name }}"
fi
# Set secrets
fly secrets set \
SECRET_KEY_BASE=${{ secrets.RAILS_SECRET_KEY_BASE }} \
RAILS_MASTER_KEY=${{ secrets.RAILS_MASTER_KEY }} \
--app "${{ steps.app_name.outputs.name }}"
# Deploy
fly deploy --app "${{ steps.app_name.outputs.name }}" \
--config fly.review.toml \
--build-arg REVIEW_APP_BRANCH="${{ github.head_ref }}"
- name: Run Playwright Tests
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install Playwright
run: |
npm install -g playwright
npx playwright install chromium
- name: Test Review App
id: test_app
run: |
# Wait for app to be ready
for i in {1..30}; do
if curl -s "${{ steps.app_name.outputs.url }}/health" | grep -q "healthy"; then
echo "App is healthy!"
break
fi
echo "Waiting for app to be ready... (attempt $i/30)"
sleep 10
done
# Run Playwright login test
npx playwright test --project=chromium tests/review-app-login.spec.ts
env:
REVIEW_APP_URL: ${{ steps.app_name.outputs.url }}
- name: Comment on PR
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const appName = '${{ steps.app_name.outputs.name }}';
const appUrl = '${{ steps.app_name.outputs.url }}';
const branch = '${{ github.head_ref }}';
const body = `## 🚀 Review App Deployed!
**App Name:** \`${appName}\`
**URL:** ${appUrl}
**Branch:** \`${branch}\`
### 📊 Deployment Details
- **Region:** US East (iad)
- **Database:** PostgreSQL (1GB)
- **Machine:** shared-cpu-1x (512MB RAM)
### 🧪 Test Results
- Health Check: ✅ Passed
- Login Test: ${{ steps.test_app.outcome == 'success' && '✅ Passed' || '❌ Failed' }}
### 🔧 Useful Commands
\`\`\`bash
# View logs
fly logs --app ${appName}
# SSH into app
fly ssh console --app ${appName}
# Open database console
fly postgres connect --app ${appName}-db
# Destroy app (when PR is closed)
fly destroy ${appName} --yes
fly destroy ${appName}-db --yes
\`\`\`
### 📱 Mobile App Testing
For mobile app testing, update your mobile app's base URL to:
\`\`\`
${appUrl}
\`\`\`
---
<sub>🤖 Deployed with GitHub Actions | [View Workflow](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})</sub>`;
// Find existing comment
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('Review App Deployed')
);
if (botComment) {
// Update existing comment
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: botComment.id,
body: body
});
} else {
// Create new comment
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: body
});
}
cleanup:
runs-on: ubuntu-latest
if: github.event.action == 'closed'
steps:
- name: Setup Fly CLI
uses: superfly/flyctl-actions/setup-flyctl@master
- name: Destroy Review App
env:
FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}
run: |
BRANCH_SLUG=$(echo "${{ github.head_ref }}" | sed 's/[^a-zA-Z0-9-]/-/g' | tr '[:upper:]' '[:lower:]' | cut -c1-30)
APP_NAME="miru-pr-${{ github.event.pull_request.number }}-${BRANCH_SLUG}"
# Destroy app and database
fly destroy "${APP_NAME}" --yes || true
fly destroy "${APP_NAME}-db" --yes || true
- name: Comment on PR
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const body = '## 🧹 Review App Destroyed\n\nThe review app has been automatically destroyed since the PR was closed.';
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: body
});