Skip to content
Closed
Show file tree
Hide file tree
Changes from all 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
49 changes: 49 additions & 0 deletions .github/workflows/fern-docs-ci.yml
Original file line number Diff line number Diff line change
@@ -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
63 changes: 63 additions & 0 deletions .github/workflows/fern-docs-preview-build.yml
Original file line number Diff line number Diff line change
@@ -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
148 changes: 148 additions & 0 deletions .github/workflows/fern-docs-preview-comment.yml
Original file line number Diff line number Diff line change
@@ -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<<EOF"; echo "$PAGE_LINKS"; echo "EOF"; } >> "$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="<!-- preview-docs -->"
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
Loading