Skip to content

Deploy

Deploy #80

Workflow file for this run

name: Deploy
on:
workflow_run:
workflows: ["Build"]
types:
- completed
workflow_dispatch:
inputs:
artifact_url:
description: 'Cloudflare build artifact URL (.tar.gz, e.g., build-v1.0.0-cloudflare.tar.gz)'
required: true
type: string
environment:
description: 'Deployment environment'
required: true
default: 'production'
type: choice
options:
- production
- preview
permissions:
contents: read
pull-requests: write
actions: read
jobs:
prepare:
runs-on: ubuntu-latest
if: ${{ github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success' }}
outputs:
is_production: ${{ steps.meta.outputs.is_production }}
pr_number: ${{ steps.meta.outputs.pr_number }}
steps:
- name: Download build artifacts from workflow
if: ${{ github.event_name == 'workflow_run' }}
uses: actions/download-artifact@v4
with:
name: build-${{ github.event.workflow_run.id }}
path: ./artifacts
run-id: ${{ github.event.workflow_run.id }}
github-token: ${{ secrets.GITHUB_TOKEN }}
- name: Download artifacts from URL
if: ${{ github.event_name == 'workflow_dispatch' }}
run: |
URL="${{ github.event.inputs.artifact_url }}"
echo "Downloading from: $URL"
mkdir -p ./artifacts
if [[ "$URL" == *.zip ]]; then
curl -L "$URL" -o ./artifacts/build.zip
unzip -q ./artifacts/build.zip -d ./artifacts
rm ./artifacts/build.zip
else
curl -L "$URL" -o ./artifacts/build.tar.gz
tar -xzf ./artifacts/build.tar.gz -C ./artifacts
rm ./artifacts/build.tar.gz
fi
- name: Set deployment type
id: meta
run: |
if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
# Manual deployment
if [ "${{ github.event.inputs.environment }}" == "production" ]; then
echo "is_production=true" >> $GITHUB_OUTPUT
else
echo "is_production=false" >> $GITHUB_OUTPUT
fi
echo "pr_number=0" >> $GITHUB_OUTPUT
else
# Auto deployment from workflow_run - check ref
REF=$(cat ./artifacts/build-meta/ref 2>/dev/null || echo "unknown")
if [[ "$REF" == "refs/heads/main" || "$REF" == "refs/heads/master" ]]; then
echo "is_production=true" >> $GITHUB_OUTPUT
else
echo "is_production=false" >> $GITHUB_OUTPUT
fi
# Read PR number from build-meta
PR_NUMBER=$(cat ./artifacts/build-meta/pr_number 2>/dev/null || echo "0")
echo "pr_number=${PR_NUMBER}" >> $GITHUB_OUTPUT
fi
- name: Upload artifacts for deploy job
uses: actions/upload-artifact@v4
with:
name: deploy-artifacts-${{ github.run_id }}
path: ./artifacts
retention-days: 1
deploy:
needs: prepare
runs-on: ubuntu-latest
environment:
name: ${{ needs.prepare.outputs.is_production == 'true' && 'production' || 'preview' }}
url: ${{ steps.deploy.outputs.url }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Download build artifacts
uses: actions/download-artifact@v4
with:
name: deploy-artifacts-${{ github.run_id }}
path: ./artifacts
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 22
- name: Set up Bun
uses: oven-sh/setup-bun@v1
with:
bun-version: 1.3.6
- name: Install dependencies
run: bun install
- name: Restore build artifacts
run: |
cp -r ./artifacts/dist ./dist
echo "Checking build artifacts..."
ls -la ./dist/client/ || echo "No client dist found"
ls -la ./dist/server/ || echo "No server dist found"
- name: Determine deployment config
id: config
env:
# Repository-level variables (available before environment is set)
REPO_NAME: ${{ vars.NAME }}
REPO_DESCRIPTION: ${{ vars.DESCRIPTION }}
REPO_AVATAR: ${{ vars.AVATAR }}
REPO_PAGE_SIZE: ${{ vars.PAGE_SIZE }}
REPO_RSS_ENABLE: ${{ vars.RSS_ENABLE }}
REPO_WORKER_NAME: ${{ vars.WORKER_NAME }}
REPO_DB_NAME: ${{ vars.DB_NAME }}
run: |
PR_NUMBER="${{ needs.prepare.outputs.pr_number }}"
if [[ "${{ needs.prepare.outputs.is_production }}" == "true" ]]; then
echo "worker_name=${REPO_WORKER_NAME:-rin-server}" >> $GITHUB_OUTPUT
echo "db_name=${REPO_DB_NAME:-rin}" >> $GITHUB_OUTPUT
echo "name=${REPO_NAME:-Rin}" >> $GITHUB_OUTPUT
elif [[ "$PR_NUMBER" != "0" ]]; then
# PR Preview uses -pr-<number> suffix
echo "worker_name=${REPO_WORKER_NAME:-rin-server}-pr-${PR_NUMBER}" >> $GITHUB_OUTPUT
echo "db_name=${REPO_DB_NAME:-rin-preview}" >> $GITHUB_OUTPUT
echo "name=${REPO_NAME:-Rin} (PR #${PR_NUMBER})" >> $GITHUB_OUTPUT
else
echo "worker_name=${REPO_WORKER_NAME:-rin-server}-preview" >> $GITHUB_OUTPUT
echo "db_name=${REPO_DB_NAME:-rin-preview}" >> $GITHUB_OUTPUT
echo "name=${REPO_NAME:-Rin} (Preview)" >> $GITHUB_OUTPUT
fi
# Output repository-level vars for use in deploy step
echo "description=${REPO_DESCRIPTION}" >> $GITHUB_OUTPUT
echo "avatar=${REPO_AVATAR}" >> $GITHUB_OUTPUT
echo "page_size=${REPO_PAGE_SIZE}" >> $GITHUB_OUTPUT
echo "rss_enable=${REPO_RSS_ENABLE}" >> $GITHUB_OUTPUT
- name: Deploy to Cloudflare
id: deploy
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
WORKER_NAME: ${{ steps.config.outputs.worker_name }}
DB_NAME: ${{ steps.config.outputs.db_name }}
NAME: ${{ steps.config.outputs.name }}
DESCRIPTION: ${{ steps.config.outputs.description || 'A lightweight personal blogging system' }}
AVATAR: ${{ steps.config.outputs.avatar || '' }}
PAGE_SIZE: ${{ steps.config.outputs.page_size || '5' }}
RSS_ENABLE: ${{ steps.config.outputs.rss_enable || 'false' }}
S3_CACHE_FOLDER: ${{ vars.S3_CACHE_FOLDER || 'cache/' }}
S3_FOLDER: ${{ vars.S3_FOLDER || 'images/' }}
S3_REGION: ${{ vars.S3_REGION || 'auto' }}
S3_FORCE_PATH_STYLE: ${{ vars.S3_FORCE_PATH_STYLE || 'false' }}
R2_BUCKET_NAME: ${{ vars.R2_BUCKET_NAME || '' }}
S3_ENDPOINT: ${{ vars.S3_ENDPOINT || '' }}
S3_ACCESS_HOST: ${{ vars.S3_ACCESS_HOST || '' }}
S3_BUCKET: ${{ vars.S3_BUCKET || '' }}
S3_ACCESS_KEY_ID: ${{ secrets.S3_ACCESS_KEY_ID || '' }}
S3_SECRET_ACCESS_KEY: ${{ secrets.S3_SECRET_ACCESS_KEY || '' }}
RIN_GITHUB_CLIENT_ID: ${{ secrets.RIN_GITHUB_CLIENT_ID || '' }}
RIN_GITHUB_CLIENT_SECRET: ${{ secrets.RIN_GITHUB_CLIENT_SECRET || '' }}
ADMIN_USERNAME: ${{ secrets.ADMIN_USERNAME }}
ADMIN_PASSWORD: ${{ secrets.ADMIN_PASSWORD }}
JWT_SECRET: ${{ secrets.JWT_SECRET || '' }}
WEBHOOK_URL: ${{ vars.WEBHOOK_URL || '' }}
RSS_TITLE: ${{ vars.RSS_TITLE || '' }}
RSS_DESCRIPTION: ${{ vars.RSS_DESCRIPTION || '' }}
CACHE_STORAGE_MODE: ${{ vars.CACHE_STORAGE_MODE || 's3' }}
run: |
bun run deploy | tee deploy_output.log
URL=$(grep -oP 'App URL: \Khttps://[^\s]+' deploy_output.log || echo "https://${WORKER_NAME}.${{ secrets.CLOUDFLARE_ACCOUNT_ID }}.workers.dev")
echo "url=${URL}" >> $GITHUB_OUTPUT
- name: Comment on PR
if: needs.prepare.outputs.pr_number != '0'
uses: actions/github-script@v7
with:
script: |
const url = '${{ steps.deploy.outputs.url }}';
const prNumber = parseInt('${{ needs.prepare.outputs.pr_number }}');
const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber
});
const botComment = comments.find(comment =>
comment.user.type === 'Bot' &&
comment.body.includes('🚀 **Preview deployed!**')
);
const body = `🚀 **Preview deployed!**\n\n🔗 ${url}`;
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: prNumber,
body: body
});
}