Skip to content
Draft
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
25 changes: 14 additions & 11 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# 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

Expand All @@ -19,8 +19,8 @@ on:
- cuda-pathfinder
- cuda-python
- all
git-tag:
description: "The release git tag"
version:
description: "Version to release (e.g. 1.2.3)"
required: true
type: string
run-id:
Expand All @@ -39,6 +39,9 @@ on:
- testpypi
- pypi

env:
TAG: ${{ fromJSON('{"cuda_bindings":"v","cuda_core":"cuda-core-v","cuda_pathfinder":"cuda-pathfinder-v","cuda_python":"v","all":"v"}')[inputs.component] }}${{ inputs.version }}

defaults:
run:
shell: bash --noprofile --norc -xeuo pipefail {0}
Expand All @@ -64,8 +67,8 @@ jobs:
echo "Using provided run ID: ${{ inputs.run-id }}"
echo "run-id=${{ inputs.run-id }}" >> $GITHUB_OUTPUT
else
echo "Auto-detecting run ID for tag: ${{ inputs.git-tag }}"
RUN_ID=$(./ci/tools/lookup-run-id "${{ inputs.git-tag }}" "${{ github.repository }}")
echo "Auto-detecting run ID for tag: ${{ env.TAG }}"
RUN_ID=$(./ci/tools/lookup-run-id "${{ env.TAG }}" "${{ github.repository }}")
echo "Auto-detected run ID: $RUN_ID"
echo "run-id=$RUN_ID" >> $GITHUB_OUTPUT
fi
Expand Down Expand Up @@ -93,8 +96,8 @@ jobs:

found=0
for idx in ${!tags[@]}; do
if [[ "${tags[$idx]}" == "${{ inputs.git-tag }}" ]]; then
echo "found existing release for ${{ inputs.git-tag }}"
if [[ "${tags[$idx]}" == "${{ env.TAG }}" ]]; then
echo "found existing release for ${{ env.TAG }}"
found=1
if [[ "${is_draft[$idx]}" != "true" ]]; then
echo "the release note is not in draft state"
Expand All @@ -104,8 +107,8 @@ jobs:
fi
done
if [[ "$found" == 0 ]]; then
echo "no release found for ${{ inputs.git-tag }}, creating draft release"
gh release create "${{ inputs.git-tag }}" --draft --repo "${{ github.repository }}" --title "Release ${{ inputs.git-tag }}" --notes "Release ${{ inputs.git-tag }}"
echo "no release found for ${{ env.TAG }}, creating draft release"
gh release create "${{ env.TAG }}" --draft --repo "${{ github.repository }}" --title "Release ${{ env.TAG }}" --notes "Release ${{ env.TAG }}"
fi

doc:
Expand All @@ -124,7 +127,7 @@ jobs:
with:
build-ctk-ver: ${{ inputs.build-ctk-ver }}
component: ${{ inputs.component }}
git-tag: ${{ inputs.git-tag }}
git-tag: ${{ vars.TAG }}
run-id: ${{ needs.determine-run-id.outputs.run-id }}
is-release: true

Expand All @@ -139,7 +142,7 @@ jobs:
secrets: inherit
uses: ./.github/workflows/release-upload.yml
with:
git-tag: ${{ inputs.git-tag }}
git-tag: ${{ vars.TAG }}
run-id: ${{ needs.determine-run-id.outputs.run-id }}
component: ${{ inputs.component }}

Expand Down
47 changes: 47 additions & 0 deletions .github/workflows/tag-release.yml
Copy link
Member

Choose a reason for hiding this comment

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

@mdboom @rwgk I like this file. Can we keep it so that no members on the team would ever need to manually push a tag to this repo?

Copy link
Member

Choose a reason for hiding this comment

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

I think this file alone (without the change in the other file) is composable with #1606.

  • We run this new workflow to generate a tag
  • The tag creation triggers the CI

Copy link
Collaborator

Choose a reason for hiding this comment

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

That works for me. It's a bit on the heavy-handed side just for the tagging, but if we fold in some easy safety features I can see good value:

  • pull-down for: cuda-pathfinder, cuda-bindings, cuda-core
  • pull-down for: bump patch, bump minor, bump major
  • compute the version number
  • validate that X.Y.Z-notes.rst exists
  • validate that corresponding the nv-versions.json entry exits

That would prevent oversights like we had in the release of cuda-bindings 13.1.0 (missing release notes under cuda-python).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@leofang: At a minimum we need to update this so it doesn't create an empty commit (which is no longer needed after #1606). And if we do that, we also have ways to fix the race condition problem.

The race condition is: I wanted to create a release, so I go to the page to trigger this workflow, and then someone else merges a PR while the workflow is waiting to run. Now we've made a release with unintended content.

If we require the user of this workflow to specify a commit hash to tag, we avoid the race condition.

FWIW, even those the GitHub UI for creating a release tag doesn't do everything we need, has the ability to specify a commit in their design since it's a real issue:

image

And then the other thing to test is:

  • The tag creation triggers the CI

There are a bunch of rules about GitHub workflows triggering other workflows (to prevent infinite loops etc). This may not work -- we will need to test.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

As I think about this further, another downside is that this workflow could only ever /validate/ the kinds of things @rwgk is suggesting. (If it needs to add a commit to add content to the repo, we are back to the problems outlined in the OP). Is it really useful to have a workflow just to validate these things when instead we could write a local script that could actually /do/ those things and then add the tag? (and the push would correctly and helpfully fail if main had been updated in the meantime)?

Copy link
Member

Choose a reason for hiding this comment

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

  • The tag creation triggers the CI

There are a bunch of rules about GitHub workflows triggering other workflows (to prevent infinite loops etc). This may not work -- we will need to test.

Isn't this just handled by #1606?

Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#
# SPDX-License-Identifier: Apache-2.0

name: Tag Release

on:
workflow_dispatch:
inputs:
component:
description: "Component to tag (cuda_bindings implies cuda_python as well)"
required: true
type: choice
options:
- cuda_bindings
- cuda_core
- cuda_pathfinder
version:
description: "Version to tag (e.g. 1.2.3)"
required: true
type: string

jobs:
tag-release:
runs-on: ubuntu-latest
permissions:
contents: write
env:
TAG: ${{ fromJSON('{"cuda_bindings":"v","cuda_core":"cuda-core-v","cuda_pathfinder":"cuda-pathfinder-v"}')[inputs.component] }}${{ inputs.version }}
steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Configure git
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"

- name: Create empty commit and tag
run: |
git commit --allow-empty -m "Release ${TAG}"
git tag "${TAG}"

- name: Push commit and tag
run: |
git push origin main
git push origin "${TAG}"