Skip to content

Replace Algolia search with built-in search #3599

Replace Algolia search with built-in search

Replace Algolia search with built-in search #3599

Workflow file for this run

on:
pull_request:
branches: [main, prerelease]
paths-ignore:
- '.github/**'
issue_comment:
types: [created]
name: Deploy Preview
concurrency:
# Use github.event.pull_request.number on pull requests, so it's unique per pull request
# Use github.event.issue.number on issue comments, so it's unique per comment
# Use github.ref on other branches, so it's unique per branch
group: ${{ github.workflow }}-${{ (github.event.pull_request && format('PR-{0}', github.event.pull_request.number)) || ( github.event.issue && format('comment-{0}', github.event.issue.number) ) || github.ref }}
cancel-in-progress: true
jobs:
is-external-pr:
# Be helpful with reviewer and remind them to trigger a deploy preview if the PR is from a fork.
if: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork == true }}
runs-on: ubuntu-latest
steps:
- name: Error with message for manual deploy
run: |
echo "::error title=Manual action required for preview::PR from fork can't be deployed as preview to Netlify automatically. Use '/deploy-preview' command in comments to trigger the preview manually."
shell: bash
role-of-commenter:
if: github.event.issue.pull_request
runs-on: ubuntu-latest
steps:
- name: Check if commenter is a member, owner or collaborator
id: commenter-check
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
commenter_role=$(gh api repos/$GITHUB_REPOSITORY/collaborators/${{ github.event.comment.user.login }}/permission --jq '.permission')
echo "commenter_role=$commenter_role" >> "$GITHUB_OUTPUT"
echo "author_association=${{ github.event.comment.author_association }}" >> "$GITHUB_OUTPUT"
shell: bash
build-deploy-preview:
# Deploy a preview only if
# - the PR is not from a fork,
# - requested by PR comment /deploy-preview, from a repo user or github action bot (user id 41898282)
# FIXME: We need to change the way we filter because somehow some MEMBER in API are seen as CONTRIBUTOR in CI
if: >
(
github.event_name == 'pull_request' &&
github.event.pull_request.head.repo.fork != true
) ||
(
github.event.issue.pull_request &&
(
github.event.comment.user.id == '41898282' ||
github.event.comment.user.login == 'gordonwoodhull' ||
github.event.comment.author_association == 'MEMBER' ||
github.event.comment.author_association == 'OWNER' ||
github.event.comment.author_association == 'COLLABORATOR'
) &&
startsWith(github.event.comment.body, '/deploy-preview')
)
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@v6
with:
ref: refs/pull/${{ github.event.pull_request.number || github.event.issue.number }}/merge
# On issue_comment events (e.g. /deploy-preview), github.event.pull_request
# is not populated so tj-actions/changed-files can't determine the base commit
# to diff against. Fetch it from the API so we can pass it explicitly.
- name: Get PR base SHA
if: github.event_name != 'pull_request'
id: pr-info
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
pr_number=${{ github.event.issue.number }}
base_sha=$(gh -R $GITHUB_REPOSITORY pr view $pr_number --json baseRefOid --jq '.baseRefOid')
echo "base_sha=$base_sha" >> "$GITHUB_OUTPUT"
shell: bash
- name: Get latest pre-release from github
id: github-release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
echo version=$(gh api repos/quarto-dev/quarto-cli/releases | jq -r 'map(select(.prerelease)) | first | .tag_name | sub("^v";"")') >> "$GITHUB_OUTPUT"
- name: Set up Quarto
uses: quarto-dev/quarto-actions/setup@v2
with:
version: ${{ steps.github-release.outputs.version }}
- name: Is it for prerelease website ?
id: prerelease-docs-check
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
if [ "${{ github.event.pull_request.base.ref }}" == "prerelease" ]; then
echo "is_prerelease_docs=true" >> "$GITHUB_OUTPUT"
elif [ -n "${{ github.event.issue.pull_request.url }}" ]; then
# This will trigger when not pull request event, so a PR comment event.
# we need to get the base info from PR number the comment is made in
base_ref=$(gh -R $GITHUB_REPOSITORY pr view ${{ github.event.issue.number }} --json baseRefName --jq '.baseRefName')
if [ "$base_ref" == "prerelease" ]; then
echo "is_prerelease_docs=true" >> "$GITHUB_OUTPUT"
else
echo "is_prerelease_docs=false" >> "$GITHUB_OUTPUT"
fi
else
echo "is_prerelease_docs=false" >> "$GITHUB_OUTPUT"
fi
shell: bash
- name: Render
uses: quarto-dev/quarto-actions/render@v2
env:
QUARTO_PROFILE: ${{ steps.prerelease-docs-check.outputs.is_prerelease_docs == 'true' && 'prerelease-docs,pr-preview' || 'pr-preview' }}
- name: Deploy Preview to Netlify as preview
id: netlify-deploy
uses: nwtgck/actions-netlify@v3
env:
NETLIFY_SITE_ID: 2a3da659-672b-4e5b-8785-e10ebf79a962
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
with:
publish-dir: './_site'
production-deploy: false
github-token: ${{ secrets.GITHUB_TOKEN }}
deploy-message: |
Deploy from GHA: ${{ github.event.pull_request.title || format('manual from PR {0}', github.event.issue.number) }}
alias: deploy-preview-${{ github.event.pull_request.number || github.event.issue.number }}
# these all default to 'true'
enable-pull-request-comment: false
enable-commit-comment: false
enable-commit-status: true
overwrites-pull-request-comment: false
timeout-minutes: 1
- name: Get changed files
id: changed-files
uses: tj-actions/changed-files@22103cc46bda19c2b464ffe86db46df6922fd323 # v47.0.5
with:
base_sha: ${{ github.event.pull_request.base.sha || steps.pr-info.outputs.base_sha }}
files: |
# don't consider modifications on file used for includes for now.
license.qmd
docs/**/[^_]*.qmd
docs/**/[^_]*.md
docs/extensions/listings/*.yml
docs/reference/**/*.json
docs/cli/*.json
docs/**/images/*.png
files_ignore: |
**/CLAUDE.md
json: true
escape_json: false
- name: Map changed images to doc pages
id: image-pages
run: |
# Build JSON mapping from image output paths to doc pages using manifest
MANIFEST="_tools/screenshots/manifest.json"
CHANGED='${{ steps.changed-files.outputs.all_changed_files }}'
if [ -f "$MANIFEST" ]; then
# Extract {output: doc.file} pairs, match against changed files
IMAGE_PAGES=$(echo "$CHANGED" | jq -r --slurpfile manifest "$MANIFEST" '
($manifest[0].screenshots | map(select(.doc.file) | {(.output): .doc.file}) | add // {}) as $map |
[.[] | select(test("[.]png$")) |
# Normalize dark variants (foo-dark.png -> foo.png) for manifest lookup
sub("-dark[.]png$"; ".png") as $base |
($map[$base] // empty) | sub("[.]qmd$"; ".html")
] | unique | .[]
')
echo "pages<<EOF" >> "$GITHUB_OUTPUT"
echo "$IMAGE_PAGES" >> "$GITHUB_OUTPUT"
echo "EOF" >> "$GITHUB_OUTPUT"
fi
shell: bash
- name: Detect draft pages
id: detect-drafts
uses: ./.github/workflows/actions/detect-drafts
with:
changed-files: ${{ steps.changed-files.outputs.all_changed_files }}
- name: Create custom PR comment
if: github.event.pull_request || github.event.issue.pull_request
uses: actions/github-script@v8
env:
DEPLOY_URL: ${{ steps.netlify-deploy.outputs.deploy-url }}
CHANGED_FILES: ${{ steps.changed-files.outputs.all_changed_files }}
IMAGE_PAGES: ${{ steps.image-pages.outputs.pages }}
DRAFT_FILES: ${{ steps.detect-drafts.outputs.files }}
HAS_DRAFTS: ${{ steps.detect-drafts.outputs.found }}
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const prNumber = context.payload.pull_request?.number || context.payload.issue.number;
const deployUrl = process.env.DEPLOY_URL;
const changedFiles = JSON.parse(process.env.CHANGED_FILES || '[]');
const draftFilesList = (process.env.DRAFT_FILES || '').trim().split('\n').filter(Boolean);
const draftSet = new Set(draftFilesList);
let commentBody = `## 📝 Preview Deployment\n\n`;
commentBody += `🔍 Full site preview: [${deployUrl}](${deployUrl})\n\n`;
if (changedFiles.length > 0) {
// Explicit mapping for files that don't follow standard naming conventions
const specialFileMapping = {
'docs/extensions/listings/shortcodes-and-filters.yml': 'docs/extensions/index.html',
'docs/extensions/listings/journal-articles.yml': 'docs/extensions/index.html',
'docs/extensions/listings/custom-formats.yml': 'docs/extensions/index.html',
'docs/extensions/listings/revealjs-formats.yml': 'docs/extensions/index.html',
'docs/extensions/listings/revealjs.yml': 'docs/extensions/index.html',
'docs/cli/cli-info.json': 'docs/reference/index.html',
};
// Projects/ JSON files have many-to-one mapping to .qmd pages
const projectsJsonMapping = {
'book': 'docs/reference/projects/books.html',
'manuscript': 'docs/reference/projects/manuscripts.html',
'project': 'docs/reference/projects/options.html',
'preview': 'docs/reference/projects/options.html',
'serve': 'docs/reference/projects/options.html',
};
const projectsDefault = 'docs/reference/projects/websites.html';
// Resolve each changed file to its preview URL path
// Group files by their target page for deduplication
const pageToFiles = new Map();
changedFiles.forEach(file => {
let fileUrlPath;
if (specialFileMapping[file]) {
fileUrlPath = specialFileMapping[file];
} else if (file.endsWith('.qmd') || file.endsWith('.md')) {
fileUrlPath = file.replace(/\.(qmd|md)$/, '.html');
} else if (file.startsWith('docs/reference/projects/') && file.endsWith('.json')) {
const stem = file.split('/').pop().replace('.json', '');
fileUrlPath = projectsJsonMapping[stem] || projectsDefault;
} else if (file.endsWith('.json')) {
// Generic: formats/, cells/, metadata/ JSON have sibling .qmd files
fileUrlPath = file.replace(/\.json$/, '.html');
}
if (fileUrlPath) {
if (!pageToFiles.has(fileUrlPath)) {
pageToFiles.set(fileUrlPath, []);
}
pageToFiles.get(fileUrlPath).push(file);
}
});
if (pageToFiles.size > 0) {
commentBody += `### 🔄 Modified Documents\n\n`;
for (const [page, files] of pageToFiles) {
const fileUrl = `${deployUrl}/${page}`;
const isDraft = files.some(f => draftSet.has(f));
const draftTag = isDraft ? ' — ⚠️ `draft`' : '';
if (files.length === 1) {
commentBody += `- [${page}](${fileUrl})${draftTag}\n`;
} else {
// Multiple source files map to one page - show page with file summary
const basenames = files.map(f => f.split('/').pop());
const shown = basenames.slice(0, 3).join(', ');
const rest = basenames.length > 3 ? `, +${basenames.length - 3} more` : '';
commentBody += `- [${page}](${fileUrl}) (${shown}${rest})${draftTag}\n`;
}
}
}
}
// Add pages affected by changed screenshots
const imagePages = (process.env.IMAGE_PAGES || '').trim();
if (imagePages) {
const pages = [...new Set(imagePages.split('\n').filter(Boolean))];
if (pages.length > 0) {
commentBody += `\n### 🖼️ Pages with Updated Screenshots\n\n`;
for (const page of pages) {
const fileUrl = `${deployUrl}/${page}`;
commentBody += `- [${page}](${fileUrl})\n`;
}
}
}
// Add draft warning callout (no file list — already tagged inline above)
const hasDrafts = process.env.HAS_DRAFTS === 'true';
if (hasDrafts) {
commentBody += `\n> [!WARNING]\n`;
commentBody += `> This PR contains pages with \`draft: true\`. Remove the draft status before merging if the content is ready to publish.\n`;
}
await github.rest.issues.createComment({
issue_number: prNumber,
owner: context.repo.owner,
repo: context.repo.repo,
body: commentBody
});