Repository navigation
docs: Documentation audit and updates for 0.8 (#5380) #2
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # 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. | |
| # Dynamo docs build and publish workflow | |
| # Build: | |
| # - Builds documentation using Docker container | |
| # - Creates artifact for downstream use | |
| # - Runs on: main, release/*, tags, PRs (docs changes only), manual dispatch | |
| # | |
| # Publish: | |
| # - Main branch: publish to S3 under 'dev' (development docs) | |
| # - Tagged commits: publish to S3 under 'archive/X.Y.Z' AND update 'latest' to match the release | |
| # - Manual dispatch: publish specified version to archive (does NOT update 'latest') | |
| # - PRs: no S3 publish (only internal preview deployment if targeting release branch) | |
| # - Version manifest: automatically updated in S3 when publishing new versions (versions1.json) | |
| # - Akamai: flushes cache for the target path after publish (when DOCS_AKAMAI_ENABLED=true) | |
| # | |
| # Required Configuration: | |
| # - Repository variable: DOCS_PUBLISH_S3_TARGET_PATH (prefix under S3 bucket, e.g., "dynamo") | |
| # - Repository variable: DOCS_BASE_URL (base URL for docs site, e.g., "https://docs.nvidia.com/dynamo") | |
| # - Secrets: AWS credentials (DOCS_AWS_ACCESS_KEY_ID, DOCS_AWS_SECRET_ACCESS_KEY, DOCS_AWS_S3_BUCKET, DOCS_AWS_REGION) | |
| # - Secrets: DOCS_TOKEN (GitHub PAT for PR preview deployment to external repo) | |
| # - Secrets (optional): DOCS_AWS_IAM_STS_ROLE (for OIDC authentication instead of IAM keys) | |
| # - Secrets (optional): DOCS_AKAMAI_* EdgeGrid credentials for cache flush | |
| # - Variable (optional): DOCS_AKAMAI_ENABLED (set to 'true' to enable Akamai cache flush) | |
| # | |
| # Commit message flags: | |
| # - '/skip-dev': skip publishing 'dev' on main branch | |
| # - '/not-latest': publish version to archive but don't update 'latest' | |
| name: Generate and Publish Documentation | |
| on: | |
| push: | |
| branches: | |
| - main | |
| - release/* | |
| tags: | |
| - '*' | |
| pull_request: | |
| paths: | |
| - 'docs/**' | |
| - 'container/Dockerfile.docs' | |
| - '.github/workflows/generate-docs.yml' | |
| workflow_dispatch: | |
| inputs: | |
| version: | |
| description: 'Optional: Version to publish (e.g., 1.2.3). If not provided, publishes as dev.' | |
| required: false | |
| type: string | |
| ref: | |
| description: 'Optional: Git ref to checkout (tag, branch, or SHA). Use to build docs from older tags.' | |
| required: false | |
| type: string | |
| jobs: | |
| build-docs: | |
| name: Build Documentation | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ inputs.ref || github.ref }} | |
| - name: Determine docs version | |
| id: version | |
| shell: bash | |
| run: | | |
| VERSION="dev" | |
| # Option 1: Tag push (e.g., v0.3.0 -> 0.3.0) | |
| if [[ "${{ github.ref_type }}" == "tag" ]]; then | |
| TAG="${{ github.ref_name }}" | |
| if [[ "${TAG}" =~ ^v([0-9]+(\.[0-9]+){1,2}([._-](post|rc|dev)[0-9]+)?)$ ]]; then | |
| VERSION="${BASH_REMATCH[1]}" | |
| echo "::notice::Detected version from tag: ${VERSION}" | |
| fi | |
| # Option 2: Manual dispatch with version input | |
| elif [[ -n "${{ inputs.version || '' }}" ]]; then | |
| VERSION="${{ inputs.version }}" | |
| echo "::notice::Using version from manual input: ${VERSION}" | |
| fi | |
| echo "version=${VERSION}" >> "$GITHUB_OUTPUT" | |
| echo "Building docs for version: ${VERSION}" | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - name: Generate documentation | |
| env: | |
| DOCS_VERSION: ${{ steps.version.outputs.version }} | |
| run: | | |
| docker build -t docs-builder \ | |
| --build-arg DYNAMO_DOCS_VERSION="${DOCS_VERSION}" \ | |
| -f container/Dockerfile.docs . | |
| - name: Copy documentation out of container | |
| run: | | |
| docker create --name docs-container docs-builder | |
| docker cp docs-container:/workspace/dynamo/docs/build/html dynamo-docs/ | |
| - name: Remove documentation container | |
| if: always() | |
| run: | | |
| docker rm docs-container || true | |
| - name: Upload documentation artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: dynamo-docs-${{ github.run_id }} | |
| path: dynamo-docs | |
| retention-days: 15 | |
| deploy: | |
| name: Deploy to private documentation repository | |
| needs: build-docs | |
| runs-on: ubuntu-latest | |
| # Deploy on PRs targeting release branches | |
| if: github.event_name == 'pull_request' && startsWith(github.base_ref, 'release') | |
| # Prevent multiple deployments from running simultaneously | |
| concurrency: | |
| group: deploy-docs-${{ github.base_ref }} | |
| cancel-in-progress: false | |
| env: | |
| DOCS_BASE_URL: "https://crispy-winner-3jnj38w.pages.github.io" | |
| DOCS_REPOSITORY: "ai-dynamo/dynamo-docs" | |
| DOCS_BRANCH: "main" | |
| DOCS_ARTIFACT_NAME: "dynamo-docs" | |
| steps: | |
| - name: Checkout source repo | |
| uses: actions/checkout@v4 | |
| - name: Download documentation artifact | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: ${{ env.DOCS_ARTIFACT_NAME }}-${{ github.run_id }} | |
| path: ${{ env.DOCS_ARTIFACT_NAME }} | |
| - name: Clean potentially stale metadata files (but preserve index) | |
| run: | | |
| rm -f ./${{ env.DOCS_ARTIFACT_NAME }}/CNAME | |
| rm -f ./${{ env.DOCS_ARTIFACT_NAME }}/_config.yml | |
| # Don't remove index.html - it's needed for navigation | |
| - name: Determine deployment directory | |
| id: deploy_dir | |
| run: | | |
| # For PRs, use consistent directory (latest commit overwrites previous) | |
| SHORT_SHA=$(echo "${{ github.sha }}" | cut -c1-8) | |
| echo "dir_name=${{ github.base_ref }}/pr-${{ github.event.number }}" >> $GITHUB_OUTPUT | |
| echo "commit_ref=${{ github.sha }}" >> $GITHUB_OUTPUT | |
| echo "short_sha=${SHORT_SHA}" >> $GITHUB_OUTPUT | |
| - name: Deploy to internal GitHub Pages | |
| uses: peaceiris/actions-gh-pages@v4 | |
| with: | |
| personal_token: ${{ secrets.DOCS_TOKEN }} | |
| external_repository: ${{ env.DOCS_REPOSITORY }} | |
| publish_branch: ${{ env.DOCS_BRANCH }} | |
| publish_dir: ./${{ env.DOCS_ARTIFACT_NAME }} | |
| destination_dir: ${{ steps.deploy_dir.outputs.dir_name }} | |
| commit_message: 'Deploy documentation from ${{ github.repository }}@${{ steps.deploy_dir.outputs.commit_ref }} (branch: ${{ steps.deploy_dir.outputs.dir_name }})' | |
| keep_files: true | |
| - name: Comment on PR with docs link | |
| if: github.event_name == 'pull_request' | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const docsUrl = `${{ env.DOCS_BASE_URL }}/${{ steps.deploy_dir.outputs.dir_name }}/`; | |
| const comment = `## 📚 Documentation Preview | |
| **📖 View Latest Documentation:** [${docsUrl}](${docsUrl}) | |
| > **Latest Deployment:** | |
| > - **Commit:** [\`${{ steps.deploy_dir.outputs.short_sha }}\`](https://github.com/${{ github.repository }}/commit/${{ github.sha }}) *(latest push)* | |
| > - **Target:** \`${{ github.base_ref }}\` | |
| > - **Updated:** ${new Date().toLocaleString('en-US', { timeZone: 'UTC', timeStyle: 'short', dateStyle: 'short' })} UTC | |
| > | |
| > **Note:** This link always shows the documentation for the latest commit. It may take a few minutes for GitHub Pages to update after each push. | |
| --- | |
| *Auto-updated by the documentation deployment workflow*`; | |
| // Find and update existing comment, or create new one | |
| const { data: comments } = await github.rest.issues.listComments({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: context.issue.number, | |
| }); | |
| const botComment = comments.find(comment => | |
| comment.user.type === 'Bot' && | |
| comment.body.includes('📚 Documentation Preview') | |
| ); | |
| if (botComment) { | |
| await github.rest.issues.updateComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| comment_id: botComment.id, | |
| body: comment | |
| }); | |
| } else { | |
| await github.rest.issues.createComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: context.issue.number, | |
| body: comment | |
| }); | |
| } | |
| publish-s3: | |
| name: Publish docs to S3 and flush Akamai | |
| needs: [build-docs] | |
| runs-on: ubuntu-latest | |
| if: ${{ github.event_name != 'pull_request' }} | |
| permissions: | |
| contents: read | |
| id-token: write | |
| actions: read | |
| env: | |
| S3_BUCKET: ${{ secrets.DOCS_AWS_S3_BUCKET }} | |
| DOCS_DIR: dynamo-docs | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| - name: Configure AWS credentials | |
| uses: aws-actions/configure-aws-credentials@v4 | |
| with: | |
| # Use OIDC (role assumption) if available, otherwise use IAM keys | |
| role-to-assume: ${{ secrets.DOCS_AWS_IAM_STS_ROLE }} | |
| aws-access-key-id: ${{ secrets.DOCS_AWS_ACCESS_KEY_ID }} | |
| aws-secret-access-key: ${{ secrets.DOCS_AWS_SECRET_ACCESS_KEY }} | |
| aws-region: ${{ secrets.DOCS_AWS_REGION }} | |
| - name: Verify AWS identity | |
| run: | | |
| aws sts get-caller-identity >/dev/null || { | |
| echo "::error::Failed to authenticate with AWS. Check credentials configuration." | |
| exit 1 | |
| } | |
| - name: Download documentation artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| pattern: dynamo-docs-* | |
| path: ${{ env.DOCS_DIR }} | |
| - name: Validate documentation artifacts | |
| run: | | |
| # The artifact is downloaded into a subdirectory, move contents up one level | |
| ARTIFACT_DIR=$(find "${{ env.DOCS_DIR }}" -mindepth 1 -maxdepth 1 -type d | head -n 1) | |
| if [[ -z "${ARTIFACT_DIR}" ]]; then | |
| echo "::error::No artifact directory found" | |
| exit 1 | |
| fi | |
| echo "::notice::Moving contents from ${ARTIFACT_DIR} to ${{ env.DOCS_DIR }}" | |
| mv "${ARTIFACT_DIR}"/* "${{ env.DOCS_DIR }}/" | |
| rmdir "${ARTIFACT_DIR}" | |
| # Validate extraction | |
| if [[ ! -d "${{ env.DOCS_DIR }}" ]] || [[ -z "$(ls -A ${{ env.DOCS_DIR }})" ]]; then | |
| echo "::error::Documentation directory is empty after extraction" | |
| exit 1 | |
| fi | |
| echo "::notice::Documentation size: $(du -sh ${{ env.DOCS_DIR }} | cut -f1)" | |
| - name: Determine version and validate inputs | |
| id: vars | |
| env: | |
| ARTIFACTS_PATH: dynamo-docs | |
| TARGET_PATH: ${{ vars.DOCS_PUBLISH_S3_TARGET_PATH }} | |
| COMMIT_MSG: ${{ github.event.head_commit.message || '' }} | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| if [[ -z "${TARGET_PATH}" ]]; then | |
| echo "::error::target-path was not provided. Set repository variable DOCS_PUBLISH_S3_TARGET_PATH." | |
| exit 1 | |
| fi | |
| if [[ ! -d "${ARTIFACTS_PATH}" ]]; then | |
| echo "::error::Failed to find documentation artifacts at ${ARTIFACTS_PATH}" | |
| exit 1 | |
| fi | |
| # Determine version from various sources | |
| VERSION="" | |
| PUBLISH_TO_LATEST="false" | |
| # Option 1: Direct tag push | |
| if [[ "${{ github.ref_type }}" == "tag" ]]; then | |
| TAG="${{ github.ref_name }}" | |
| if [[ "${TAG}" =~ ^v([0-9]+(\.[0-9]+){1,2}([._-](post|rc|dev)[0-9]+)?)$ ]]; then | |
| VERSION="${BASH_REMATCH[1]}" | |
| echo "Detected version from tag: ${VERSION}" | |
| PUBLISH_TO_LATEST="true" | |
| fi | |
| # Check for /not-latest flag in commit message | |
| if [[ "${COMMIT_MSG}" =~ /not-latest ]]; then | |
| PUBLISH_TO_LATEST="false" | |
| echo "Detected /not-latest flag in commit message" | |
| fi | |
| # Option 2: Manual dispatch with version input | |
| elif [[ -n "${{ inputs.version || '' }}" ]]; then | |
| VERSION="${{ inputs.version }}" | |
| echo "Using version from manual input: ${VERSION}" | |
| # Don't publish to latest on manual dispatch | |
| PUBLISH_TO_LATEST="false" | |
| echo "Manual dispatch detected - will not publish to latest" | |
| fi | |
| echo "version=${VERSION}" >> "$GITHUB_OUTPUT" | |
| echo "artifacts_path=${ARTIFACTS_PATH}" >> "$GITHUB_OUTPUT" | |
| echo "publish_to_latest=${PUBLISH_TO_LATEST}" >> "$GITHUB_OUTPUT" | |
| if [[ -n "${VERSION}" ]]; then | |
| echo "::notice::Publishing version: ${VERSION}" | |
| if [[ "${PUBLISH_TO_LATEST}" == "true" ]]; then | |
| echo "::notice::Will also publish to 'latest'" | |
| else | |
| echo "::notice::Will NOT publish to 'latest'" | |
| fi | |
| else | |
| echo "::notice::Publishing as dev (no version detected)" | |
| fi | |
| - name: Normalize S3 path | |
| id: paths | |
| env: | |
| S3_TARGET_ROOT: ${{ env.S3_BUCKET }} | |
| TARGET_PATH: ${{ vars.DOCS_PUBLISH_S3_TARGET_PATH }} | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| S3_ROOT="${S3_TARGET_ROOT%/}" | |
| S3_PATH="${TARGET_PATH#/}" | |
| S3_PATH="${S3_PATH%/}" | |
| echo "S3_TARGET_PATH...${S3_PATH}" | |
| echo "s3_root=${S3_ROOT}" >> "$GITHUB_OUTPUT" | |
| echo "s3_path=${S3_PATH}" >> "$GITHUB_OUTPUT" | |
| - name: Publish version | |
| if: ${{ steps.vars.outputs.version != '' }} | |
| working-directory: ${{ env.DOCS_DIR }} | |
| id: publish_version | |
| env: | |
| S3_ROOT: ${{ steps.paths.outputs.s3_root }} | |
| S3_PATH: ${{ steps.paths.outputs.s3_path }} | |
| VERSION: ${{ steps.vars.outputs.version }} | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| echo "Publishing version ${VERSION} to ${S3_ROOT}/${S3_PATH}/archive/${VERSION}" | |
| aws s3 sync . "${S3_ROOT}/${S3_PATH}/archive/${VERSION}" --exclude .buildinfo --exclude .doctrees --delete | |
| echo "published=true" >> "$GITHUB_OUTPUT" | |
| - name: Update versions manifest in S3 | |
| if: ${{ steps.publish_version.outputs.published == 'true' }} | |
| env: | |
| DOCS_BASE_URL: ${{ vars.DOCS_BASE_URL }} | |
| S3_ROOT: ${{ steps.paths.outputs.s3_root }} | |
| S3_PATH: ${{ steps.paths.outputs.s3_path }} | |
| VERSION: ${{ steps.vars.outputs.version }} | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| MANIFEST_URL="${S3_ROOT}/${S3_PATH}/versions1.json" | |
| LOCAL_MANIFEST="/tmp/versions1.json" | |
| # Download existing manifest from S3 | |
| aws s3 cp "${MANIFEST_URL}" "${LOCAL_MANIFEST}" | |
| # Check if version already exists in manifest | |
| if jq -e ".[] | select(.version == \"${VERSION}\")" "${LOCAL_MANIFEST}" > /dev/null 2>&1; then | |
| echo "Version ${VERSION} already exists in manifest, skipping update" | |
| else | |
| echo "Adding version ${VERSION} to manifest" | |
| # Create new version entry and insert after "dev" and "latest" (index 2) | |
| jq --arg version "${VERSION}" \ | |
| --arg url "${DOCS_BASE_URL}/archive/${VERSION}/" \ | |
| '.[0:2] + [{version: $version, url: $url}] + .[2:]' \ | |
| "${LOCAL_MANIFEST}" > "${LOCAL_MANIFEST}.tmp" | |
| mv "${LOCAL_MANIFEST}.tmp" "${LOCAL_MANIFEST}" | |
| # Upload updated manifest to S3 | |
| aws s3 cp "${LOCAL_MANIFEST}" "${MANIFEST_URL}" | |
| echo "✅ Added ${VERSION} to versions1.json" | |
| fi | |
| - name: Publish latest | |
| if: ${{ steps.publish_version.outputs.published == 'true' && steps.vars.outputs.publish_to_latest == 'true' }} | |
| working-directory: ${{ env.DOCS_DIR }} | |
| id: publish_latest | |
| env: | |
| S3_ROOT: ${{ steps.paths.outputs.s3_root }} | |
| S3_PATH: ${{ steps.paths.outputs.s3_path }} | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| echo "Publishing latest to ${S3_ROOT}/${S3_PATH}/latest" | |
| aws s3 sync . "${S3_ROOT}/${S3_PATH}/latest" --exclude .buildinfo --exclude .doctrees --delete | |
| echo "published_latest=true" >> "$GITHUB_OUTPUT" | |
| - name: Publish dev (main branch) | |
| # Publish main branch to 'dev' directory for development docs | |
| # Skip if commit message contains '/skip-dev' anywhere | |
| if: ${{ github.ref == 'refs/heads/main' && !contains(github.event.head_commit.message || '', '/skip-dev') }} | |
| working-directory: ${{ env.DOCS_DIR }} | |
| id: publish_dev | |
| env: | |
| S3_ROOT: ${{ steps.paths.outputs.s3_root }} | |
| S3_PATH: ${{ steps.paths.outputs.s3_path }} | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| echo "Publishing development docs to ${S3_ROOT}/${S3_PATH}/dev" | |
| aws s3 sync . "${S3_ROOT}/${S3_PATH}/dev" --exclude .buildinfo --exclude .doctrees --delete | |
| echo "published=true" >> "$GITHUB_OUTPUT" | |
| - name: Update versions manifest in all archive directories | |
| # Update versions*.json in ALL archive directories so old docs show current version list | |
| # Only run when publishing a version (not for dev builds) | |
| if: ${{ steps.vars.outputs.version != '' }} | |
| working-directory: ${{ env.DOCS_DIR }} | |
| env: | |
| S3_ROOT: ${{ steps.paths.outputs.s3_root }} | |
| S3_PATH: ${{ steps.paths.outputs.s3_path }} | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| # Get list of all archive directories | |
| echo "Updating version manifests in all archive directories..." | |
| ARCHIVE_DIRS=$(aws s3 ls "${S3_ROOT}/${S3_PATH}/archive/" | grep "PRE" | awk '{print $2}' | tr -d '/') | |
| for file in versions.json versions1.json; do | |
| if [[ -f "${file}" ]]; then | |
| for dir in ${ARCHIVE_DIRS}; do | |
| echo "Updating ${file} in archive/${dir}/" | |
| aws s3 cp "${file}" "${S3_ROOT}/${S3_PATH}/archive/${dir}/${file}" || { | |
| echo "::warning::Failed to update ${file} in archive/${dir}" | |
| } | |
| done | |
| fi | |
| done | |
| echo "✅ Version manifests updated in all archive directories" | |
| - name: Collect publish outputs | |
| id: publish | |
| env: | |
| S3_PATH: ${{ steps.paths.outputs.s3_path }} | |
| VERSION: ${{ steps.vars.outputs.version }} | |
| PUBLISHED_VERSION: ${{ steps.publish_version.outputs.published || 'false' }} | |
| PUBLISHED_LATEST: ${{ steps.publish_latest.outputs.published_latest || 'false' }} | |
| PUBLISHED_DEV: ${{ steps.publish_dev.outputs.published || 'false' }} | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| echo "s3_target_path=${S3_PATH}" >> "$GITHUB_OUTPUT" | |
| echo "request_name=Publish docs from ${GITHUB_REPOSITORY}@${GITHUB_SHA:0:8}" >> "$GITHUB_OUTPUT" | |
| echo "published_latest=${PUBLISHED_LATEST}" >> "$GITHUB_OUTPUT" | |
| # Determine what to flush based on what was published | |
| # - Version publish: flush entire path (versions.json updated in all archive dirs) | |
| # - Dev publish only: flush just the dev directory | |
| if [[ "${PUBLISHED_VERSION}" == "true" ]]; then | |
| echo "perform_flush=true" >> "$GITHUB_OUTPUT" | |
| echo "flush_path=${S3_PATH}" >> "$GITHUB_OUTPUT" | |
| echo "::notice::Will flush entire ${S3_PATH} (version publish updates all archives)" | |
| elif [[ "${PUBLISHED_DEV}" == "true" ]]; then | |
| echo "perform_flush=true" >> "$GITHUB_OUTPUT" | |
| echo "flush_path=${S3_PATH}/dev" >> "$GITHUB_OUTPUT" | |
| echo "::notice::Will flush ${S3_PATH}/dev only (dev publish)" | |
| else | |
| echo "perform_flush=false" >> "$GITHUB_OUTPUT" | |
| echo "flush_path=" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Flush Akamai cache | |
| # Only run if cache flush is needed AND Akamai is enabled | |
| if: ${{ steps.publish.outputs.perform_flush == 'true' && vars.DOCS_AKAMAI_ENABLED == 'true' }} | |
| env: | |
| FLUSH_PATH: ${{ steps.publish.outputs.flush_path }} | |
| REQUEST_NAME: ${{ steps.publish.outputs.request_name }} | |
| # Use repository variable or secret for notification emails | |
| # Format: JSON array of email addresses, e.g., '["email1@example.com", "email2@example.com"]' | |
| EMAILS_JSON: ${{ secrets.DOCS_AKAMAI_NOTIFICATION_EMAILS }} | |
| AKAMAI_CLIENT_SECRET: ${{ secrets.DOCS_AKAMAI_CLIENT_SECRET }} | |
| AKAMAI_HOST: ${{ secrets.DOCS_AKAMAI_HOST }} | |
| AKAMAI_ACCESS_TOKEN: ${{ secrets.DOCS_AKAMAI_ACCESS_TOKEN }} | |
| AKAMAI_CLIENT_TOKEN: ${{ secrets.DOCS_AKAMAI_CLIENT_TOKEN }} | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| # Install required tools for Akamai | |
| sudo apt-get update -qq | |
| sudo apt-get install -y -qq jq xsltproc | |
| pip install -q httpie httpie-edgegrid | |
| echo "Flushing Akamai cache for path: ${FLUSH_PATH}" | |
| # Generate Akamai ECCU request XML using the XSLT template | |
| XSLT_TEMPLATE="${GITHUB_WORKSPACE}/.github/workflows/templates/akamai-eccu-flush.xslt" | |
| if [[ ! -f "${XSLT_TEMPLATE}" ]]; then | |
| echo "::error::XSLT template file not found at ${XSLT_TEMPLATE}" | |
| exit 1 | |
| fi | |
| # Process XSLT to generate ECCU request XML | |
| xsltproc --stringparam target-path "${FLUSH_PATH}" "${XSLT_TEMPLATE}" "${XSLT_TEMPLATE}" | \ | |
| sed 's/xmlns:match="x" //' > /tmp/flush.xml | |
| # Prepare Akamai EdgeGrid credentials | |
| echo "[default]" > ~/.edgerc | |
| echo "client_secret = ${AKAMAI_CLIENT_SECRET}" >> ~/.edgerc | |
| echo "host = ${AKAMAI_HOST}" >> ~/.edgerc | |
| echo "access_token = ${AKAMAI_ACCESS_TOKEN}" >> ~/.edgerc | |
| echo "client_token = ${AKAMAI_CLIENT_TOKEN}" >> ~/.edgerc | |
| # Validate and prepare email list JSON | |
| if [[ -n "${EMAILS_JSON}" ]]; then | |
| echo "${EMAILS_JSON}" | jq -c . > /tmp/email-addresses.json || { | |
| echo "::error::Invalid JSON format for AKAMAI_NOTIFICATION_EMAILS" | |
| exit 1 | |
| } | |
| else | |
| echo '[]' > /tmp/email-addresses.json | |
| fi | |
| # Submit ECCU request to Akamai | |
| http --ignore-stdin --auth-type edgegrid -a default: POST :/eccu-api/v1/requests \ | |
| metadata=@"/tmp/flush.xml" \ | |
| propertyName=docs.nvidia.com \ | |
| propertyNameExactMatch=true \ | |
| propertyType=HOST_HEADER \ | |
| requestName="${REQUEST_NAME}" \ | |
| statusUpdateEmails:=@/tmp/email-addresses.json || { | |
| echo "::warning::Failed to flush Akamai cache, but continuing workflow" | |
| # Don't fail the workflow if cache flush fails | |
| } | |
| - name: Summary | |
| if: always() | |
| env: | |
| VERSION: ${{ steps.vars.outputs.version }} | |
| S3_PATH: ${{ steps.paths.outputs.s3_path }} | |
| PUBLISHED_VERSION: ${{ steps.publish_version.outputs.published || 'false' }} | |
| PUBLISHED_LATEST: ${{ steps.publish.outputs.published_latest || 'false' }} | |
| PUBLISHED_DEV: ${{ steps.publish_dev.outputs.published || 'false' }} | |
| CACHE_FLUSHED: ${{ steps.publish.outputs.perform_flush }} | |
| FLUSH_PATH: ${{ steps.publish.outputs.flush_path }} | |
| run: | | |
| echo "## 📚 Documentation Publishing Summary" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### Source" >> $GITHUB_STEP_SUMMARY | |
| echo "- **Workflow Run:** [#${{ github.run_id }}](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### Published To" >> $GITHUB_STEP_SUMMARY | |
| if [[ "${PUBLISHED_VERSION}" == "true" ]]; then | |
| echo "- ✅ **Version:** \`${VERSION}\` → \`s3://.../${S3_PATH}/archive/${VERSION}\`" >> $GITHUB_STEP_SUMMARY | |
| if [[ "${PUBLISHED_LATEST}" == "true" ]]; then | |
| echo "- ✅ **Latest:** \`${VERSION}\` → \`s3://.../${S3_PATH}/latest\` (updated to match release)" >> $GITHUB_STEP_SUMMARY | |
| else | |
| echo "- ⏭️ **Latest:** not updated (manual dispatch or /not-latest flag)" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| fi | |
| if [[ "${PUBLISHED_DEV}" == "true" ]]; then | |
| echo "- ✅ **Dev:** \`s3://.../${S3_PATH}/dev\` (main branch)" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| if [[ "${PUBLISHED_VERSION}" != "true" ]] && [[ "${PUBLISHED_DEV}" != "true" ]]; then | |
| echo "- ⚠️ No documentation was published" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### Cache" >> $GITHUB_STEP_SUMMARY | |
| if [[ "${CACHE_FLUSHED}" == "true" ]]; then | |
| echo "- ✅ Akamai cache flush requested for \`${FLUSH_PATH}\`" >> $GITHUB_STEP_SUMMARY | |
| else | |
| echo "- ⏭️ Cache flush skipped (nothing published or Akamai disabled)" >> $GITHUB_STEP_SUMMARY | |
| fi |