Skip to content
Draft
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
1b996ae
feat: add netlify-preview job to sphinxbuild workflow
Copilot Apr 17, 2026
1d35c34
feat: deploy full merged documentation to Netlify preview
Copilot Apr 17, 2026
aec4ec0
Initial plan
Copilot Apr 17, 2026
0bdd6b8
refactor: move Netlify preview into deploy job, avoiding 2GB cache ro…
Copilot Apr 17, 2026
b3fa788
refactor: use netlify-cli directly, preview current branch only with …
Copilot Apr 17, 2026
38ffccd
Merge pull request #14406 from nextcloud/copilot/sub-pr-14401
skjnldsv Apr 17, 2026
937510e
refactor: merge netlify preview into deploy job, make it optional
Copilot Apr 17, 2026
b5c6f75
Merge branch 'master' into copilot/add-netlify-preview-job
skjnldsv Apr 17, 2026
79c0629
feat: add index.html generation with user_manual/en redirect for Netl…
Copilot Apr 17, 2026
c61e9a6
fix: remove redundant user_manual/index.html generation — already exi…
Copilot Apr 17, 2026
31b64a1
chore: merge master into branch and add Netlify preview to deploy job
Copilot May 1, 2026
6f4a7b2
fix: list only PR manuals in preview index.html, not all gh-pages ver…
Copilot May 1, 2026
5182ec1
feat: pin Netlify preview comment on PR after create/update
Copilot May 1, 2026
154bdd4
fix: use github.request() to pin comment instead of missing pinCommen…
Copilot May 1, 2026
f3360db
fix: only copy manuals (remove PDF moving/copying) in deploy workflow
Copilot May 1, 2026
3ee5a8c
fix: remove unsupported pinned comment PATCH call that caused HttpError
Copilot May 1, 2026
31d3860
restore: pin comment using correct PUT /issues/comments/{id}/pin endp…
Copilot May 1, 2026
71c6a1b
remove unsupported pin call (PR context + insufficient token permissi…
Copilot May 1, 2026
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
145 changes: 115 additions & 30 deletions .github/workflows/sphinxbuild.yml
Original file line number Diff line number Diff line change
Expand Up @@ -337,16 +337,6 @@ jobs:
fi
done

# Move PDF files to the root of the branch folder for cleaner structure
echo "Looking for PDF files to move..."
find "stage/${branch}/" -maxdepth 2 -name "*.pdf" -type f
for pdf in "stage/${branch}"/*/*.pdf; do
if [ -f "$pdf" ]; then
echo "Moving PDF: $pdf"
mv "$pdf" "stage/${branch}/"
fi
done

# Clean up empty directories
find stage -type d -empty -delete

Expand Down Expand Up @@ -415,18 +405,20 @@ jobs:
# ============================================================================
# DEPLOY
# ============================================================================
# This job is responsible for:
# 1. Downloading the staged artifacts from stage-and-check
# 2. Applying them to the gh-pages branch
# 3. Creating a pull request for the deployment
# This job handles two cases based on the event type:
#
# This job ONLY runs on pushes (not on pull requests), since we only want
# to deploy when code is merged to master or a stable branch.
# push → Apply staged artifacts to gh-pages and open a PR for the update.
#
# pull_request → Check out gh-pages, overlay the new artifacts, and deploy
# the full server/ tree to Netlify as a preview (optional –
# Netlify failure does NOT block the PR).
#
# In both cases the job checks out gh-pages first, so the full existing
# documentation is available before the new artifacts are applied.
# ============================================================================
deploy:
name: Deploy documentation for gh-pages
needs: stage-and-check
if: github.event_name == 'push'
runs-on: ubuntu-latest

permissions:
Expand Down Expand Up @@ -471,16 +463,6 @@ jobs:
fi
done

# Move pdf files to the root of the branch folder
echo "Looking for PDF files to copy..."
find stage/${branch}/ -name "*.pdf" -type f
for pdf in stage/${branch}/*.pdf; do
if [ -f "$pdf" ]; then
echo "Copying PDF: $pdf"
cp "$pdf" server/${branch}/
fi
done

# If this is the highest stable branch, also deploy to its versioned folder
if [ -n "${additional}" ]; then
rm -rf server/${additional}
Expand All @@ -499,12 +481,14 @@ jobs:

# Remove the stage/ directory BEFORE creating the PR so it doesn't get committed
- name: Clean up staging cache before commit
if: github.event_name == 'push'
run: rm -rf stage/

# ========================================================================
# ADD REDIRECT FILES
# ========================================================================
- name: Add various redirects for go.php and user_manual english version
if: github.event_name == 'push'
run: |
branch="${{ needs.stage-and-check.outputs.branch_name }}"
additional="${{ needs.stage-and-check.outputs.additional_deployment }}"
Expand All @@ -531,7 +515,7 @@ jobs:
- name: Create Pull Request for documentation deployment
uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1
id: cpr
if: steps.apply.outputs.has_changes == 'true'
if: steps.apply.outputs.has_changes == 'true' && github.event_name == 'push'
with:
token: ${{ secrets.COMMAND_BOT_PAT }}
commit-message: "chore: update documentation for `${{ needs.stage-and-check.outputs.branch_name }}`"
Expand All @@ -554,6 +538,107 @@ jobs:
env:
GH_TOKEN: ${{ secrets.COMMAND_BOT_PAT }}

# ========================================================================
# NETLIFY PREVIEW (pull_request events only)
# ========================================================================
# At this point the working directory is the gh-pages checkout with the
# newly staged artifacts already applied, so server/ is a complete,
# up-to-date snapshot of the full documentation site.
# Netlify failure is non-fatal – the step uses continue-on-error so it
# does not block the PR.
# ========================================================================
- name: Install Netlify CLI
Comment thread
skjnldsv marked this conversation as resolved.
if: github.event_name == 'pull_request'
run: npm install -g netlify-cli

- name: Generate index.html for preview
if: github.event_name == 'pull_request'
run: |
branch="${{ needs.stage-and-check.outputs.branch_name }}"
# Build a root index listing only the manuals built for this PR
cat > server/index.html <<'INDEXEOF'
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Nextcloud Documentation Preview</title>
</head>
<body>
<h1>Nextcloud Documentation Preview</h1>
<ul>
INDEXEOF

for manual_dir in "server/${branch}"/*/; do
[ -d "$manual_dir" ] || continue
manual="$(basename "$manual_dir")"
echo " <li><a href=\"${branch}/${manual}/\">${manual}</a></li>" >> server/index.html
done

cat >> server/index.html <<'INDEXEOF'
</ul>
</body>
</html>
INDEXEOF

- name: Deploy to Netlify
id: netlify
if: github.event_name == 'pull_request'
continue-on-error: true
run: |
output=$(netlify deploy \
--dir=server \
--site="${{ secrets.NETLIFY_SITE_ID }}" \
--auth="${{ secrets.NETLIFY_AUTH_TOKEN }}" \
--alias="pr-${{ github.event.number }}" \
--message="Preview for PR #${{ github.event.number }}" \
--json)
deploy_url=$(echo "$output" | jq -r '.deploy_url // .url')
if [ -z "$deploy_url" ] || [ "$deploy_url" = "null" ]; then
echo "Failed to get deploy URL from Netlify output:" >&2
echo "$output" >&2
exit 1
fi
echo "deploy_url=${deploy_url}" >> $GITHUB_OUTPUT

- name: Comment preview URL on PR
if: github.event_name == 'pull_request' && steps.netlify.outputs.deploy_url != ''
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
with:
script: |
const deployUrl = '${{ steps.netlify.outputs.deploy_url }}';
const marker = '<!-- netlify-preview -->';
const body = `${marker}\n:rocket: **Netlify preview deployed:** ${deployUrl}`;

const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
});

const existing = comments.find(c => c.body.includes(marker));
let commentId;
if (existing) {
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: existing.id,
body,
});
commentId = existing.id;
} else {
const { data: created } = await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body,
});
commentId = created.id;
}

# ============================================================================
# SUMMARY
# ============================================================================
summary:
needs: [stage-and-check, link-check, deploy]
runs-on: ubuntu-latest-low
Expand All @@ -569,8 +654,8 @@ jobs:
run: |
if ${{ github.event_name == 'pull_request' }}
then
echo "This workflow ran for a pull request. We need stage-and-check and link-check to succeed, but deploy will be skipped"
if ${{ needs.stage-and-check.result != 'success' || needs.link-check.result != 'success' || needs.deploy.result != 'skipped' }}; then exit 1; fi
echo "This workflow ran for a pull request. We need stage-and-check, link-check, and deploy to succeed"
if ${{ needs.stage-and-check.result != 'success' || needs.link-check.result != 'success' || needs.deploy.result != 'success' }}; then exit 1; fi
else
echo "This workflow ran for a push. We need all jobs to succeed, including deploy"
if ${{ needs.stage-and-check.result != 'success' || needs.link-check.result != 'success' || needs.deploy.result != 'success' }}; then exit 1; fi
Expand Down