Skip to content
Open
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
6 changes: 6 additions & 0 deletions .github/actionlint.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ self-hosted-runner:
# GitHub supports queued concurrency runs, but the latest actionlint release
# does not yet recognize the concurrency.queue key.
paths:
".github/workflows/build-docs.yml":
ignore:
- 'unexpected key "queue" for "concurrency" section'
".github/workflows/cleanup-pr-previews.yml":
ignore:
- 'unexpected key "queue" for "concurrency" section'
".github/workflows/ci-workflow-health.yml":
ignore:
- 'unexpected key "queue" for "concurrency" section'
35 changes: 7 additions & 28 deletions .github/actions/doc_preview/action.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-FileCopyrightText: Copyright (c) 2024-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#
# SPDX-License-Identifier: Apache-2.0

name: Docs in PRs
description: Preview or clean up docs built from PRs
description: Preview docs built from PRs

# A re-implementation based on the logic of https://github.com/rossjrw/pr-preview-action/blob/41a957c44a456a34718e9bcf825363194db5e6d5/README.md, due to limitations illustrated in NVIDIA/cuda-python#380.

Expand All @@ -18,8 +18,6 @@ inputs:
runs:
using: composite
steps:
# The steps below are executed only when testing in a PR.
# Note: the PR previews will be removed once merged to main or release/* (see below)
- name: Deploy doc preview
if: ${{ github.ref_name != 'main' && !startsWith(github.ref_name, 'release/') }}
uses: JamesIves/github-pages-deploy-action@d92aa235d04922e8f08b40ce78cc5442fcfbfa2f # v4.8.0
Expand All @@ -29,6 +27,11 @@ runs:
folder: ${{ inputs.source-folder }}
target-folder: docs/pr-preview/pr-${{ inputs.pr-number }}/
commit-message: "Deploy doc preview for PR ${{ inputs.pr-number }} (${{ github.sha }})"
# Every PR preview, the main docs deploy, and the coverage deploy commit to
# the shared gh-pages branch. Rebase onto a deployment that landed in the
# meantime instead of force-pushing over it, which the branch ruleset
# rejects (and which used to discard the other deployment).
force: false

- name: Leave a comment after deployment
if: ${{ github.ref_name != 'main' && !startsWith(github.ref_name, 'release/') }}
Expand All @@ -45,27 +48,3 @@ runs:
| <br> https://nvidia.github.io/cuda-python/pr-preview/pr-${{ inputs.pr-number }}/cuda-bindings/ <br>
| <br> https://nvidia.github.io/cuda-python/pr-preview/pr-${{ inputs.pr-number }}/cuda-pathfinder/ <br><br>
| <h6><br> Preview will be ready when the GitHub Pages deployment is complete. <br><br></h6>

# The steps below are executed only when building on main or release/*.
- name: Remove doc preview
if: ${{ github.ref_name == 'main' || startsWith(github.ref_name, 'release/') }}
uses: JamesIves/github-pages-deploy-action@d92aa235d04922e8f08b40ce78cc5442fcfbfa2f # v4.8.0
with:
git-config-name: cuda-python-bot
git-config-email: cuda-python-bot@users.noreply.github.com
folder: ${{ inputs.source-folder }}
target-folder: docs/pr-preview/pr-${{ inputs.pr-number }}/
commit-message: "Clean up doc preview for PR ${{ inputs.pr-number }} (${{ github.sha }})"

- name: Leave a comment after removal
if: ${{ github.ref_name == 'main' || startsWith(github.ref_name, 'release/') }}
uses: marocchino/sticky-pull-request-comment@d4d6b0936434b21bc8345ad45a440c5f7d2c40ff # v3.0.3
with:
header: pr-preview
number: ${{ inputs.pr-number }}
hide_and_recreate: true
hide_classify: "OUTDATED"
message: |
Doc Preview CI
:---:
Preview removed because the pull request was closed or merged.
70 changes: 59 additions & 11 deletions .github/workflows/build-docs.yml

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

btw one other thing: I think we have two workflows that have a race condition in cleaning up docs. I suggested @Andy-Jost that we should let the nightly job (cleanup-pr-reviews) be the sole owner, and don't do cleanup in this workflow.

