Skip to content

Preview by @katmayb #2012

Preview by @katmayb

Preview by @katmayb #2012

---
name: Create Preview Branch
run-name: Preview by @${{ github.actor }}
on:
pull_request:
types: [opened, synchronize, reopened]
workflow_dispatch:
concurrency:
group: create-preview-${{ github.ref_name }}
cancel-in-progress: true
# Least-privileged defaults. We'll elevate at the job level only where needed.
permissions:
contents: read
actions: read
jobs:
create-preview:
# This job needs to push a branch, so contents: write here only.
permissions:
contents: write
runs-on: ubuntu-latest
# Skip for PRs from forks - they don't have write access
if: github.event.pull_request.head.repo.full_name == github.repository || github.event_name == 'workflow_dispatch'
# Expose the generated preview branch name for the next job
outputs:
preview_branch: ${{ steps.branch-name.outputs.branch_name }}
env:
SOURCE_BRANCH: ${{ github.event_name == 'pull_request' && github.head_ref || github.ref_name }}
GITHUB_SHA: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }}
steps:
- name: Validate and sanitize branch context
id: validate
run: |
set -euo pipefail
echo "[INFO] Validating current branch context"
echo "[INFO] Current ref: ${{ github.ref }}"
echo "[INFO] Branch name: $SOURCE_BRANCH"
# Validate source branch contains only safe characters and isn't too long
if [[ ! "$SOURCE_BRANCH" =~ ^[a-zA-Z0-9/_-]+$ ]]; then
echo "[ERROR] Branch name contains invalid characters. Only alphanumeric, slash, underscore, and hyphen are allowed."
exit 1
fi
if [[ ${#SOURCE_BRANCH} -gt 100 ]]; then
echo "[ERROR] Branch name too long (max 100)."
exit 1
fi
# Sanitize for logging (first 20 chars max)
SAFE_LOG_BRANCH=$(echo "$SOURCE_BRANCH" | cut -c1-20)
echo "safe_branch_log=$SAFE_LOG_BRANCH" >> $GITHUB_OUTPUT
echo "[SUCCESS] Branch validation passed for: $SAFE_LOG_BRANCH"
- name: Checkout current branch
uses: actions/checkout@v5
with:
ref: ${{ github.event_name == 'pull_request' && github.head_ref || github.ref_name }}
fetch-depth: 0
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: '3.12'
- name: Install uv
uses: astral-sh/setup-uv@v6
- name: Install dependencies
run: make install
- name: Build documentation
run: make build
- name: Generate secure preview branch name
id: branch-name
run: |
set -euo pipefail
echo "[INFO] Generating collision-resistant preview branch name"
safe_prefix=$(echo "$SOURCE_BRANCH" | tr -cd '[:alnum:]' | cut -c1-6)
timestamp=$(date +%s)
short_sha="${GITHUB_SHA:0:7}"
PREVIEW_BRANCH="preview-${safe_prefix}-${timestamp}-${short_sha}"
echo "branch_name=$PREVIEW_BRANCH" >> $GITHUB_OUTPUT
echo "[INFO] Preview branch will be: $PREVIEW_BRANCH"
- name: Configure Git
run: |
git config --global user.name "github-actions[bot]"
git config --global user.email "github-actions[bot]@users.noreply.github.com"
- name: Check if preview branch already exists
run: |
set -euo pipefail
PREVIEW_BRANCH="${{ steps.branch-name.outputs.branch_name }}"
echo "[INFO] Checking if preview branch already exists: $PREVIEW_BRANCH"
# Check if the branch exists remotely
if git ls-remote --exit-code --heads origin "$PREVIEW_BRANCH" >/dev/null 2>&1; then
echo "[ERROR] Preview branch $PREVIEW_BRANCH already exists. This should be extremely rare."
echo "[INFO] Please retry the workflow to generate a new branch name."
exit 1
fi
echo "[SUCCESS] Preview branch name is unique"
- name: Create and push preview branch
run: |
set -euo pipefail
PREVIEW_BRANCH="${{ steps.branch-name.outputs.branch_name }}"
SAFE_BRANCH_LOG="${{ steps.validate.outputs.safe_branch_log }}"
echo "[INFO] Creating preview branch: $PREVIEW_BRANCH"
# Create new branch from current state
git checkout -b "$PREVIEW_BRANCH"
# Add build artifacts (force add since build/ is likely in .gitignore)
echo "[INFO] Adding build artifacts to preview branch (forced)"
git add -f build/
# Check if there are changes to commit
if git diff --cached --quiet; then
echo "[WARN] No build artifacts to commit"
else
echo "[INFO] Committing build artifacts"
git commit -m "Add build artifacts for preview deployment
Source branch: $SAFE_BRANCH_LOG
Generated from commit: $GITHUB_SHA
Timestamp: $(date -u +"%Y-%m-%d %H:%M:%S UTC")
This branch contains the built documentation for preview deployment.
Do not merge this branch to main."
fi
# Push the preview branch
echo "[INFO] Pushing preview branch to origin"
git push origin "$PREVIEW_BRANCH"
echo "[SUCCESS] Successfully pushed preview branch"
- name: Save preview branch info (log)
run: |
PREVIEW_BRANCH="${{ steps.branch-name.outputs.branch_name }}"
SAFE_BRANCH_LOG="${{ steps.validate.outputs.safe_branch_log }}"
echo "[SUCCESS] Preview branch created: $PREVIEW_BRANCH"
echo "[INFO] Branch name: $PREVIEW_BRANCH"
echo "[INFO] Source branch: $SAFE_BRANCH_LOG"
echo "[INFO] Source commit: $GITHUB_SHA"
echo "[INFO] Created at: $(date -u +"%Y-%m-%d %H:%M:%S UTC")"
echo ""
echo "[INFO] The preview branch is now ready for Mintlify deployment."
echo ""
echo "[INFO] πŸ”— Branch URL: https://github.com/${{ github.repository }}/tree/$PREVIEW_BRANCH"
comment-on-pr:
# Only this job gets permission to write PR comments.
permissions:
pull-requests: write
runs-on: ubuntu-latest
needs: create-preview
if: github.event_name == 'pull_request' && needs.create-preview.result == 'success'
steps:
- name: Comment on PR
uses: actions/github-script@v8
with:
script: |
const preview = `${{ needs.create-preview.outputs.preview_branch }}`;
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: `Preview ID generated: ${preview}`
});