Skip to content

Commit 03b8746

Browse files
committed
Document shared maintenance and explicit release-branch backports
Signed-off-by: Ralf W. Grosse-Kunstleve <rgrossekunst@nvidia.com>
1 parent cce0618 commit 03b8746

10 files changed

Lines changed: 377 additions & 113 deletions

File tree

‎.github/RELEASE-bindings.md‎

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
<!--
2+
SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3+
SPDX-License-Identifier: Apache-2.0
4+
-->
5+
6+
# Releasing CUDA bindings
7+
8+
## Choose the release scope and source
9+
10+
Develop the current and maintenance CUDA major lines together on `main`, in
11+
the two package roots listed in [`ci/versions.yml`](../ci/versions.yml).
12+
Release each line independently. A bindings release also needs its matching
13+
`cuda-python` metapackage release; it does not require a release of the other
14+
CUDA major, `cuda-core`, or `cuda-pathfinder`.
15+
16+
Major-line maintenance may include selected API, Python, platform, or other
17+
compatibility changes. Decide those changes explicitly and describe them in
18+
the release notes. Once a patch release is frozen, admit only its approved
19+
fixes and release prerequisites. Do not infer patch-release scope solely
20+
from the registry's `maintenance` role.
21+
22+
For an ordinary release, select a tested commit on `main`. If stabilization
23+
must continue while development advances, create a short release branch such
24+
as `release/bindings-12.9.11` from the chosen commit. For an emergency after a
25+
release, start from its exact tag, provided that tag contains the new package
26+
layout. For the first release after this transition, use a validated commit
27+
containing both roots; do not resume development on the historical `12.9.x`
28+
branch. Keep the package layout and release tooling together on the branch.
29+
30+
Record the source commit, intended tag, selected package root, release owner,
31+
and accepted changes in the release checklist. A branch is a temporary scope
32+
boundary, not a separate long-term home for shared infrastructure.
33+
34+
## Move fixes between integration and release branches
35+
36+
Prefer a reviewed fix on `main`, then backport it to the selected release
37+
branch. Run **CI: Backport a merged PR to a release branch** from the Actions
38+
tab on `main`, supplying the merged PR number and one existing target branch.
39+
The workflow opens a PR; it does not merge or release the result. Inspect the
40+
diff, request CI using the normal PR approval procedure, and review it before
41+
merging. Workflow-file changes require a manual backport with appropriate
42+
credentials. Conflicts and toolkit-specific generated changes require an
43+
explicitly reviewed adaptation.
44+
45+
If urgency requires a fix on the release branch first, link a follow-up PR
46+
reconciling the fix back into `main` before closing the release checklist. In either
47+
direction, assess both bindings roots and record why a change applies to one
48+
or both. Regenerate affected generated files from the intended toolkit and
49+
cybind inputs instead of blindly copying generated output between majors.
50+
See the [shared maintenance policy](../ci/README.md#maintaining-both-bindings-roots).
51+
52+
## Validate and publish the selected line
53+
54+
1. Finalize the bindings and metapackage release notes, dependency constraints,
55+
and selected toolkit pin in the release source tree. The registry and
56+
packaging metadata must agree. Run the CI-tool suite and pre-commit checks.
57+
2. Test the candidate through a reviewed PR or manual CI dispatch on its
58+
branch. Normal development CI includes dependent packages and may cover
59+
both majors. Resolve failures in affected code before selecting the tag.
60+
3. Create the approved immutable `vX.Y.Z` tag at the selected source commit.
61+
The tag-triggered CI selects that line's bindings and metapackage, validates
62+
them with the published Pathfinder dependency, and builds release artifacts.
63+
The tag does not have to be on `main`. Wait for this exact tag's CI to pass.
64+
4. Run **CI: Release** with `release-action=dry-run`, the tag, and
65+
`component=cuda-bindings`; repeat for `cuda-python`. Leave `run-id` blank
66+
to exercise automatic lookup, and leave `dry-run-docs-branch` blank to avoid
67+
deploying docs. The workflow verifies a successful tag-triggered CI run
68+
with the exact source SHA, validates artifacts, and builds docs.
69+
5. Review the dry runs, then separately approve and run `full-release` for
70+
each component under the team's release procedure. A successful candidate
71+
rehearsal or ordinary branch CI is not a substitute for exact-tag CI.
72+
6. Finish post-release QA and announcements, return every applicable fix to
73+
`main`, and close the stabilization effort. Retain immutable tags and the
74+
branch history needed for diagnosis.
75+
76+
The workflow revision used for a release is its **control revision**; the
77+
tagged commit is its **source revision**. Record both and the artifact CI run
78+
ID. Release routing uses the package layout and toolkit settings in
79+
`ci/versions.yml` at the release tag. The current tooling requires a valid
80+
schema-2 registry in that source, for both dry runs and publication, including
81+
Core and Pathfinder releases. Tags from before this registry was introduced
82+
require compatible historical tooling; the current workflow configuration
83+
cannot supply missing tagged configuration. Published releases remain unchanged.
84+
85+
In **CI: Release**, normal releases require each component's exact-version,
86+
nonempty release notes in the tagged source. The `cuda-python` metapackage requires its own notes.
87+
Notes from the workflow control revision or a different component cannot fill
88+
a gap. Preserve the existing exemption for `.postN` releases, which do not
89+
require new notes.
90+
91+
Local synthetic tags used in publication-incapable rehearsals must remain local;
92+
they do not authorize publishing a package, creating a remote tag, or moving
93+
an existing tag.

‎.github/dependabot.yml‎

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -52,23 +52,3 @@ updates:
5252
time: "09:00"
5353
timezone: "America/Los_Angeles"
5454
open-pull-requests-limit: 1
55-
56-
# GitHub Actions updates targeting the 12.9.x branch
57-
- package-ecosystem: github-actions
58-
directory: /
59-
target-branch: "12.9.x" # keep in sync with backport_branch in ci/versions.yml
60-
schedule:
61-
interval: "monthly"
62-
time: "09:00"
63-
timezone: "America/Los_Angeles"
64-
65-
# Keep churn down: only one open PR from this ecosystem at a time
66-
open-pull-requests-limit: 1
67-
68-
groups:
69-
actions-monthly:
70-
applies-to: version-updates
71-
patterns: ["*"]
72-
update-types: ["major", "minor", "patch"]
73-
74-
labels: [CI/CD, dependencies]

‎.github/workflows/backport.yml‎

Lines changed: 57 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -2,75 +2,84 @@
22
#
33
# SPDX-License-Identifier: Apache-2.0
44

5-
name: "CI: Backport the merged PR"
5+
name: "CI: Backport a merged PR to a release branch"
66

77
on:
8-
pull_request_target:
9-
types: [closed, labeled]
10-
branches:
11-
- main
128
workflow_dispatch:
139
inputs:
1410
backport-branch:
15-
description: "Branch to backport commits onto"
16-
required: false
11+
description: "Existing release branch to receive the fix"
12+
required: true
1713
type: string
1814
pull-request:
19-
description: "PR to backport"
15+
description: "Merged PR to backport"
2016
required: true
2117
type: number
2218

23-
2419
permissions:
25-
contents: write # so it can comment
26-
pull-requests: write # so it can create pull requests
20+
contents: write
21+
pull-requests: write
22+
23+
concurrency:
24+
group: backport-${{ inputs.pull-request }}-${{ inputs.backport-branch }}
25+
cancel-in-progress: false
2726

2827
jobs:
29-
backport-from-pr:
30-
name: Backport directly from a pull request
31-
if: ${{ github.repository_owner == 'nvidia' &&
32-
github.event.pull_request.merged == true &&
33-
contains( github.event.pull_request.labels.*.name, 'to-be-backported')
34-
}}
28+
backport:
29+
if: github.repository == 'NVIDIA/cuda-python'
3530
runs-on: ubuntu-latest
3631
steps:
37-
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
32+
- name: Checkout workflow source
33+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
34+
with:
35+
ref: ${{ github.sha }}
3836

39-
- name: Load branch name
40-
id: get-branch
37+
- name: Validate source PR and target branch
38+
env:
39+
GH_TOKEN: ${{ github.token }}
40+
GH_REPO: ${{ github.repository }}
41+
DEFAULT_BRANCH: ${{ github.event.repository.default_branch }}
42+
BACKPORT_BRANCH: ${{ inputs.backport-branch }}
43+
PR_NUMBER: ${{ inputs.pull-request }}
4144
run: |
42-
OLD_BRANCH=$(yq '.backport_branch' ci/versions.yml)
43-
echo "OLD_BRANCH=${OLD_BRANCH}" >> $GITHUB_ENV
45+
set -euo pipefail
46+
if [[ ! "$PR_NUMBER" =~ ^[1-9][0-9]*$ ]]; then
47+
echo "::error::The source PR must be a positive integer."
48+
exit 1
49+
fi
50+
if ! git check-ref-format "refs/heads/$BACKPORT_BRANCH"; then
51+
echo "::error::Provide one exact target branch name."
52+
exit 1
53+
fi
54+
if [[ "$BACKPORT_BRANCH" == "$DEFAULT_BRANCH" ]]; then
55+
echo "::error::Choose a release branch, not the default branch."
56+
exit 1
57+
fi
58+
if ! git ls-remote --exit-code --heads origin "refs/heads/$BACKPORT_BRANCH"; then
59+
echo "::error::The target branch must already exist in this repository."
60+
exit 1
61+
fi
62+
if [[ "$(gh pr view "$PR_NUMBER" --repo "$GH_REPO" --json state --jq .state)" != MERGED ]]; then
63+
echo "::error::The source PR must already be merged in this repository."
64+
exit 1
65+
fi
4466
45-
- name: Create backport pull requests
67+
# Workflow-file changes need a manual backport because GITHUB_TOKEN
68+
# cannot push them. Generated changes need target-specific regeneration.
69+
- name: Create backport pull request
70+
id: backport
4671
uses: korthout/backport-action@8560fb503c275d433c56f05a2f64850093baa9f7 # v4.7.0
4772
with:
73+
source_pr_number: ${{ inputs.pull-request }}
74+
target_branches: ${{ inputs.backport-branch }}
75+
# The explicit target must not be combined with source PR labels.
76+
label_pattern: ''
4877
copy_assignees: true
49-
copy_labels_pattern: true
78+
copy_labels_pattern: '^(?!to-be-backported$|backport ).*'
5079
copy_requested_reviewers: true
51-
target_branches: ${{ env.OLD_BRANCH }}
52-
backport-to-branch:
53-
name: Backport a specific PR against a specific branch
54-
if: github.repository_owner == 'nvidia' && github.event_name == 'workflow_dispatch'
55-
runs-on: ubuntu-latest
56-
steps:
57-
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
5880

59-
- name: Load branch from environment name
60-
if: inputs.backport-branch == null
81+
- name: Require successful backport
82+
if: steps.backport.outputs.was_successful != 'true'
6183
run: |
62-
BACKPORT_BRANCH=$(yq '.backport_branch' ci/versions.yml)
63-
echo "BACKPORT_BRANCH=${BRANCH}" >> $GITHUB_ENV
64-
65-
- name: Load branch name from input
66-
if: inputs.backport-branch != null
67-
run: echo "BACKPORT_BRANCH=${{ inputs.backport-branch }}" >> $GITHUB_ENV
68-
69-
- name: Create backport pull requests
70-
uses: korthout/backport-action@8560fb503c275d433c56f05a2f64850093baa9f7 # v4.7.0
71-
with:
72-
copy_assignees: true
73-
copy_labels_pattern: true
74-
copy_requested_reviewers: true
75-
target_branches: ${{ env.BACKPORT_BRANCH }}
76-
source_pr_number: ${{ inputs.pull-request }}
84+
echo "::error::Backport failed; resolve the conflict or prepare the target-specific fix manually."
85+
exit 1

‎AGENTS.md‎

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,34 @@ guide for package-specific conventions and workflows.
88
## Package map
99

1010
- `cuda_pathfinder/`: Pure-Python library discovery and loading utilities.
11-
- `cuda_bindings_13/`: Low-level CUDA host API bindings (Cython-heavy).
11+
- `cuda_bindings_13/`: Current low-level CUDA host API bindings (Cython-heavy).
12+
- `cuda_bindings_12/`: CUDA 12 maintenance bindings release line.
1213
- `cuda_core/`: High-level Pythonic CUDA APIs built on top of bindings.
1314
- `cuda_python/`: Metapackage and docs aggregation.
1415

16+
## Synchronized code blocks
17+
18+
Use matching `BEGIN SYNCED <group>` and `END SYNCED <group>` comments for
19+
deliberately duplicated snippets whose contents must remain byte-for-byte
20+
identical. The group name identifies all copies; the boundaries define the
21+
shared snippet, not the surrounding file.
22+
23+
- Before editing a marked block, search from the repository root for its exact
24+
`BEGIN SYNCED <group>` marker, for example with `rg -n -F`. Read every copy
25+
and update them together, including copies outside the current package.
26+
- Compare the complete marked blocks after editing. Also check required
27+
imports and surrounding assumptions, such as relative directory depth,
28+
which may live outside the markers.
29+
- During review, identify groups touched by the diff and compare every copy,
30+
including files absent from the diff. Use the base revision too when markers
31+
were removed or renamed. Report drift, missing boundaries, and newly copied
32+
snippets that omit the markers as review findings.
33+
- Preserve both markers when copying a snippet. If a copy must diverge,
34+
explain why and explicitly revise the group membership; do not remove or
35+
rename a marker merely to conceal drift.
36+
- In the work or review summary, name the groups and files compared, or state
37+
why verification could not be completed.
38+
1539
# Git-derived version lifecycle
1640

1741
Package versions are derived from reachable Git tags by `setuptools-scm`.

‎CONTRIBUTING.md‎

Lines changed: 32 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,8 @@ Thank you for your interest in contributing to CUDA Python! Based on the type of
3434
- [Developer Certificate of Origin (DCO)](#developer-certificate-of-origin-dco)
3535
- [CI infrastructure overview](#ci-infrastructure-overview)
3636
- [CI Pipeline Flow](#ci-pipeline-flow)
37-
- [Pipeline Execution Details](#pipeline-execution-details)
38-
- [Branch-specific Artifact Flow](#branch-specific-artifact-flow)
39-
- [Main Branch](#main-branch)
40-
- [Backport Branches](#backport-branches)
41-
- [Key Infrastructure Details](#key-infrastructure-details)
37+
- [CUDA-major Artifact Flow](#cuda-major-artifact-flow)
38+
- [Release Branches](#release-branches)
4239
- [Code coverage](#code-coverage)
4340

4441

@@ -374,36 +371,36 @@ The CUDA Python project uses a comprehensive CI pipeline that builds, tests, and
374371

375372
The CI pipeline diagram is maintained as Mermaid source in [`ci/ci-pipeline.mmd`](ci/ci-pipeline.mmd).
376373

377-
### Pipeline Execution Details
378-
379-
**Parallel Execution**: The CI pipeline leverages parallel execution to optimize build and test times:
380-
- **Build Stage**: Different architectures/operating systems (linux-64, linux-aarch64, win-64) are built in parallel across their respective runners
381-
- **Test Stage**: Different architectures/operating systems/CUDA versions are tested in parallel; documentation preview is also built in parallel with testing
382-
383-
### Branch-specific Artifact Flow
384-
385-
#### Main Branch
386-
- **Build** → **Test** → **Documentation** → **Potential Release**
387-
- Artifacts stored as `{component}-python{version}-{platform}-{sha}`
388-
- Full test coverage across all platforms and CUDA versions
389-
- **Artifact flow out**: `cuda-pathfinder` artifacts → backport branches
390-
391-
#### Backport Branches
392-
- **Build** → **Test** → **Backport PR Creation**
393-
- Artifacts used for validation before creating backport pull requests
394-
- Maintains compatibility with older CUDA versions
395-
- **Artifact flow in**: `cuda-pathfinder` artifacts ← main branch
396-
- **Artifact flow out**: older `cuda-bindings` artifacts → main branch
397-
398-
### Key Infrastructure Details
399-
400-
- **Self-hosted runners**: Used for Linux builds and GPU testing (more resources, faster builds)
401-
- **GitHub-hosted runners**: Used for Windows builds and general tasks
402-
- **Artifact retention**: 30 days for GitHub Artifacts (wheels, docs, tests)
403-
- **Cache retention**: GitHub Cache for build dependencies and environments
404-
- **Security**: All commits must be signed, untrusted code blocked
405-
- **Parallel execution**: Matrix builds across Python versions and platforms
406-
- **Component isolation**: Each component (core, bindings, pathfinder, python) can be built/released independently
374+
The [CI workflow](.github/workflows/ci.yml) defines the supported platform,
375+
Python, and CUDA matrices. Build and test jobs run in parallel across their
376+
configured runners. Package selection and artifact validation are shared
377+
through the [CI tools](ci/README.md).
378+
379+
### CUDA-major Artifact Flow
380+
381+
- CUDA 12.9 bindings live in `cuda_bindings_12/`; CUDA 13 bindings live in
382+
`cuda_bindings_13/`. The registry assigns their maintenance and current roles.
383+
- Development CI builds changed roots and affected dependents, reusing a
384+
validated baseline for unaffected roots. Shared changes and scheduled runs
385+
cover both CUDA majors.
386+
- A bindings tag selects one line's bindings and metapackage. Its release
387+
validation uses published Pathfinder and does not require a CUDA Core or
388+
other-major release.
389+
- Artifacts identify their Python version, toolkit, platform, and source SHA
390+
where applicable. Release workflows require the exact tag's successful CI.
391+
392+
### Release Branches
393+
394+
`main` integrates changes for both supported majors. Short release branches
395+
can stabilize a selected release or carry urgent fixes while development
396+
continues. Return applicable fixes to `main` and assess both source roots.
397+
The historical `12.9.x` branch is retained for diagnosis of old releases;
398+
new main CI and releases do not fetch package artifacts from that branch.
399+
400+
The [bindings release guide](.github/RELEASE-bindings.md) covers release scope,
401+
manual backport automation, source and control revisions, and validation.
402+
The [CUDA 12 maintenance guide](cuda_bindings_12/MAINTENANCE.md) links the
403+
shared regeneration and cross-root review policy.
407404

408405
## Code coverage
409406

0 commit comments

Comments
 (0)