Files
blackroad-os-docs/.github/workflows/auto-deploy.yml
Alexa Louise d03040419c ci: add automated CI/CD workflows
- Auto Deploy: Deploys to Railway/Cloudflare on PR and push
- Auto Merge: Approves and merges PRs when CI passes
- CI: Runs lint, tests, and builds

🤖 Generated by BlackRoad OS Automation
2025-11-30 12:09:14 -06:00

189 lines
7.7 KiB
YAML

name: Auto Deploy
on:
pull_request:
types: [opened, synchronize, reopened]
push:
branches: [main, master]
env:
RAILWAY_TOKEN: ${{ secrets.RAILWAY_TOKEN }}
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
jobs:
detect-and-deploy:
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
deployments: write
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Detect Project Type
id: detect
run: |
# Detect what kind of project this is
if [ -f "railway.toml" ] || [ -f "railway.json" ]; then
echo "platform=railway" >> $GITHUB_OUTPUT
elif [ -f "wrangler.toml" ] || [ -f "wrangler.json" ]; then
echo "platform=cloudflare-workers" >> $GITHUB_OUTPUT
elif [ -f "next.config.js" ] || [ -f "next.config.mjs" ] || [ -f "next.config.ts" ]; then
echo "platform=cloudflare-pages" >> $GITHUB_OUTPUT
echo "framework=next" >> $GITHUB_OUTPUT
elif [ -f "vite.config.ts" ] || [ -f "vite.config.js" ]; then
echo "platform=cloudflare-pages" >> $GITHUB_OUTPUT
echo "framework=vite" >> $GITHUB_OUTPUT
elif [ -f "Dockerfile" ]; then
echo "platform=railway" >> $GITHUB_OUTPUT
elif [ -f "requirements.txt" ] || [ -f "pyproject.toml" ]; then
echo "platform=railway" >> $GITHUB_OUTPUT
echo "framework=python" >> $GITHUB_OUTPUT
elif [ -f "package.json" ]; then
echo "platform=cloudflare-pages" >> $GITHUB_OUTPUT
echo "framework=static" >> $GITHUB_OUTPUT
else
echo "platform=railway" >> $GITHUB_OUTPUT
fi
# Get repo name for service naming
echo "repo_name=${GITHUB_REPOSITORY#*/}" >> $GITHUB_OUTPUT
# Set environment based on event
if [ "${{ github.event_name }}" == "pull_request" ]; then
echo "environment=preview" >> $GITHUB_OUTPUT
echo "pr_number=${{ github.event.pull_request.number }}" >> $GITHUB_OUTPUT
else
echo "environment=production" >> $GITHUB_OUTPUT
fi
- name: Install Dependencies
if: steps.detect.outputs.platform == 'cloudflare-pages' || steps.detect.outputs.platform == 'cloudflare-workers'
run: |
if [ -f "package.json" ]; then
npm ci || npm install
fi
- name: Build (if needed)
if: steps.detect.outputs.platform == 'cloudflare-pages'
run: |
if [ -f "package.json" ]; then
npm run build || true
fi
# ============ RAILWAY DEPLOYMENT ============
- name: Install Railway CLI
if: steps.detect.outputs.platform == 'railway' && env.RAILWAY_TOKEN != ''
run: npm install -g @railway/cli
- name: Deploy to Railway
if: steps.detect.outputs.platform == 'railway' && env.RAILWAY_TOKEN != ''
id: railway
run: |
railway link --environment ${{ steps.detect.outputs.environment }} 2>/dev/null || true
DEPLOY_URL=$(railway up --detach 2>&1 | grep -oP 'https://[^\s]+' | head -1 || echo "")
if [ -n "$DEPLOY_URL" ]; then
echo "url=$DEPLOY_URL" >> $GITHUB_OUTPUT
echo "success=true" >> $GITHUB_OUTPUT
else
DEPLOY_URL=$(railway status --json 2>/dev/null | jq -r '.deployments[0].url // empty' || echo "")
echo "url=$DEPLOY_URL" >> $GITHUB_OUTPUT
echo "success=true" >> $GITHUB_OUTPUT
fi
# ============ CLOUDFLARE PAGES DEPLOYMENT ============
- name: Deploy to Cloudflare Pages
if: steps.detect.outputs.platform == 'cloudflare-pages' && env.CLOUDFLARE_API_TOKEN != ''
id: cloudflare-pages
run: |
npm install -g wrangler
if [ -d "dist" ]; then OUTPUT_DIR="dist"
elif [ -d "build" ]; then OUTPUT_DIR="build"
elif [ -d "out" ]; then OUTPUT_DIR="out"
elif [ -d ".next" ]; then OUTPUT_DIR=".next"
elif [ -d "public" ]; then OUTPUT_DIR="public"
else OUTPUT_DIR="."; fi
PROJECT_NAME="${{ steps.detect.outputs.repo_name }}"
wrangler pages project create "$PROJECT_NAME" --production-branch main 2>/dev/null || true
if [ "${{ steps.detect.outputs.environment }}" == "preview" ]; then
RESULT=$(wrangler pages deploy "$OUTPUT_DIR" --project-name="$PROJECT_NAME" --branch="pr-${{ steps.detect.outputs.pr_number }}" 2>&1)
else
RESULT=$(wrangler pages deploy "$OUTPUT_DIR" --project-name="$PROJECT_NAME" --branch=main 2>&1)
fi
DEPLOY_URL=$(echo "$RESULT" | grep -oP 'https://[^\s]+\.pages\.dev' | head -1 || echo "")
echo "url=$DEPLOY_URL" >> $GITHUB_OUTPUT
echo "success=true" >> $GITHUB_OUTPUT
# ============ CLOUDFLARE WORKERS DEPLOYMENT ============
- name: Deploy to Cloudflare Workers
if: steps.detect.outputs.platform == 'cloudflare-workers' && env.CLOUDFLARE_API_TOKEN != ''
id: cloudflare-workers
run: |
npm install -g wrangler
if [ "${{ steps.detect.outputs.environment }}" == "preview" ]; then
RESULT=$(wrangler deploy --env preview 2>&1 || wrangler deploy 2>&1)
else
RESULT=$(wrangler deploy 2>&1)
fi
DEPLOY_URL=$(echo "$RESULT" | grep -oP 'https://[^\s]+\.workers\.dev' | head -1 || echo "")
echo "url=$DEPLOY_URL" >> $GITHUB_OUTPUT
echo "success=true" >> $GITHUB_OUTPUT
# ============ COMMENT ON PR ============
- name: Comment Deployment URL on PR
if: github.event_name == 'pull_request' && (steps.railway.outputs.success == 'true' || steps.cloudflare-pages.outputs.success == 'true' || steps.cloudflare-workers.outputs.success == 'true')
uses: actions/github-script@v7
with:
script: |
const railwayUrl = '${{ steps.railway.outputs.url }}';
const pagesUrl = '${{ steps.cloudflare-pages.outputs.url }}';
const workersUrl = '${{ steps.cloudflare-workers.outputs.url }}';
const platform = '${{ steps.detect.outputs.platform }}';
const deployUrl = railwayUrl || pagesUrl || workersUrl || 'Deployment in progress...';
const platformEmoji = { 'railway': '🚂', 'cloudflare-pages': '📄', 'cloudflare-workers': '⚡' };
const body = `## ${platformEmoji[platform] || '🚀'} Preview Deployment Ready!
| Platform | URL |
|----------|-----|
| **${platform}** | ${deployUrl ? `[${deployUrl}](${deployUrl})` : 'Deploying...'} |
---
🤖 *Auto-deployed by BlackRoad OS*`;
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(c => c.body.includes('Preview Deployment Ready'));
if (botComment) {
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: botComment.id,
body: body
});
} else {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: body
});
}