|
| 1 | +# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. |
| 2 | +# SPDX-License-Identifier: Apache-2.0 |
| 3 | +# |
| 4 | +# Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | +# you may not use this file except in compliance with the License. |
| 6 | +# You may obtain a copy of the License at |
| 7 | +# |
| 8 | +# http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | +# |
| 10 | +# Unless required by applicable law or agreed to in writing, software |
| 11 | +# distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | +# See the License for the specific language governing permissions and |
| 14 | +# limitations under the License. |
| 15 | + |
| 16 | +# Workflow 2 of 2 for Fern doc previews. |
| 17 | +# |
| 18 | +# Triggered by workflow_run after "Preview Fern Docs: Build" completes. |
| 19 | +# Downloads the fern/ artifact, builds a preview with DOCS_FERN_TOKEN, and |
| 20 | +# posts a stable :herb: comment on the PR. This workflow never checks out the |
| 21 | +# PR branch directly, keeping secrets isolated from untrusted code. |
| 22 | +# |
| 23 | +# Required configuration: |
| 24 | +# - Organization secret: DOCS_FERN_TOKEN (from `fern token` for the nvidia Fern org) |
| 25 | + |
| 26 | +name: "Preview Fern Docs: Comment" |
| 27 | + |
| 28 | +on: |
| 29 | + workflow_run: |
| 30 | + workflows: ["Preview Fern Docs: Build"] |
| 31 | + types: [completed] |
| 32 | + |
| 33 | +permissions: |
| 34 | + pull-requests: write |
| 35 | + actions: read |
| 36 | + |
| 37 | +jobs: |
| 38 | + preview: |
| 39 | + runs-on: ubuntu-latest |
| 40 | + if: ${{ github.event.workflow_run.conclusion == 'success' }} |
| 41 | + steps: |
| 42 | + - name: Download fern sources and metadata |
| 43 | + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 |
| 44 | + with: |
| 45 | + name: fern-preview |
| 46 | + run-id: ${{ github.event.workflow_run.id }} |
| 47 | + github-token: ${{ secrets.GITHUB_TOKEN }} |
| 48 | + |
| 49 | + - name: Read PR metadata |
| 50 | + id: metadata |
| 51 | + run: | |
| 52 | + echo "pr_number=$(cat .preview-metadata/pr_number)" >> "$GITHUB_OUTPUT" |
| 53 | + echo "head_ref=$(cat .preview-metadata/head_ref)" >> "$GITHUB_OUTPUT" |
| 54 | +
|
| 55 | + - name: Setup Node.js |
| 56 | + uses: actions/setup-node@v6 |
| 57 | + with: |
| 58 | + node-version: '20' |
| 59 | + |
| 60 | + - name: Install Fern CLI |
| 61 | + run: npm install -g fern-api |
| 62 | + |
| 63 | + - name: Generate library reference MDX (autodocs) |
| 64 | + env: |
| 65 | + FERN_TOKEN: ${{ secrets.DOCS_FERN_TOKEN }} |
| 66 | + working-directory: ./fern |
| 67 | + run: fern docs md generate |
| 68 | + |
| 69 | + - name: Generate preview URL |
| 70 | + id: generate-docs |
| 71 | + env: |
| 72 | + FERN_TOKEN: ${{ secrets.DOCS_FERN_TOKEN }} |
| 73 | + HEAD_REF: ${{ steps.metadata.outputs.head_ref }} |
| 74 | + working-directory: ./fern |
| 75 | + run: | |
| 76 | + OUTPUT=$(fern generate --docs --preview --id "$HEAD_REF" 2>&1) |
| 77 | + echo "$OUTPUT" |
| 78 | + URL=$(echo "$OUTPUT" | grep -oP 'Published docs to \K.*(?= \()') |
| 79 | + if [ -z "$URL" ]; then |
| 80 | + echo "::error::Failed to generate preview URL. See fern output above." |
| 81 | + exit 1 |
| 82 | + fi |
| 83 | + echo "preview_url=$URL" >> "$GITHUB_OUTPUT" |
| 84 | +
|
| 85 | + - name: Build page links for changed MDX files |
| 86 | + id: page-links |
| 87 | + env: |
| 88 | + FERN_TOKEN: ${{ secrets.DOCS_FERN_TOKEN }} |
| 89 | + PREVIEW_URL: ${{ steps.generate-docs.outputs.preview_url }} |
| 90 | + run: | |
| 91 | + CHANGED_FILES="" |
| 92 | + if [ -f .preview-metadata/changed_mdx_files ]; then |
| 93 | + CHANGED_FILES=$(cat .preview-metadata/changed_mdx_files) |
| 94 | + fi |
| 95 | +
|
| 96 | + if [ -z "$CHANGED_FILES" ] || [ -z "$PREVIEW_URL" ]; then |
| 97 | + echo "page_links=" >> "$GITHUB_OUTPUT"; exit 0 |
| 98 | + fi |
| 99 | +
|
| 100 | + BASE_URL=$(echo "$PREVIEW_URL" | grep -oP 'https?://[^/]+') |
| 101 | + FILES_PARAM=$(echo "$CHANGED_FILES" | tr '\n' ',' | sed 's/,$//' \ |
| 102 | + | python3 -c "import sys, urllib.parse; print(urllib.parse.quote(sys.stdin.read().strip(), safe=',/'))") |
| 103 | + RESPONSE=$(curl -sf -H "FERN_TOKEN: $FERN_TOKEN" "${PREVIEW_URL}/api/fern-docs/get-slug-for-file?files=${FILES_PARAM}" 2>/dev/null) || { |
| 104 | + echo "page_links=" >> "$GITHUB_OUTPUT"; exit 0 |
| 105 | + } |
| 106 | +
|
| 107 | + PAGE_LINKS=$(echo "$RESPONSE" | jq -r --arg url "$BASE_URL" \ |
| 108 | + '.mappings[] | select(.slug != null) | "- [\(.slug)](\($url)/\(.slug))"') |
| 109 | +
|
| 110 | + if [ -n "$PAGE_LINKS" ]; then |
| 111 | + { echo "page_links<<EOF"; echo "$PAGE_LINKS"; echo "EOF"; } >> "$GITHUB_OUTPUT" |
| 112 | + else |
| 113 | + echo "page_links=" >> "$GITHUB_OUTPUT" |
| 114 | + fi |
| 115 | +
|
| 116 | + - name: Post or update PR comment |
| 117 | + env: |
| 118 | + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
| 119 | + PR_NUMBER: ${{ steps.metadata.outputs.pr_number }} |
| 120 | + PREVIEW_URL: ${{ steps.generate-docs.outputs.preview_url }} |
| 121 | + PAGE_LINKS: ${{ steps.page-links.outputs.page_links }} |
| 122 | + run: | |
| 123 | + # Build comment body |
| 124 | + BODY=":herb: **Preview your docs:** <${PREVIEW_URL}>" |
| 125 | + if [ -n "${PAGE_LINKS}" ]; then |
| 126 | + BODY="${BODY} |
| 127 | +
|
| 128 | + Here are the markdown pages you've updated: |
| 129 | + ${PAGE_LINKS}" |
| 130 | + fi |
| 131 | +
|
| 132 | + # Hidden marker for upsert |
| 133 | + MARKER="<!-- preview-docs -->" |
| 134 | + BODY="${BODY} |
| 135 | +
|
| 136 | + ${MARKER}" |
| 137 | +
|
| 138 | + # Find existing comment with marker |
| 139 | + COMMENT_ID=$(gh api "repos/${{ github.repository }}/issues/${PR_NUMBER}/comments" \ |
| 140 | + --jq ".[] | select(.body | contains(\"${MARKER}\")) | .id" | head -1) |
| 141 | +
|
| 142 | + if [ -n "$COMMENT_ID" ]; then |
| 143 | + gh api "repos/${{ github.repository }}/issues/comments/${COMMENT_ID}" \ |
| 144 | + -X PATCH -f body="$BODY" |
| 145 | + else |
| 146 | + gh api "repos/${{ github.repository }}/issues/${PR_NUMBER}/comments" \ |
| 147 | + -f body="$BODY" |
| 148 | + fi |
0 commit comments