Skip to content

Commit 38ec15d

Browse files
authored
ci: consolidate release publishing flow (#1752)
* ci: consolidate release publishing flow Run the release workflow through TestPyPI and PyPI in one pass so release managers do not need to rerun it with a destination selector. Update the release docs to match the streamlined flow. Made-with: Cursor * ci: preserve automatic release run detection Keep the consolidated release flow aligned with upstream's automatic run lookup after the rebase so the workflow inputs and release docs stay consistent. Made-with: Cursor
1 parent e6b553d commit 38ec15d

2 files changed

Lines changed: 46 additions & 54 deletions

File tree

.github/RELEASE-core.md

Lines changed: 7 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -123,41 +123,21 @@ Pushing the tag triggers a CI run automatically. Monitor it in the
123123

124124
## Upload wheels to PyPI
125125

126-
This is a two-stage process: first publish to TestPyPI, verify, then
127-
publish to PyPI.
128-
129-
### Stage 1: TestPyPI
126+
This is a single `CI: Release` workflow run with two sequential stages:
127+
publish to TestPyPI, then publish the same wheel set to PyPI.
130128

131129
1. Go to **Actions > CI: Release** and run the workflow with:
132130
- **Component**: `cuda-core`
133131
- **The release git tag**: `cuda-core-v0.6.0`
134-
- **The GHA run ID that generated validated artifacts**: This is the
135-
run ID of the successful tag-triggered CI run from the previous step.
136-
You can find it in the URL when viewing the run in the Actions tab
137-
(e.g. `https://github.com/NVIDIA/cuda-python/actions/runs/123456789`
138-
— the run ID is `123456789`).
139-
- **Which wheel index to publish to**: `testpypi`
132+
140133
The workflow automatically looks up the successful tag-triggered CI run
141134
for the selected release tag.
142135

143-
2. Wait for the workflow to complete.
144-
145-
3. Verify the TestPyPI upload by installing and running tests from a
146-
checked-out copy of the repository:
147-
148-
```bash
149-
pip install -i https://test.pypi.org/simple/ \
150-
--extra-index-url https://pypi.org/simple/ \
151-
cuda-core==0.6.0
152-
cd cuda_core/tests && pytest
153-
```
154-
155-
### Stage 2: PyPI
156-
157-
Once TestPyPI verification passes, rerun the same workflow with:
158-
- **Which wheel index to publish to**: `pypi`
136+
2. Wait for the workflow to complete. It will:
137+
- publish the selected wheels to TestPyPI
138+
- publish the same wheel set to PyPI
159139

160-
After completion, verify:
140+
3. After completion, verify the final PyPI upload:
161141

162142
```bash
163143
pip install cuda-core==0.6.0

.github/workflows/release.yml

Lines changed: 39 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44

55
name: "CI: Release"
66

7-
# Manually-triggered release workflow. Creates a release draft if one doesn't exist for the given tag, or uses existing draft.
7+
# Manually-triggered release workflow. Creates a release draft if one doesn't exist
8+
# for the given tag, or uses an existing draft, then publishes the selected wheels
9+
# to TestPyPI followed by PyPI.
810

911
on:
1012
workflow_dispatch:
@@ -28,13 +30,6 @@ on:
2830
required: false
2931
type: string
3032
default: ""
31-
wheel-dst:
32-
description: "Which wheel index to publish to?"
33-
required: true
34-
type: choice
35-
options:
36-
- testpypi
37-
- pypi
3833

3934
defaults:
4035
run:
@@ -60,7 +55,7 @@ jobs:
6055
echo "Auto-detecting successful tag-triggered run ID for tag: ${{ inputs.git-tag }}"
6156
RUN_ID=$(./ci/tools/lookup-run-id "${{ inputs.git-tag }}" "${{ github.repository }}")
6257
echo "Auto-detected run ID: $RUN_ID"
63-
echo "run-id=$RUN_ID" >> $GITHUB_OUTPUT
58+
echo "run-id=$RUN_ID" >> "$GITHUB_OUTPUT"
6459
6560
check-tag:
6661
runs-on: ubuntu-latest
@@ -74,17 +69,11 @@ jobs:
7469
env:
7570
GH_TOKEN: ${{ github.token }}
7671
run: |
77-
tags=
78-
for i in $(gh release list -R ${{ github.repository }} --json tagName --jq '.[]| .tagName'); do
79-
tags+=( $i )
80-
done
81-
is_draft=
82-
for i in $(gh release list -R ${{ github.repository }} --json isDraft --jq '.[]| .isDraft'); do
83-
is_draft+=( $i )
84-
done
72+
mapfile -t tags < <(gh release list -R "${{ github.repository }}" --json tagName --jq '.[] | .tagName')
73+
mapfile -t is_draft < <(gh release list -R "${{ github.repository }}" --json isDraft --jq '.[] | .isDraft')
8574
8675
found=0
87-
for idx in ${!tags[@]}; do
76+
for idx in "${!tags[@]}"; do
8877
if [[ "${tags[$idx]}" == "${{ inputs.git-tag }}" ]]; then
8978
echo "found existing release for ${{ inputs.git-tag }}"
9079
found=1
@@ -134,16 +123,16 @@ jobs:
134123
run-id: ${{ needs.determine-run-id.outputs.run-id }}
135124
component: ${{ inputs.component }}
136125

137-
publish-wheels:
138-
name: Publish wheels
126+
publish-testpypi:
127+
name: Publish wheels to TestPyPI
139128
runs-on: ubuntu-latest
140129
needs:
141130
- check-tag
142131
- determine-run-id
143132
- doc
144133
environment:
145-
name: ${{ inputs.wheel-dst }}
146-
url: https://${{ (inputs.wheel-dst == 'testpypi' && 'test.') || '' }}pypi.org/p/${{ inputs.component }}/
134+
name: testpypi
135+
url: https://test.pypi.org/${{ inputs.component != 'all' && format('p/{0}/', inputs.component) || '' }}
147136
permissions:
148137
id-token: write
149138
steps:
@@ -160,14 +149,37 @@ jobs:
160149
run: |
161150
./ci/tools/validate-release-wheels "${{ inputs.git-tag }}" "${{ inputs.component }}" "dist"
162151
163-
- name: Publish package distributions to PyPI
164-
if: ${{ inputs.wheel-dst == 'pypi' }}
165-
uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # v1.13.0
166-
167152
- name: Publish package distributions to TestPyPI
168-
if: ${{ inputs.wheel-dst == 'testpypi' }}
169153
uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # v1.13.0
170154
with:
171155
repository-url: https://test.pypi.org/legacy/
172156

157+
publish-pypi:
158+
name: Publish wheels to PyPI
159+
runs-on: ubuntu-latest
160+
needs:
161+
- determine-run-id
162+
- publish-testpypi
163+
environment:
164+
name: pypi
165+
url: https://pypi.org/${{ inputs.component != 'all' && format('p/{0}/', inputs.component) || '' }}
166+
permissions:
167+
id-token: write
168+
steps:
169+
- name: Checkout Source
170+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
171+
172+
- name: Download component wheels
173+
env:
174+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
175+
run: |
176+
./ci/tools/download-wheels "${{ needs.determine-run-id.outputs.run-id }}" "${{ inputs.component }}" "${{ github.repository }}" "dist"
177+
178+
- name: Validate wheel versions for release tag
179+
run: |
180+
./ci/tools/validate-release-wheels "${{ inputs.git-tag }}" "${{ inputs.component }}" "dist"
181+
182+
- name: Publish package distributions to PyPI
183+
uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # v1.13.0
184+
173185
# TODO: add another job to make the release leave the draft state?

0 commit comments

Comments
 (0)