Skip to content

Google-services error fix. #128

Google-services error fix.

Google-services error fix. #128

name: 🚀 Deploy Static Next.js to GitHub Pages
on:
push:
branches: ['main'] # Only trigger push on main; PR branches use pull_request event
pull_request:
types: [opened, synchronize, reopened]
workflow_dispatch: # Allows manual triggering
permissions:
contents: write
pull-requests: write
concurrency:
group: 'pages-${{ github.head_ref || github.ref_name }}'
cancel-in-progress: true
jobs:
build-and-deploy:
name: 🏗 Build & Deploy
runs-on: ubuntu-latest
steps:
- name: 🔍 Checkout repository
uses: actions/checkout@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: 🔧 Set deployment variables
id: vars
run: |
REPO_NAME="${{ github.event.repository.name }}"
# Custom domain means no repo name prefix in the URL path.
# Set CUSTOM_DOMAIN to your domain, or leave empty to use github.io/<repo> URLs.
CUSTOM_DOMAIN="codebuilder.org"
# Get the branch name (works for both push and PR events)
if [ "${{ github.event_name }}" = "pull_request" ]; then
BRANCH="${{ github.head_ref }}"
else
BRANCH="${{ github.ref_name }}"
fi
# Sanitize branch name for use in URL paths
SAFE_BRANCH=$(echo "$BRANCH" | sed 's/[^a-zA-Z0-9._-]/-/g')
if [ -n "$CUSTOM_DOMAIN" ]; then
BASE_URL="https://${CUSTOM_DOMAIN}"
else
BASE_URL="https://${{ github.repository_owner }}.github.io/${REPO_NAME}"
fi
if [ "$BRANCH" = "main" ]; then
if [ -n "$CUSTOM_DOMAIN" ]; then
echo "base_path=" >> $GITHUB_OUTPUT
else
echo "base_path=/${REPO_NAME}" >> $GITHUB_OUTPUT
fi
echo "dest_dir=" >> $GITHUB_OUTPUT
# keep_files must be true so preview/ directories are preserved
echo "keep_files=true" >> $GITHUB_OUTPUT
echo "is_main=true" >> $GITHUB_OUTPUT
echo "preview_url=${BASE_URL}/" >> $GITHUB_OUTPUT
else
echo "base_path=/preview/${SAFE_BRANCH}" >> $GITHUB_OUTPUT
echo "dest_dir=preview/${SAFE_BRANCH}" >> $GITHUB_OUTPUT
echo "keep_files=true" >> $GITHUB_OUTPUT
echo "preview_url=${BASE_URL}/preview/${SAFE_BRANCH}/" >> $GITHUB_OUTPUT
fi
echo "branch=$BRANCH" >> $GITHUB_OUTPUT
echo "safe_branch=$SAFE_BRANCH" >> $GITHUB_OUTPUT
- name: 🔎 Detect package manager
id: detect-pm
run: |
if [ -f "pnpm-lock.yaml" ]; then
echo "manager=pnpm" >> $GITHUB_OUTPUT
echo "command=install" >> $GITHUB_OUTPUT
echo "runner=pnpm exec" >> $GITHUB_OUTPUT
else
echo "manager=npm" >> $GITHUB_OUTPUT
echo "command=ci" >> $GITHUB_OUTPUT
echo "runner=npx --no-install" >> $GITHUB_OUTPUT
fi
- name: 📦 Install pnpm
if: steps.detect-pm.outputs.manager == 'pnpm'
run: npm install -g pnpm
- name: ⚙️ Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '24'
cache: ${{ steps.detect-pm.outputs.manager }}
- name: 📦 Cache Next.js build
uses: actions/cache@v4
with:
path: |
${{ github.workspace }}/.next/cache
key: ${{ runner.os }}-nextjs-${{ hashFiles('**/pnpm-lock.yaml') }}-${{ hashFiles('**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx') }}
restore-keys: |
${{ runner.os }}-nextjs-${{ hashFiles('**/pnpm-lock.yaml') }}-
- name: 🚫 Ephemerally delete server/api files
env:
STATIC_BUILD_REMOVE_PATHS: ${{ vars.STATIC_BUILD_REMOVE_PATHS }}
run: |
DEFAULT_PATHS="'src/app/blog/[slug]' 'src/app/invoice/[id]' src/app/api src/server src/proxy.ts 'src/app/jobs/[id]' 'src/app/[...not-found]' prisma.config.ts 'src/app/jobs/details/[id]/page.tsx'"
PATHS="${STATIC_BUILD_REMOVE_PATHS:-$DEFAULT_PATHS}"
echo "Deleting server/api files for static build..."
echo "Paths: $PATHS"
eval rm -rf $PATHS
- name: 📥 Install dependencies
run: ${{ steps.detect-pm.outputs.manager }} ${{ steps.detect-pm.outputs.command }}
- name: 🏗 Generate Static Build
env:
NEXT_OUTPUT_MODE: export
GITHUB_PAGES: 1
NEXT_BASE_PATH: ${{ steps.vars.outputs.base_path }}
run: |
echo "Building static files for GitHub Pages..."
echo "Base path: $NEXT_BASE_PATH"
echo "Preview URL: ${{ steps.vars.outputs.preview_url }}"
pnpm build
touch out/.nojekyll
- name: 🧹 Clean stale root files from gh-pages (main only)
if: steps.vars.outputs.is_main == 'true'
run: |
# Checkout the gh-pages branch into a temp directory
git fetch origin gh-pages || true
mkdir -p /tmp/gh-pages-current
cd /tmp/gh-pages-current
git init
git remote add origin https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git
git fetch origin gh-pages --depth=1 || exit 0
git checkout gh-pages || exit 0
# Delete everything EXCEPT the preview/ directory and CNAME
find . -maxdepth 1 ! -name '.' ! -name '.git' ! -name 'preview' ! -name 'CNAME' -exec rm -rf {} +
git add -A
git diff --cached --quiet || git -c user.name="github-actions" -c user.email="[email protected]" commit -m "clean stale root files before main deploy"
git push origin gh-pages || true
- name: 🚀 Deploy to GitHub Pages
uses: peaceiris/actions-gh-pages@v4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./out
destination_dir: ${{ steps.vars.outputs.dest_dir }}
keep_files: ${{ steps.vars.outputs.keep_files }}
cname: codebuilder.org
- name: 💬 Comment preview URL on PR
if: github.event_name == 'pull_request'
uses: actions/github-script@v7
with:
script: |
const url = '${{ steps.vars.outputs.preview_url }}';
const sha = context.sha.substring(0, 7);
const body = `🚀 **Preview deployment ready!**\n\n🌐 **Preview URL:** [${url}](${url})\n<sub>Deployed from commit \`${sha}\`</sub>`;
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,
});
} else {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body,
});
}
- name: Update PR description with preview URL
uses: actions/github-script@v7
with:
script: |
const owner = context.repo.owner;
const repo = context.repo.repo;
const branch = '${{ steps.vars.outputs.branch }}';
const previewUrl = '${{ steps.vars.outputs.preview_url }}';
const sha = context.sha.substring(0, 7);
// Find open PR for this branch
const { data: prs } = await github.rest.pulls.list({
owner, repo, head: `${owner}:${branch}`, state: 'open',
});
if (prs.length === 0) {
console.log(`No open PR found for branch ${branch}, skipping.`);
return;
}
const pr = prs[0];
const body = pr.body || '';
const marker = {
start: '<!-- GH-PAGES-PREVIEW:START -->',
end: '<!-- GH-PAGES-PREVIEW:END -->',
};
const section = [
marker.start,
`🌐 **Preview:** [${previewUrl}](${previewUrl})`,
`<sub>Deployed from \`${sha}\`</sub>`,
marker.end,
].join('\n');
let updated;
if (body.includes(marker.start)) {
const re = new RegExp(`${marker.start}[\\s\\S]*?${marker.end}`);
updated = body.replace(re, section);
} else {
// Prepend to top of PR description
updated = section + '\n\n' + body;
}
if (updated !== body) {
await github.rest.pulls.update({
owner, repo, pull_number: pr.number, body: updated,
});
console.log(`PR #${pr.number} description updated with preview URL: ${previewUrl}`);
}