Unverified Commit 8fd41eae authored by Kangyan-Zhou's avatar Kangyan-Zhou Committed by GitHub
Browse files

Improve bot release workflow (#11240)

parent 0cd1996e
......@@ -26,14 +26,12 @@ jobs:
with:
python-version: '3.10'
- name: Configure Git
- name: Configure Git and branch
run: |
git config user.name "sglang-bot"
git config user.email "sglang-bot@users.noreply.github.com"
- name: Create new branch
run: |
BRANCH_NAME="bot/bump-kernel-version-${{ github.event.inputs.new_version }}"
RANDOM_SUFFIX=$(echo $RANDOM | md5sum | head -c 4)
BRANCH_NAME="bot/bump-kernel-version-${{ github.event.inputs.new_version }}-${RANDOM_SUFFIX}"
git checkout -b "$BRANCH_NAME"
echo "BRANCH_NAME=$BRANCH_NAME" >> $GITHUB_ENV
......@@ -41,44 +39,8 @@ jobs:
run: |
python scripts/release/bump_kernel_version.py "${{ github.event.inputs.new_version }}"
- name: Commit changes
run: |
git add -A
git commit -m "chore: bump sgl-kernel version to ${{ github.event.inputs.new_version }}
This commit updates the sgl-kernel version across all relevant files:
- sgl-kernel/pyproject.toml
- sgl-kernel/pyproject_cpu.toml
- sgl-kernel/pyproject_rocm.toml
- sgl-kernel/python/sgl_kernel/version.py
🤖 Generated with GitHub Actions"
- name: Push changes
run: |
git push origin "$BRANCH_NAME"
- name: Create Pull Request
- name: Commit and create PR
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_TOKEN: ${{ secrets.GH_PAT_FOR_TAGGING }}
run: |
gh pr create \
--title "chore: bump sgl-kernel version to ${{ github.event.inputs.new_version }}" \
--body "## Summary
This PR bumps the sgl-kernel version to \`${{ github.event.inputs.new_version }}\` across all relevant files.
## Files Updated
- sgl-kernel/pyproject.toml
- sgl-kernel/pyproject_cpu.toml
- sgl-kernel/pyproject_rocm.toml
- sgl-kernel/python/sgl_kernel/version.py
## Testing
- [ ] Verify all version strings are updated correctly
- [ ] Test kernel installation with new version
- [ ] Run CI tests
🤖 Generated with GitHub Actions" \
--base main \
--head "$BRANCH_NAME"
bash scripts/release/commit_and_pr.sh "sgl-kernel" "${{ github.event.inputs.new_version }}" "$BRANCH_NAME"
......@@ -26,14 +26,12 @@ jobs:
with:
python-version: '3.10'
- name: Configure Git
- name: Configure Git and branch
run: |
git config user.name "sglang-bot"
git config user.email "sglang-bot@users.noreply.github.com"
- name: Create new branch
run: |
BRANCH_NAME="bot/bump-sglang-version-${{ github.event.inputs.new_version }}"
RANDOM_SUFFIX=$(echo $RANDOM | md5sum | head -c 4)
BRANCH_NAME="bot/bump-sglang-version-${{ github.event.inputs.new_version }}-${RANDOM_SUFFIX}"
git checkout -b "$BRANCH_NAME"
echo "BRANCH_NAME=$BRANCH_NAME" >> $GITHUB_ENV
......@@ -41,54 +39,8 @@ jobs:
run: |
python scripts/release/bump_sglang_version.py "${{ github.event.inputs.new_version }}"
- name: Commit changes
run: |
git add -A
git commit -m "chore: bump SGLang version to ${{ github.event.inputs.new_version }}
This commit updates the SGLang version across all relevant files:
- Makefile
- benchmark/deepseek_v3/README.md
- docker/Dockerfile.rocm
- docs/get_started/install.md
- docs/platforms/amd_gpu.md
- docs/platforms/ascend_npu.md
- python/pyproject.toml
- python/pyproject_other.toml
- python/sglang/version.py
🤖 Generated with GitHub Actions"
- name: Push changes
run: |
git push origin "$BRANCH_NAME"
- name: Create Pull Request
- name: Commit and create PR
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_TOKEN: ${{ secrets.GH_PAT_FOR_TAGGING }}
run: |
gh pr create \
--title "chore: bump SGLang version to ${{ github.event.inputs.new_version }}" \
--body "## Summary
This PR bumps the SGLang version to \`${{ github.event.inputs.new_version }}\` across all relevant files.
## Files Updated
- Makefile
- benchmark/deepseek_v3/README.md
- docker/Dockerfile.rocm
- docs/get_started/install.md
- docs/platforms/amd_gpu.md
- docs/platforms/ascend_npu.md
- python/pyproject.toml
- python/pyproject_other.toml
- python/sglang/version.py
## Testing
- [ ] Verify all version strings are updated correctly
- [ ] Test installation with new version
- [ ] Run CI tests
🤖 Generated with GitHub Actions" \
--base main \
--head "$BRANCH_NAME"
bash scripts/release/commit_and_pr.sh "SGLang" "${{ github.event.inputs.new_version }}" "$BRANCH_NAME"
......@@ -10,7 +10,10 @@ def main():
parser = argparse.ArgumentParser(
description="Bump sgl-kernel version across all relevant files"
)
parser.add_argument("new_version", help="New version (e.g., 0.3.12)")
parser.add_argument(
"new_version",
help="New version (e.g., 0.3.12, 0.3.11rc0, or 0.3.11.post1)",
)
args = parser.parse_args()
version_file = Path("sgl-kernel/python/sgl_kernel/version.py")
......@@ -23,7 +26,7 @@ def main():
Path("sgl-kernel/python/sgl_kernel/version.py"),
]
bump_version(args.new_version, version_file, files_to_update, "kernel")
bump_version(args.new_version, version_file, files_to_update)
if __name__ == "__main__":
......
......@@ -10,7 +10,10 @@ def main():
parser = argparse.ArgumentParser(
description="Bump SGLang version across all relevant files"
)
parser.add_argument("new_version", help="New version (e.g., 0.5.3 or 0.5.3rc0)")
parser.add_argument(
"new_version",
help="New version (e.g., 0.5.4, 0.5.3rc0, or 0.5.3.post1)",
)
args = parser.parse_args()
version_file = Path("python/sglang/version.py")
......@@ -27,7 +30,7 @@ def main():
Path("python/sglang/version.py"),
]
bump_version(args.new_version, version_file, files_to_update, "sglang")
bump_version(args.new_version, version_file, files_to_update)
if __name__ == "__main__":
......
#!/bin/bash
set -e
# Script to commit version bump changes and create a pull request
# Usage: commit_and_pr.sh <version_type> <new_version> <branch_name>
#
# Arguments:
# version_type: "SGLang" or "sgl-kernel"
# new_version: The new version number
# branch_name: The git branch name to push to
VERSION_TYPE="$1"
NEW_VERSION="$2"
BRANCH_NAME="$3"
if [ -z "$VERSION_TYPE" ] || [ -z "$NEW_VERSION" ] || [ -z "$BRANCH_NAME" ]; then
echo "Error: Missing required arguments"
echo "Usage: $0 <version_type> <new_version> <branch_name>"
exit 1
fi
# Get changed files and format them
echo "Getting changed files..."
FILES_LIST=$(git diff --name-only | sed 's/^/- /')
COMMIT_FILES=$(git diff --name-only | sed 's/^/ - /')
# Commit changes
echo "Committing changes..."
git add -A
git commit -m "chore: bump ${VERSION_TYPE} version to ${NEW_VERSION}
This commit updates the ${VERSION_TYPE} version across all relevant files:
${COMMIT_FILES}
🤖 Generated with GitHub Actions"
# Push changes
echo "Pushing to ${BRANCH_NAME}..."
git push origin "${BRANCH_NAME}"
# Create pull request
echo "Creating pull request..."
PR_URL=$(gh pr create \
--title "chore: bump ${VERSION_TYPE} version to ${NEW_VERSION}" \
--body "## Summary
This PR bumps the ${VERSION_TYPE} version to \`${NEW_VERSION}\` across all relevant files.
## Files Updated
${FILES_LIST}
🤖 Generated with GitHub Actions" \
--base main \
--head "${BRANCH_NAME}")
echo "✓ Pull request created successfully"
# Add GitHub Actions job summary
if [ -n "$GITHUB_STEP_SUMMARY" ]; then
cat >> "$GITHUB_STEP_SUMMARY" <<EOF
## ✅ Version Bump Complete
**Version Type:** ${VERSION_TYPE}
**New Version:** \`${NEW_VERSION}\`
### 📝 Pull Request Created
${PR_URL}
### 📦 Files Updated
${FILES_LIST}
EOF
fi
#!/usr/bin/env python3
import unittest
from pathlib import Path
from utils import compare_versions, normalize_version, parse_version, validate_version
class TestVersionUtils(unittest.TestCase):
def test_normalize_version(self):
"""Test version normalization removes 'v' prefix."""
self.assertEqual(normalize_version("v0.5.3"), "0.5.3")
self.assertEqual(normalize_version("0.5.3"), "0.5.3")
self.assertEqual(normalize_version("v0.5.3rc0"), "0.5.3rc0")
self.assertEqual(normalize_version("0.5.3.post1"), "0.5.3.post1")
def test_validate_version(self):
"""Test version format validation."""
# Valid formats
self.assertTrue(validate_version("0.5.3"))
self.assertTrue(validate_version("0.5.3rc0"))
self.assertTrue(validate_version("0.5.3rc1"))
self.assertTrue(validate_version("0.5.3rc999"))
self.assertTrue(validate_version("0.5.3.post1"))
self.assertTrue(validate_version("0.5.3.post10"))
self.assertTrue(validate_version("1.2.3"))
self.assertTrue(validate_version("10.20.30"))
# Invalid formats
self.assertFalse(validate_version("0.5"))
self.assertFalse(validate_version("0.5.3."))
self.assertFalse(validate_version("0.5.3rc"))
self.assertFalse(validate_version("0.5.3post1"))
self.assertFalse(validate_version("0.5.3-rc0"))
self.assertFalse(validate_version("v0.5.3"))
self.assertFalse(validate_version("0.5.3beta1"))
self.assertFalse(validate_version("0.5.3.rc0"))
def test_parse_version_stable(self):
"""Test parsing stable version."""
self.assertEqual(parse_version("0.5.3"), (0, 5, 3, 0, 0))
self.assertEqual(parse_version("1.2.3"), (1, 2, 3, 0, 0))
self.assertEqual(parse_version("10.20.30"), (10, 20, 30, 0, 0))
def test_parse_version_rc(self):
"""Test parsing release candidate versions."""
self.assertEqual(parse_version("0.5.3rc0"), (0, 5, 3, -1000, 0))
self.assertEqual(parse_version("0.5.3rc1"), (0, 5, 3, -999, 0))
self.assertEqual(parse_version("0.5.3rc2"), (0, 5, 3, -998, 0))
self.assertEqual(parse_version("0.5.3rc10"), (0, 5, 3, -990, 0))
def test_parse_version_post(self):
"""Test parsing post-release versions."""
self.assertEqual(parse_version("0.5.3.post1"), (0, 5, 3, 0, 1))
self.assertEqual(parse_version("0.5.3.post2"), (0, 5, 3, 0, 2))
self.assertEqual(parse_version("0.5.3.post10"), (0, 5, 3, 0, 10))
def test_parse_version_invalid(self):
"""Test parsing invalid versions raises error."""
with self.assertRaises(ValueError):
parse_version("0.5")
with self.assertRaises(ValueError):
parse_version("invalid")
with self.assertRaises(ValueError):
parse_version("v0.5.3")
def test_compare_versions_equal(self):
"""Test comparing equal versions."""
self.assertEqual(compare_versions("0.5.3", "0.5.3"), 0)
self.assertEqual(compare_versions("0.5.3rc0", "0.5.3rc0"), 0)
self.assertEqual(compare_versions("0.5.3.post1", "0.5.3.post1"), 0)
def test_compare_versions_rc_ordering(self):
"""Test release candidate ordering: rc0 < rc1 < rc2 < stable."""
# rc0 < rc1
self.assertEqual(compare_versions("0.5.3rc0", "0.5.3rc1"), -1)
self.assertEqual(compare_versions("0.5.3rc1", "0.5.3rc0"), 1)
# rc1 < rc2
self.assertEqual(compare_versions("0.5.3rc1", "0.5.3rc2"), -1)
self.assertEqual(compare_versions("0.5.3rc2", "0.5.3rc1"), 1)
# rc < stable
self.assertEqual(compare_versions("0.5.3rc0", "0.5.3"), -1)
self.assertEqual(compare_versions("0.5.3rc1", "0.5.3"), -1)
self.assertEqual(compare_versions("0.5.3", "0.5.3rc0"), 1)
def test_compare_versions_post_ordering(self):
"""Test post-release ordering: stable < post1 < post2."""
# stable < post1
self.assertEqual(compare_versions("0.5.3", "0.5.3.post1"), -1)
self.assertEqual(compare_versions("0.5.3.post1", "0.5.3"), 1)
# post1 < post2
self.assertEqual(compare_versions("0.5.3.post1", "0.5.3.post2"), -1)
self.assertEqual(compare_versions("0.5.3.post2", "0.5.3.post1"), 1)
def test_compare_versions_full_ordering(self):
"""Test complete version ordering: rc < stable < post."""
# rc < stable < post
self.assertEqual(compare_versions("0.5.3rc0", "0.5.3"), -1)
self.assertEqual(compare_versions("0.5.3", "0.5.3.post1"), -1)
self.assertEqual(compare_versions("0.5.3rc0", "0.5.3.post1"), -1)
# Verify transitivity: rc0 < rc1 < stable < post1 < post2
versions = [
"0.5.3rc0",
"0.5.3rc1",
"0.5.3",
"0.5.3.post1",
"0.5.3.post2",
]
for i in range(len(versions) - 1):
self.assertEqual(
compare_versions(versions[i], versions[i + 1]),
-1,
f"{versions[i]} should be less than {versions[i + 1]}",
)
def test_compare_versions_different_patch(self):
"""Test comparing versions with different patch numbers."""
# 0.5.3 < 0.5.4
self.assertEqual(compare_versions("0.5.3", "0.5.4"), -1)
self.assertEqual(compare_versions("0.5.4", "0.5.3"), 1)
# rc of higher patch > stable of lower patch
self.assertEqual(compare_versions("0.5.4rc0", "0.5.3"), 1)
self.assertEqual(compare_versions("0.5.3.post1", "0.5.4rc0"), -1)
def test_compare_versions_different_minor(self):
"""Test comparing versions with different minor numbers."""
self.assertEqual(compare_versions("0.4.9", "0.5.0"), -1)
self.assertEqual(compare_versions("0.5.0", "0.4.9"), 1)
def test_compare_versions_different_major(self):
"""Test comparing versions with different major numbers."""
self.assertEqual(compare_versions("0.9.9", "1.0.0"), -1)
self.assertEqual(compare_versions("1.0.0", "0.9.9"), 1)
def test_real_world_scenarios(self):
"""Test real-world version bump scenarios."""
# Scenario 1: RC progression
self.assertEqual(compare_versions("0.5.3rc0", "0.5.3rc1"), -1)
# Scenario 2: RC to stable release
self.assertEqual(compare_versions("0.5.3rc2", "0.5.3"), -1)
# Scenario 3: Stable to post-release hotfix
self.assertEqual(compare_versions("0.5.3", "0.5.3.post1"), -1)
# Scenario 4: Post-release to next RC
self.assertEqual(compare_versions("0.5.3.post1", "0.5.4rc0"), -1)
# Scenario 5: Next stable version
self.assertEqual(compare_versions("0.5.3", "0.5.4"), -1)
if __name__ == "__main__":
unittest.main()
......@@ -9,15 +9,69 @@ def normalize_version(version: str) -> str:
return version.lstrip("v")
def validate_version(version: str, version_type: str = "sglang") -> bool:
if version_type == "sglang":
pattern = r"^\d+\.\d+\.\d+(rc\d+)?$"
def validate_version(version: str) -> bool:
"""Validate version format: X.Y.Z, X.Y.Zrc0, or X.Y.Z.post1"""
pattern = r"^\d+\.\d+\.\d+(rc\d+|\.post\d+)?$"
return bool(re.match(pattern, version))
def parse_version(version: str) -> Tuple[int, int, int, int, int]:
"""
Parse version string into comparable components.
Returns: (major, minor, patch, pre_release, post_release)
- pre_release: -1000 + rc_number for rcN, 0 for stable (rc0 < rc1 < stable)
- post_release: N for .postN, 0 otherwise
The pre_release field uses negative numbers to ensure RC versions come before
stable versions when tuples are compared. Python compares tuples element by
element, so (0, 5, 3, -1000, 0) < (0, 5, 3, 0, 0) ensures rc0 < stable.
Examples:
- "0.5.3rc0" → (0, 5, 3, -1000, 0) # rc0 comes before stable
- "0.5.3rc1" → (0, 5, 3, -999, 0) # rc1 comes after rc0
- "0.5.3" → (0, 5, 3, 0, 0) # stable version
- "0.5.3.post1" → (0, 5, 3, 0, 1) # post comes after stable
"""
# Match version components
match = re.match(r"^(\d+)\.(\d+)\.(\d+)(?:rc(\d+)|\.post(\d+))?$", version)
if not match:
raise ValueError(f"Invalid version format: {version}")
major, minor, patch, rc, post = match.groups()
major, minor, patch = int(major), int(minor), int(patch)
if rc is not None:
# RC version: pre_release = -1000 + rc_number (ensures rc0 < rc1 < ... < stable)
return (major, minor, patch, -1000 + int(rc), 0)
elif post is not None:
# Post version: post_release = N
return (major, minor, patch, 0, int(post))
else:
pattern = r"^\d+\.\d+\.\d+$"
# Stable version
return (major, minor, patch, 0, 0)
if not re.match(pattern, version):
return False
return True
def compare_versions(v1: str, v2: str) -> int:
"""
Compare two version strings following PEP 440 ordering.
Returns:
- -1 if v1 < v2
- 0 if v1 == v2
- 1 if v1 > v2
Version ordering: X.Y.ZrcN < X.Y.Z < X.Y.Z.postN < X.Y.(Z+1)
"""
parsed_v1 = parse_version(v1)
parsed_v2 = parse_version(v2)
if parsed_v1 < parsed_v2:
return -1
elif parsed_v1 > parsed_v2:
return 1
else:
return 0
def get_repo_root() -> Path:
......@@ -53,17 +107,14 @@ def bump_version(
new_version: str,
version_file: Path,
files_to_update: List[Path],
version_type: str = "sglang",
) -> None:
# Normalize version (remove 'v' prefix if present)
new_version = normalize_version(new_version)
if not validate_version(new_version, version_type):
if not validate_version(new_version):
print(f"Error: Invalid version format: {new_version}")
if version_type == "sglang":
print("Expected format: X.Y.Z or X.Y.ZrcN (e.g., 0.5.3 or 0.5.3rc0)")
else:
print("Expected format: X.Y.Z (e.g., 0.3.12)")
print("Expected format: X.Y.Z, X.Y.ZrcN, or X.Y.Z.postN")
print("Examples: 0.5.4, 0.5.3rc0, 0.5.3.post1")
sys.exit(1)
repo_root = get_repo_root()
......@@ -78,9 +129,17 @@ def bump_version(
print(f"New version: {new_version}")
print()
if old_version == new_version:
print("Warning: New version is the same as current version")
sys.exit(0)
# Compare versions
comparison = compare_versions(new_version, old_version)
if comparison == 0:
print("Error: New version is the same as current version")
sys.exit(1)
elif comparison < 0:
print(
f"Error: New version ({new_version}) is older than current version ({old_version})"
)
print("Version must be greater than the current version")
sys.exit(1)
updated_count = 0
for file_rel in files_to_update:
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment