diff --git a/.github/workflows/fern-docs-ci.yml b/.github/workflows/fern-docs-ci.yml new file mode 100644 index 00000000..d7f57940 --- /dev/null +++ b/.github/workflows/fern-docs-ci.yml @@ -0,0 +1,49 @@ +# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Validates Fern autodocs generation (fern/product-docs) on pull requests. +# Output is gitignored; see fern/AUTODOCS_GUIDE.md and docs.yml `libraries`. + +name: Fern docs (autodocs) + +on: + pull_request: + paths: + - 'fern/**' + - '.github/workflows/fern-docs-ci.yml' + +permissions: + contents: read + +jobs: + generate-library-reference: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v6 + + - name: Setup Node.js + uses: actions/setup-node@v6 + with: + node-version: '20' + + - name: Install Fern CLI + run: npm install -g fern-api + + - name: Generate library reference MDX (product-docs) + env: + FERN_TOKEN: ${{ secrets.DOCS_FERN_TOKEN }} + working-directory: ./fern + run: fern docs md generate diff --git a/.github/workflows/fern-docs-preview-build.yml b/.github/workflows/fern-docs-preview-build.yml new file mode 100644 index 00000000..bab659cb --- /dev/null +++ b/.github/workflows/fern-docs-preview-build.yml @@ -0,0 +1,63 @@ +# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Workflow 1 of 2 for Fern doc previews. +# +# Collects the fern/ sources and PR metadata from the (possibly untrusted) PR +# branch and uploads them as an artifact. No secrets are used here, so this is +# safe to run on fork PRs via the regular pull_request trigger. +# +# The companion workflow (fern-docs-preview-comment.yml) picks up the artifact, +# builds the preview with DOCS_FERN_TOKEN, and posts the PR comment. + +name: "Preview Fern Docs: Build" + +on: + pull_request: + paths: + - 'fern/**' + - '.github/workflows/fern-docs-preview-build.yml' + +permissions: + contents: read + +jobs: + collect: + runs-on: ubuntu-latest + steps: + - name: Checkout PR + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + fetch-depth: 0 + + - name: Save PR metadata + env: + PR_NUMBER: ${{ github.event.pull_request.number }} + HEAD_REF: ${{ github.head_ref }} + BASE_REF: ${{ github.base_ref }} + run: | + mkdir -p .preview-metadata + echo "$PR_NUMBER" > .preview-metadata/pr_number + echo "$HEAD_REF" > .preview-metadata/head_ref + git diff --name-only "origin/${BASE_REF}...HEAD" -- '*.mdx' > .preview-metadata/changed_mdx_files 2>/dev/null || true + + - name: Upload fern sources and metadata + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + with: + name: fern-preview + path: | + fern/ + .preview-metadata/ + retention-days: 1 diff --git a/.github/workflows/fern-docs-preview-comment.yml b/.github/workflows/fern-docs-preview-comment.yml new file mode 100644 index 00000000..6696f512 --- /dev/null +++ b/.github/workflows/fern-docs-preview-comment.yml @@ -0,0 +1,148 @@ +# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Workflow 2 of 2 for Fern doc previews. +# +# Triggered by workflow_run after "Preview Fern Docs: Build" completes. +# Downloads the fern/ artifact, builds a preview with DOCS_FERN_TOKEN, and +# posts a stable :herb: comment on the PR. This workflow never checks out the +# PR branch directly, keeping secrets isolated from untrusted code. +# +# Required configuration: +# - Organization secret: DOCS_FERN_TOKEN (from `fern token` for the nvidia Fern org) + +name: "Preview Fern Docs: Comment" + +on: + workflow_run: + workflows: ["Preview Fern Docs: Build"] + types: [completed] + +permissions: + pull-requests: write + actions: read + +jobs: + preview: + runs-on: ubuntu-latest + if: ${{ github.event.workflow_run.conclusion == 'success' }} + steps: + - name: Download fern sources and metadata + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 + with: + name: fern-preview + run-id: ${{ github.event.workflow_run.id }} + github-token: ${{ secrets.GITHUB_TOKEN }} + + - name: Read PR metadata + id: metadata + run: | + echo "pr_number=$(cat .preview-metadata/pr_number)" >> "$GITHUB_OUTPUT" + echo "head_ref=$(cat .preview-metadata/head_ref)" >> "$GITHUB_OUTPUT" + + - name: Setup Node.js + uses: actions/setup-node@v6 + with: + node-version: '20' + + - name: Install Fern CLI + run: npm install -g fern-api + + - name: Generate library reference MDX (autodocs) + env: + FERN_TOKEN: ${{ secrets.DOCS_FERN_TOKEN }} + working-directory: ./fern + run: fern docs md generate + + - name: Generate preview URL + id: generate-docs + env: + FERN_TOKEN: ${{ secrets.DOCS_FERN_TOKEN }} + HEAD_REF: ${{ steps.metadata.outputs.head_ref }} + working-directory: ./fern + run: | + OUTPUT=$(fern generate --docs --preview --id "$HEAD_REF" 2>&1) + echo "$OUTPUT" + URL=$(echo "$OUTPUT" | grep -oP 'Published docs to \K.*(?= \()') + if [ -z "$URL" ]; then + echo "::error::Failed to generate preview URL. See fern output above." + exit 1 + fi + echo "preview_url=$URL" >> "$GITHUB_OUTPUT" + + - name: Build page links for changed MDX files + id: page-links + env: + FERN_TOKEN: ${{ secrets.DOCS_FERN_TOKEN }} + PREVIEW_URL: ${{ steps.generate-docs.outputs.preview_url }} + run: | + CHANGED_FILES="" + if [ -f .preview-metadata/changed_mdx_files ]; then + CHANGED_FILES=$(cat .preview-metadata/changed_mdx_files) + fi + + if [ -z "$CHANGED_FILES" ] || [ -z "$PREVIEW_URL" ]; then + echo "page_links=" >> "$GITHUB_OUTPUT"; exit 0 + fi + + BASE_URL=$(echo "$PREVIEW_URL" | grep -oP 'https?://[^/]+') + FILES_PARAM=$(echo "$CHANGED_FILES" | tr '\n' ',' | sed 's/,$//' \ + | python3 -c "import sys, urllib.parse; print(urllib.parse.quote(sys.stdin.read().strip(), safe=',/'))") + RESPONSE=$(curl -sf -H "FERN_TOKEN: $FERN_TOKEN" "${PREVIEW_URL}/api/fern-docs/get-slug-for-file?files=${FILES_PARAM}" 2>/dev/null) || { + echo "page_links=" >> "$GITHUB_OUTPUT"; exit 0 + } + + PAGE_LINKS=$(echo "$RESPONSE" | jq -r --arg url "$BASE_URL" \ + '.mappings[] | select(.slug != null) | "- [\(.slug)](\($url)/\(.slug))"') + + if [ -n "$PAGE_LINKS" ]; then + { echo "page_links<> "$GITHUB_OUTPUT" + else + echo "page_links=" >> "$GITHUB_OUTPUT" + fi + + - name: Post or update PR comment + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PR_NUMBER: ${{ steps.metadata.outputs.pr_number }} + PREVIEW_URL: ${{ steps.generate-docs.outputs.preview_url }} + PAGE_LINKS: ${{ steps.page-links.outputs.page_links }} + run: | + # Build comment body + BODY=":herb: **Preview your docs:** <${PREVIEW_URL}>" + if [ -n "${PAGE_LINKS}" ]; then + BODY="${BODY} + + Here are the markdown pages you've updated: + ${PAGE_LINKS}" + fi + + # Hidden marker for upsert + MARKER="" + BODY="${BODY} + + ${MARKER}" + + # Find existing comment with marker + COMMENT_ID=$(gh api "repos/${{ github.repository }}/issues/${PR_NUMBER}/comments" \ + --jq ".[] | select(.body | contains(\"${MARKER}\")) | .id" | head -1) + + if [ -n "$COMMENT_ID" ]; then + gh api "repos/${{ github.repository }}/issues/comments/${COMMENT_ID}" \ + -X PATCH -f body="$BODY" + else + gh api "repos/${{ github.repository }}/issues/${PR_NUMBER}/comments" \ + -f body="$BODY" + fi