Preview by @mdrxy #2010
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--- | |
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}` | |
}); |