@Andy-Jost do I recall correctly?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've removed the place where cleanup-pr-reviews was called during builds of main and release, so it will only cleanup nightly.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, isolating cleanup in a nightly job makes sense to me.

Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ jobs:
# The build stage could fail but we want the CI to keep moving.
if: ${{ github.repository_owner == 'nvidia' && !cancelled() }}
runs-on: ubuntu-latest
outputs:
deployment-artifact-name: ${{ steps.deployment-metadata.outputs.deployment-artifact-name }}
docs-github-ref: ${{ steps.deployment-metadata.outputs.docs-github-ref }}
pr-number: ${{ steps.deployment-metadata.outputs.pr-number }}
defaults:
run:
shell: bash -el {0}
Expand Down Expand Up @@ -221,11 +225,15 @@ jobs:
if: ${{ !inputs.is-release }}
uses: ./.github/actions/get_pr_number

- name: Set up artifact directories
- name: Record deployment metadata
id: deployment-metadata
run: |
mkdir -p artifacts/docs
# create an empty folder for removal use
mkdir -p artifacts/empty_docs
echo "deployment-artifact-name=docs-deployment-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}" >> "$GITHUB_OUTPUT"
echo "docs-github-ref=${CUDA_PYTHON_DOCS_GITHUB_REF}" >> "$GITHUB_OUTPUT"
echo "pr-number=${PR_NUMBER:-}" >> "$GITHUB_OUTPUT"

- name: Set up artifact directories
run: mkdir -p artifacts/docs

- name: Build all docs
if: ${{ inputs.component == 'all' }}
Expand Down Expand Up @@ -330,6 +338,16 @@ jobs:
path: artifacts/
retention-days: 3

