Improve bot release workflow (#11240)
This commit is contained in:
50
.github/workflows/bot-bump-kernel-version.yml
vendored
50
.github/workflows/bot-bump-kernel-version.yml
vendored
@@ -26,14 +26,12 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
python-version: '3.10'
|
python-version: '3.10'
|
||||||
|
|
||||||
- name: Configure Git
|
- name: Configure Git and branch
|
||||||
run: |
|
run: |
|
||||||
git config user.name "sglang-bot"
|
git config user.name "sglang-bot"
|
||||||
git config user.email "sglang-bot@users.noreply.github.com"
|
git config user.email "sglang-bot@users.noreply.github.com"
|
||||||
|
RANDOM_SUFFIX=$(echo $RANDOM | md5sum | head -c 4)
|
||||||
- name: Create new branch
|
BRANCH_NAME="bot/bump-kernel-version-${{ github.event.inputs.new_version }}-${RANDOM_SUFFIX}"
|
||||||
run: |
|
|
||||||
BRANCH_NAME="bot/bump-kernel-version-${{ github.event.inputs.new_version }}"
|
|
||||||
git checkout -b "$BRANCH_NAME"
|
git checkout -b "$BRANCH_NAME"
|
||||||
echo "BRANCH_NAME=$BRANCH_NAME" >> $GITHUB_ENV
|
echo "BRANCH_NAME=$BRANCH_NAME" >> $GITHUB_ENV
|
||||||
|
|
||||||
@@ -41,44 +39,8 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
python scripts/release/bump_kernel_version.py "${{ github.event.inputs.new_version }}"
|
python scripts/release/bump_kernel_version.py "${{ github.event.inputs.new_version }}"
|
||||||
|
|
||||||
- name: Commit changes
|
- name: Commit and create PR
|
||||||
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
|
|
||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GH_TOKEN: ${{ secrets.GH_PAT_FOR_TAGGING }}
|
||||||
run: |
|
run: |
|
||||||
gh pr create \
|
bash scripts/release/commit_and_pr.sh "sgl-kernel" "${{ github.event.inputs.new_version }}" "$BRANCH_NAME"
|
||||||
--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"
|
|
||||||
|
|||||||
60
.github/workflows/bot-bump-sglang-version.yml
vendored
60
.github/workflows/bot-bump-sglang-version.yml
vendored
@@ -26,14 +26,12 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
python-version: '3.10'
|
python-version: '3.10'
|
||||||
|
|
||||||
- name: Configure Git
|
- name: Configure Git and branch
|
||||||
run: |
|
run: |
|
||||||
git config user.name "sglang-bot"
|
git config user.name "sglang-bot"
|
||||||
git config user.email "sglang-bot@users.noreply.github.com"
|
git config user.email "sglang-bot@users.noreply.github.com"
|
||||||
|
RANDOM_SUFFIX=$(echo $RANDOM | md5sum | head -c 4)
|
||||||
- name: Create new branch
|
BRANCH_NAME="bot/bump-sglang-version-${{ github.event.inputs.new_version }}-${RANDOM_SUFFIX}"
|
||||||
run: |
|
|
||||||
BRANCH_NAME="bot/bump-sglang-version-${{ github.event.inputs.new_version }}"
|
|
||||||
git checkout -b "$BRANCH_NAME"
|
git checkout -b "$BRANCH_NAME"
|
||||||
echo "BRANCH_NAME=$BRANCH_NAME" >> $GITHUB_ENV
|
echo "BRANCH_NAME=$BRANCH_NAME" >> $GITHUB_ENV
|
||||||
|
|
||||||
@@ -41,54 +39,8 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
python scripts/release/bump_sglang_version.py "${{ github.event.inputs.new_version }}"
|
python scripts/release/bump_sglang_version.py "${{ github.event.inputs.new_version }}"
|
||||||
|
|
||||||
- name: Commit changes
|
- name: Commit and create PR
|
||||||
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
|
|
||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GH_TOKEN: ${{ secrets.GH_PAT_FOR_TAGGING }}
|
||||||
run: |
|
run: |
|
||||||
gh pr create \
|
bash scripts/release/commit_and_pr.sh "SGLang" "${{ github.event.inputs.new_version }}" "$BRANCH_NAME"
|
||||||
--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"
|
|
||||||
|
|||||||
@@ -10,7 +10,10 @@ def main():
|
|||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(
|
||||||
description="Bump sgl-kernel version across all relevant files"
|
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()
|
args = parser.parse_args()
|
||||||
|
|
||||||
version_file = Path("sgl-kernel/python/sgl_kernel/version.py")
|
version_file = Path("sgl-kernel/python/sgl_kernel/version.py")
|
||||||
@@ -23,7 +26,7 @@ def main():
|
|||||||
Path("sgl-kernel/python/sgl_kernel/version.py"),
|
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__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
@@ -10,7 +10,10 @@ def main():
|
|||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(
|
||||||
description="Bump SGLang version across all relevant files"
|
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()
|
args = parser.parse_args()
|
||||||
|
|
||||||
version_file = Path("python/sglang/version.py")
|
version_file = Path("python/sglang/version.py")
|
||||||
@@ -27,7 +30,7 @@ def main():
|
|||||||
Path("python/sglang/version.py"),
|
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__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
72
scripts/release/commit_and_pr.sh
Executable file
72
scripts/release/commit_and_pr.sh
Executable file
@@ -0,0 +1,72 @@
|
|||||||
|
#!/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
|
||||||
159
scripts/release/test_utils.py
Executable file
159
scripts/release/test_utils.py
Executable file
@@ -0,0 +1,159 @@
|
|||||||
|
#!/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")
|
return version.lstrip("v")
|
||||||
|
|
||||||
|
|
||||||
def validate_version(version: str, version_type: str = "sglang") -> bool:
|
def validate_version(version: str) -> bool:
|
||||||
if version_type == "sglang":
|
"""Validate version format: X.Y.Z, X.Y.Zrc0, or X.Y.Z.post1"""
|
||||||
pattern = r"^\d+\.\d+\.\d+(rc\d+)?$"
|
pattern = r"^\d+\.\d+\.\d+(rc\d+|\.post\d+)?$"
|
||||||
else:
|
return bool(re.match(pattern, version))
|
||||||
pattern = r"^\d+\.\d+\.\d+$"
|
|
||||||
|
|
||||||
if not re.match(pattern, version):
|
|
||||||
return False
|
def parse_version(version: str) -> Tuple[int, int, int, int, int]:
|
||||||
return True
|
"""
|
||||||
|
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:
|
||||||
|
# Stable version
|
||||||
|
return (major, minor, patch, 0, 0)
|
||||||
|
|
||||||
|
|
||||||
|
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:
|
def get_repo_root() -> Path:
|
||||||
@@ -53,17 +107,14 @@ def bump_version(
|
|||||||
new_version: str,
|
new_version: str,
|
||||||
version_file: Path,
|
version_file: Path,
|
||||||
files_to_update: List[Path],
|
files_to_update: List[Path],
|
||||||
version_type: str = "sglang",
|
|
||||||
) -> None:
|
) -> None:
|
||||||
# Normalize version (remove 'v' prefix if present)
|
# Normalize version (remove 'v' prefix if present)
|
||||||
new_version = normalize_version(new_version)
|
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}")
|
print(f"Error: Invalid version format: {new_version}")
|
||||||
if version_type == "sglang":
|
print("Expected format: X.Y.Z, X.Y.ZrcN, or X.Y.Z.postN")
|
||||||
print("Expected format: X.Y.Z or X.Y.ZrcN (e.g., 0.5.3 or 0.5.3rc0)")
|
print("Examples: 0.5.4, 0.5.3rc0, 0.5.3.post1")
|
||||||
else:
|
|
||||||
print("Expected format: X.Y.Z (e.g., 0.3.12)")
|
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
repo_root = get_repo_root()
|
repo_root = get_repo_root()
|
||||||
@@ -78,9 +129,17 @@ def bump_version(
|
|||||||
print(f"New version: {new_version}")
|
print(f"New version: {new_version}")
|
||||||
print()
|
print()
|
||||||
|
|
||||||
if old_version == new_version:
|
# Compare versions
|
||||||
print("Warning: New version is the same as current version")
|
comparison = compare_versions(new_version, old_version)
|
||||||
sys.exit(0)
|
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
|
updated_count = 0
|
||||||
for file_rel in files_to_update:
|
for file_rel in files_to_update:
|
||||||
|
|||||||
Reference in New Issue
Block a user