diff --git a/.github/workflows/release-pypi-nightly.yml b/.github/workflows/release-pypi-nightly.yml
index ff8d031aa..f94a316bf 100644
--- a/.github/workflows/release-pypi-nightly.yml
+++ b/.github/workflows/release-pypi-nightly.yml
@@ -14,11 +14,6 @@ on:
description: 'Specific commit SHA to build (leave empty for latest)'
required: false
type: string
- cuda_version:
- description: 'CUDA version (e.g., 129 or 130)'
- required: false
- default: '129'
- type: string
concurrency:
group: release-pypi-nightly-${{ github.ref }}
@@ -112,6 +107,15 @@ jobs:
needs: build-nightly-wheel
runs-on: ubuntu-latest
environment: 'prod'
+ strategy:
+ fail-fast: false
+ # The wheel is CUDA-agnostic and built once — we just register the same
+ # artifact under cu129/sglang/ and cu130/sglang/ wheel indexes so users
+ # can install via either --extra-index-url. Serialize because both matrix
+ # runs clone and push to the same sgl-whl branch.
+ max-parallel: 1
+ matrix:
+ cuda_version: ['129', '130']
steps:
- uses: actions/checkout@v4
@@ -160,12 +164,12 @@ jobs:
python3 scripts/update_nightly_whl_index.py \
--commit-hash ${{ needs.build-nightly-wheel.outputs.commit_hash }} \
--nightly-version ${{ needs.build-nightly-wheel.outputs.nightly_version }} \
- --cuda-version ${{ inputs.cuda_version || '129' }} \
+ --cuda-version ${{ matrix.cuda_version }} \
--build-date ${{ needs.build-nightly-wheel.outputs.build_date }}
- name: Push wheel index
run: |
cd sgl-whl
git add -A
- git diff --staged --quiet || git commit -m "Update nightly wheel index for commit ${{ needs.build-nightly-wheel.outputs.commit_hash }}"
+ git diff --staged --quiet || git commit -m "Update cu${{ matrix.cuda_version }} nightly wheel index for commit ${{ needs.build-nightly-wheel.outputs.commit_hash }}"
git push
diff --git a/scripts/update_nightly_whl_index.py b/scripts/update_nightly_whl_index.py
index 5ac55230c..92d6c50c9 100755
--- a/scripts/update_nightly_whl_index.py
+++ b/scripts/update_nightly_whl_index.py
@@ -42,8 +42,10 @@ def update_wheel_index(
whl_repo_dir = pathlib.Path("sgl-whl")
if not dist_dir.exists():
- print(f"Warning: {dist_dir} does not exist, skipping index update")
- return
+ raise FileNotFoundError(
+ f"{dist_dir} does not exist — the download-artifact step did not "
+ f"populate it; refusing to silently no-op the index update"
+ )
# Format CUDA version with 'cu' prefix if not already present
if not cuda_version.startswith("cu"):
@@ -87,23 +89,21 @@ def update_wheel_index(
# Generate new links for current wheels
new_links = []
for wheel_path in sorted(dist_dir.glob("*.whl")):
- try:
- filename = wheel_path.name
- sha256 = compute_sha256(wheel_path)
+ filename = wheel_path.name
+ sha256 = compute_sha256(wheel_path)
- # URL format: {base_url}/{release_tag}/{filename}#sha256={hash}
- wheel_url = f"{base_url}/{release_tag}/{filename}#sha256={sha256}"
- link = f'{filename}
'
+ # URL format: {base_url}/{release_tag}/{filename}#sha256={hash}
+ wheel_url = f"{base_url}/{release_tag}/{filename}#sha256={sha256}"
+ link = f'{filename}
'
- new_links.append(link)
- print(f" Added: {filename}")
- except Exception as e:
- print(f" Error processing {wheel_path.name}: {e}")
- continue
+ new_links.append(link)
+ print(f" Added: {filename}")
if not new_links:
- print(" No new wheels to add")
- return
+ raise RuntimeError(
+ f"No wheels found in {dist_dir} — index update for {cuda_version} "
+ f"would be a no-op; failing loudly instead of pushing an empty change"
+ )
# Combine existing and new links (new links first for latest)
all_links = new_links + existing_links