- name: Upload docs deployment payload
if: ${{ inputs.deploy-docs }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: ${{ steps.deployment-metadata.outputs.deployment-artifact-name }}
path: artifacts/docs/
retention-days: 3
include-hidden-files: true
if-no-files-found: error

- name: Upload dry-run docs artifact
if: ${{ !inputs.deploy-docs || (inputs.is-release && inputs.docs-branch != 'gh-pages') }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
Expand All @@ -338,22 +356,52 @@ jobs:
path: artifacts/docs/
retention-days: 3

- name: Deploy or clean up doc preview
if: ${{ inputs.deploy-docs && !inputs.is-release }}
deploy:
name: Deploy docs
# GitHub discards prerequisite artifacts on a new run attempt. If only this
# job fails, use "Re-run all jobs" so the build recreates its payload.
needs: build
if: ${{ inputs.deploy-docs && needs.build.result == 'success' }}
runs-on: ubuntu-latest
# Must match every job that writes to gh-pages.
concurrency:
group: cuda-python-gh-pages-publish
queue: max
cancel-in-progress: false
defaults:
run:
shell: bash -el {0}
steps:
- name: Checkout ${{ github.event.repository.name }}
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 1
ref: ${{ inputs.git-tag }}

- name: Download docs deployment payload
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: ${{ needs.build.outputs.deployment-artifact-name }}
path: artifacts/docs/

- name: Deploy doc preview
if: ${{ !inputs.is-release && github.ref_name != 'main' && !startsWith(github.ref_name, 'release/') }}
uses: ./.github/actions/doc_preview
with:
source-folder: ${{ (github.ref_name != 'main' && 'artifacts/docs') ||
'artifacts/empty_docs' }}
pr-number: ${{ env.PR_NUMBER }}
source-folder: artifacts/docs
pr-number: ${{ needs.build.outputs.pr-number }}

- name: Deploy doc update
if: ${{ inputs.deploy-docs && (github.ref_name == 'main' || inputs.is-release) }}
if: ${{ github.ref_name == 'main' || inputs.is-release }}
uses: JamesIves/github-pages-deploy-action@fa24774553152dd7873cd16ebd8d959b010c5445 # v4.9.0
with:
git-config-name: cuda-python-bot
git-config-email: cuda-python-bot@users.noreply.github.com
branch: ${{ inputs.docs-branch }}
folder: artifacts/docs/
target-folder: docs/
commit-message: "Deploy ${{ (inputs.is-release && 'release') || 'latest' }} docs: ${{ env.CUDA_PYTHON_DOCS_GITHUB_REF }}"
commit-message: "Deploy ${{ (inputs.is-release && 'release') || 'latest' }} docs: ${{ needs.build.outputs.docs-github-ref }}"
clean: false
# Rebase onto concurrent PR-preview or coverage deployments instead of
# force-pushing, which the gh-pages ruleset rejects.
force: false
33 changes: 12 additions & 21 deletions .github/workflows/cleanup-pr-previews.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#
# SPDX-License-Identifier: Apache-2.0

Expand All @@ -9,13 +9,6 @@ on:
# Run every night at 11pm EST (4am UTC during EST, 3am UTC during EDT)
# Using 4am UTC to be safe during EST (Nov-Mar)
- cron: '0 4 * * *'
workflow_dispatch:
inputs:
dry-run:
description: 'Run in dry-run mode (preview only, no changes)'
required: false
default: false
type: boolean

permissions:
contents: write # Required to push changes to gh-pages branch
Expand All @@ -24,6 +17,11 @@ jobs:
cleanup:
name: Clean up stale PR preview folders
runs-on: ubuntu-latest
# Must match every job that writes to gh-pages.
concurrency:
group: cuda-python-gh-pages-publish
queue: max
cancel-in-progress: false
# Only run for NVIDIA org to prevent forks from running this
if: github.repository_owner == 'NVIDIA'
steps:
Expand All @@ -41,28 +39,21 @@ jobs:
git config --global user.email "cuda-python-bot@users.noreply.github.com"

- name: Run PR preview cleanup script
id: cleanup
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
# Determine if we should run in dry-run mode
if [[ "${{ inputs.dry-run }}" == "true" ]]; then
echo "Running in dry-run mode (preview only)"
./ci/cleanup-pr-previews --dry-run
else
echo "Running cleanup with push to gh-pages"
./ci/cleanup-pr-previews --push
fi
GH_PAGES_PUBLISH_LOCK: cuda-python-gh-pages-publish
run: ./ci/cleanup-pr-previews --push

- name: Summary
if: always()
run: |
echo "### PR Preview Cleanup Summary" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
if [[ "${{ inputs.dry-run }}" == "true" ]]; then
echo "✅ Dry-run completed successfully" >> $GITHUB_STEP_SUMMARY
echo "No changes were made to the gh-pages branch" >> $GITHUB_STEP_SUMMARY
if [[ "${{ steps.cleanup.outcome }}" != "success" ]]; then
echo "❌ Cleanup failed; no successful update was confirmed" >> $GITHUB_STEP_SUMMARY
else
echo "✅ Cleanup completed and changes pushed to gh-pages" >> $GITHUB_STEP_SUMMARY
echo "✅ Cleanup completed; gh-pages is up to date" >> $GITHUB_STEP_SUMMARY
fi
echo "" >> $GITHUB_STEP_SUMMARY
echo "Workflow run: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" >> $GITHUB_STEP_SUMMARY
29 changes: 28 additions & 1 deletion .github/workflows/coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -465,7 +465,7 @@ jobs:
if-no-files-found: error

combine-and-deploy:
name: Combine Coverage and Deploy
name: Combine Coverage
needs: [coverage-linux, coverage-windows]
runs-on: ubuntu-latest
if: ${{ always() && github.repository_owner == 'nvidia' }}
Expand Down Expand Up @@ -566,6 +566,30 @@ jobs:
retention-days: 7
include-hidden-files: true

deploy:
name: Deploy Coverage
# GitHub discards prerequisite artifacts on a new run attempt. If only this
# job fails, use "Re-run all jobs" so coverage recreates its payload.
needs: combine-and-deploy
if: ${{ needs.combine-and-deploy.result == 'success' && github.repository_owner == 'nvidia' }}
runs-on: ubuntu-latest
permissions:
contents: write
# Must match every job that writes to gh-pages.
concurrency:
group: cuda-python-gh-pages-publish
queue: max
cancel-in-progress: false
steps:
- name: Checkout ${{ github.event.repository.name }}
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- name: Download combined coverage results
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: coverage-combined
path: docs/coverage/

- name: Deploy to gh-pages
uses: JamesIves/github-pages-deploy-action@fa24774553152dd7873cd16ebd8d959b010c5445 # v4.9.0
with:
Expand All @@ -575,3 +599,6 @@ jobs:
target-folder: docs/
commit-message: "Deploy combined coverage (Linux + Windows): ${{ github.sha }}"
clean: false
# Rebase onto concurrent docs deployments instead of force-pushing,
# which the gh-pages ruleset rejects.
force: false
Loading
Loading