Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 0 additions & 61 deletions .github/workflows/builds-docs.yml

This file was deleted.

61 changes: 61 additions & 0 deletions .github/workflows/docs-cleanup-staging-pr.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
name: "Docs - PR Staging - Cleanup"

on:
pull_request:
branches: [ main ]
types: [ closed ]

# Default to no permissions — each job declares only what it needs.
permissions: {}

# Ensure documentation workflows run sequentially
concurrency:
group: "docs-deployment"
cancel-in-progress: false

jobs:
cleanup:
runs-on: ubuntu-latest
permissions:
contents: write # push to gh-pages
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Remove staging directory from gh-pages
env:
PR_NUMBER: ${{ github.event.number }}
run: |
# Validate PR_NUMBER is a positive integer before using in paths
if ! [[ "$PR_NUMBER" =~ ^[1-9][0-9]*$ ]]; then
echo "Invalid PR number: $PR_NUMBER"
exit 1
fi

# Switch to gh-pages branch; exit cleanly if it doesn't exist yet
if ! git fetch origin gh-pages:gh-pages 2>/dev/null; then
echo "gh-pages branch does not exist, nothing to clean up"
exit 0
fi
if ! git checkout gh-pages 2>/dev/null; then
echo "Failed to checkout gh-pages, nothing to clean up"
exit 0
fi

if [ -d "staging/$PR_NUMBER" ]; then
rm -rf staging/$PR_NUMBER
git config --local user.email "action@github.com"
git config --local user.name "GitHub Action"
git add -A
if ! git diff --cached --quiet; then
git commit -m "Remove staging docs for PR #$PR_NUMBER"
git push origin gh-pages
echo "Removed staging directory for PR #$PR_NUMBER"
else
echo "No changes to commit for PR #$PR_NUMBER"
fi
else
echo "No staging directory found for PR #$PR_NUMBER"
fi
150 changes: 150 additions & 0 deletions .github/workflows/docs-deploy-fork-pr.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
name: "Docs - Fork PR - Deploy"

# This workflow runs in a TRUSTED context (base repo token with write access).
# It is triggered AFTER "Docs - Deploy" completes for a fork PR.
# The "Docs - Deploy" build job uploads the site artifact; this workflow
# downloads it and deploys to gh-pages/staging/{pr}/, then comments on the PR.
#
# Security: no untrusted code is executed here — we only deploy a pre-built
# artifact produced by our own workflow. The workflow_run trigger always runs
# with the base repository's token, regardless of where the PR originated.

on:
workflow_run:
workflows: [ "Docs - Deploy" ]
types: [ completed ]

# Default to no permissions — each job declares only what it needs.
permissions: {}

# Ensure documentation workflows run sequentially
concurrency:
group: "docs-deployment"
cancel-in-progress: false

jobs:
deploy-fork-pr-staging:
# Only run for successful fork PR builds
if: |
github.event.workflow_run.conclusion == 'success' &&
github.event.workflow_run.event == 'pull_request' &&
github.event.workflow_run.head_repository.full_name != github.repository
runs-on: ubuntu-latest
permissions:
contents: write # push to gh-pages
pull-requests: write # comment on PR
steps:
- name: Find staging artifact for this PR
id: artifact
uses: actions/github-script@v7
env:
WORKFLOW_RUN_ID: ${{ github.event.workflow_run.id }}
with:
script: |
const runId = parseInt(process.env.WORKFLOW_RUN_ID, 10);
const artifacts = await github.rest.actions.listWorkflowRunArtifacts({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: runId
});
const staging = artifacts.data.artifacts.find(a => a.name.startsWith('staging-site-'));
if (!staging) {
core.setFailed('No staging artifact found for this workflow run');
return;
}
// Extract and validate PR number (must be a positive integer)
const prNumberStr = staging.name.replace('staging-site-', '');
const prNumber = parseInt(prNumberStr, 10);
if (!prNumber || prNumber <= 0 || String(prNumber) !== prNumberStr) {
core.setFailed(`Invalid PR number extracted from artifact name: ${staging.name}`);
return;
}
core.setOutput('artifact_name', staging.name);
core.setOutput('pr_number', String(prNumber));

- name: Download staging artifact
uses: actions/download-artifact@v4
with:
run-id: ${{ github.event.workflow_run.id }}
github-token: ${{ secrets.GITHUB_TOKEN }}
name: ${{ steps.artifact.outputs.artifact_name }}
path: /tmp/site-temp

- name: Checkout gh-pages branch
uses: actions/checkout@v4
with:
ref: gh-pages
fetch-depth: 0

- name: Deploy staging content
env:
PR_NUMBER: ${{ steps.artifact.outputs.pr_number }}
run: |
# Validate PR_NUMBER is a positive integer before using in paths
if ! [[ "$PR_NUMBER" =~ ^[1-9][0-9]*$ ]]; then
echo "Invalid PR number: $PR_NUMBER"
exit 1
fi
mkdir -p staging/$PR_NUMBER
rm -rf staging/$PR_NUMBER/*
cp -r /tmp/site-temp/. staging/$PR_NUMBER/
rm -rf /tmp/site-temp
git config --local user.email "action@github.com"
git config --local user.name "GitHub Action"
git add staging/$PR_NUMBER
if ! git diff --cached --quiet; then
git commit -m "Deploy staging docs for PR #$PR_NUMBER"
git push origin gh-pages
else
echo "No changes to commit"
fi

- name: Comment on PR
uses: actions/github-script@v7
env:
PR_NUMBER: ${{ steps.artifact.outputs.pr_number }}
with:
script: |
const prNumber = parseInt(process.env.PR_NUMBER, 10);
if (!prNumber || prNumber <= 0) {
core.setFailed('Invalid PR number');
return;
}
const stagingUrl = `https://mono.github.io/SkiaSharp.Extended/staging/${prNumber}/`;
const sampleUrl = `https://mono.github.io/SkiaSharp.Extended/staging/${prNumber}/sample/`;

// Only comment once; check for an existing bot comment
const comments = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber
});
const botComment = comments.data.find(c =>
c.user.type === 'Bot' &&
c.body.includes('Documentation Preview')
);
if (botComment) {
console.log('Bot comment already exists, skipping.');
return;
}

const commentBody = `📖 **Documentation Preview**

The documentation for this PR has been deployed and is available at:

🔗 **[View Staging Documentation](${stagingUrl})**

🔗 **[View Staging Blazor Sample](${sampleUrl})**

This preview will be updated automatically when you push new commits to this PR.

---
*This comment is automatically updated by the documentation staging workflow.*`;

await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
body: commentBody
});

Loading
Loading