chore: vendor sglang v0.5.10 snapshot
This commit is contained in:
96
third_party/sglang/scripts/release/README.md
vendored
Normal file
96
third_party/sglang/scripts/release/README.md
vendored
Normal file
@@ -0,0 +1,96 @@
|
||||
# Release Scripts
|
||||
|
||||
This directory contains scripts to automate version bumping for SGLang releases.
|
||||
|
||||
## Scripts
|
||||
|
||||
### `bump_sglang_version.py`
|
||||
Updates SGLang version across all relevant files following the pattern from [PR #10468](https://github.com/sgl-project/sglang/pull/10468).
|
||||
|
||||
**Usage:**
|
||||
```bash
|
||||
python scripts/release/bump_sglang_version.py 0.5.3rc0
|
||||
```
|
||||
|
||||
**Files updated:**
|
||||
- `Makefile`
|
||||
- `benchmark/deepseek_v3/README.md`
|
||||
- `docker/rocm.Dockerfile`
|
||||
- `docs/get_started/install.md`
|
||||
- `docs/platforms/amd_gpu.md`
|
||||
- `docs/platforms/ascend_npu.md`
|
||||
- `python/pyproject.toml`
|
||||
- `python/pyproject_other.toml`
|
||||
- `python/pyproject_npu.toml`
|
||||
- `python/sglang/version.py`
|
||||
|
||||
### `bump_kernel_version.py`
|
||||
Updates the `sglang-kernel` release version across all relevant files following the pattern from [PR #10732](https://github.com/sgl-project/sglang/pull/10732).
|
||||
|
||||
**Usage:**
|
||||
```bash
|
||||
python scripts/release/bump_kernel_version.py 0.4.0
|
||||
```
|
||||
|
||||
**Files updated:**
|
||||
- `sgl-kernel/pyproject.toml`
|
||||
- `sgl-kernel/pyproject_cpu.toml`
|
||||
- `sgl-kernel/pyproject_rocm.toml`
|
||||
- `sgl-kernel/pyproject_musa.toml`
|
||||
- `sgl-kernel/python/sgl_kernel/version.py`
|
||||
|
||||
## Manual Testing Instructions
|
||||
|
||||
### Test SGLang Version Bump
|
||||
|
||||
1. **Run the script:**
|
||||
```bash
|
||||
python scripts/release/bump_sglang_version.py 0.5.4rc0
|
||||
```
|
||||
|
||||
2. **Verify changes with git diff:**
|
||||
```bash
|
||||
git diff
|
||||
```
|
||||
|
||||
3. **Check specific files contain the new version:**
|
||||
```bash
|
||||
grep -r "0.5.4rc0" python/sglang/version.py
|
||||
grep -r "0.5.4rc0" python/pyproject.toml
|
||||
grep -r "0.5.4rc0" docs/get_started/install.md
|
||||
```
|
||||
|
||||
4. **Reset changes (if testing):**
|
||||
```bash
|
||||
git checkout .
|
||||
```
|
||||
|
||||
### Test Kernel Version Bump
|
||||
|
||||
1. **Run the script:**
|
||||
```bash
|
||||
python scripts/release/bump_kernel_version.py 0.4.0
|
||||
```
|
||||
|
||||
2. **Verify changes with git diff:**
|
||||
```bash
|
||||
git diff
|
||||
```
|
||||
|
||||
3. **Check specific files contain the new version:**
|
||||
```bash
|
||||
grep -r "0.4.0" sgl-kernel/python/sgl_kernel/version.py
|
||||
grep -r "0.4.0" sgl-kernel/pyproject.toml
|
||||
```
|
||||
|
||||
4. **Reset changes (if testing):**
|
||||
```bash
|
||||
git checkout .
|
||||
```
|
||||
|
||||
## Version Format Validation
|
||||
|
||||
- **SGLang versions:** `X.Y.Z` or `X.Y.ZrcN` (e.g., `0.5.3` or `0.5.3rc0`)
|
||||
- **Kernel versions:** `X.Y.Z` (e.g., `0.4.0`)
|
||||
|
||||
The scripts will validate the version format and exit with an error if invalid.
|
||||
148
third_party/sglang/scripts/release/bump_flashinfer_version.py
vendored
Executable file
148
third_party/sglang/scripts/release/bump_flashinfer_version.py
vendored
Executable file
@@ -0,0 +1,148 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from utils import compare_versions, get_repo_root, normalize_version, validate_version
|
||||
|
||||
FILES_TO_UPDATE = [
|
||||
Path("python/pyproject.toml"),
|
||||
Path("docker/Dockerfile"),
|
||||
Path("python/sglang/srt/entrypoints/engine.py"),
|
||||
Path("python/sglang/srt/utils/common.py"),
|
||||
]
|
||||
|
||||
|
||||
def read_current_flashinfer_version(repo_root: Path) -> str:
|
||||
"""Read the current flashinfer version from python/pyproject.toml."""
|
||||
pyproject = repo_root / "python" / "pyproject.toml"
|
||||
content = pyproject.read_text()
|
||||
match = re.search(
|
||||
r"flashinfer_python==(\d+\.\d+\.\d+(?:rc\d+|\.post\d+)?)", content
|
||||
)
|
||||
if not match:
|
||||
raise ValueError(f"Could not find flashinfer_python version in {pyproject}")
|
||||
return match.group(1)
|
||||
|
||||
|
||||
def replace_flashinfer_version(
|
||||
file_path: Path, old_version: str, new_version: str
|
||||
) -> bool:
|
||||
if not file_path.exists():
|
||||
print(f"Warning: {file_path} does not exist, skipping")
|
||||
return False
|
||||
|
||||
content = file_path.read_text()
|
||||
new_content = content
|
||||
|
||||
name = file_path.name
|
||||
if name == "pyproject.toml":
|
||||
new_content = new_content.replace(
|
||||
f"flashinfer_python=={old_version}", f"flashinfer_python=={new_version}"
|
||||
)
|
||||
new_content = new_content.replace(
|
||||
f"flashinfer_cubin=={old_version}", f"flashinfer_cubin=={new_version}"
|
||||
)
|
||||
elif name == "Dockerfile":
|
||||
new_content = re.sub(
|
||||
rf"(ARG FLASHINFER_VERSION=){re.escape(old_version)}",
|
||||
rf"\g<1>{new_version}",
|
||||
new_content,
|
||||
)
|
||||
elif name == "engine.py":
|
||||
new_content = re.sub(
|
||||
r'(assert_pkg_version\(\s*"flashinfer_python",\s*)"'
|
||||
+ re.escape(old_version)
|
||||
+ r'"',
|
||||
r'\g<1>"' + new_version + '"',
|
||||
new_content,
|
||||
flags=re.DOTALL,
|
||||
)
|
||||
elif name == "common.py":
|
||||
new_content = new_content.replace(
|
||||
f'e.g., "{old_version}"',
|
||||
f'e.g., "{new_version}"',
|
||||
)
|
||||
|
||||
if content == new_content:
|
||||
print(f"No changes needed in {file_path}")
|
||||
return False
|
||||
|
||||
file_path.write_text(new_content)
|
||||
print(f"✓ Updated {file_path}")
|
||||
return True
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Bump flashinfer version across all relevant files"
|
||||
)
|
||||
parser.add_argument(
|
||||
"new_version",
|
||||
help="New version (e.g., 0.6.4, 0.6.4rc0, or 0.6.4.post1)",
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
new_version = normalize_version(args.new_version)
|
||||
|
||||
if not validate_version(new_version):
|
||||
print(f"Error: Invalid version format: {new_version}")
|
||||
print("Expected format: X.Y.Z, X.Y.ZrcN, or X.Y.Z.postN")
|
||||
print("Examples: 0.6.4, 0.6.4rc0, 0.6.4.post1")
|
||||
sys.exit(1)
|
||||
|
||||
repo_root = get_repo_root()
|
||||
old_version = read_current_flashinfer_version(repo_root)
|
||||
print(f"Current flashinfer version: {old_version}")
|
||||
print(f"New flashinfer version: {new_version}")
|
||||
print()
|
||||
|
||||
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:
|
||||
file_abs = repo_root / file_rel
|
||||
if replace_flashinfer_version(file_abs, old_version, new_version):
|
||||
updated_count += 1
|
||||
|
||||
print()
|
||||
print(f"Successfully updated {updated_count} file(s)")
|
||||
print(f"Flashinfer version bumped from {old_version} to {new_version}")
|
||||
|
||||
print("\nValidating version updates...")
|
||||
failed_files = []
|
||||
for file_rel in FILES_TO_UPDATE:
|
||||
file_abs = repo_root / file_rel
|
||||
if not file_abs.exists():
|
||||
print(f"Warning: File {file_rel} does not exist, skipping validation.")
|
||||
continue
|
||||
|
||||
content = file_abs.read_text()
|
||||
if new_version not in content:
|
||||
failed_files.append(file_rel)
|
||||
print(f"✗ {file_rel} does not contain version {new_version}")
|
||||
else:
|
||||
print(f"✓ {file_rel} validated")
|
||||
|
||||
if failed_files:
|
||||
print(f"\nError: {len(failed_files)} file(s) were not updated correctly:")
|
||||
for file_rel in failed_files:
|
||||
print(f" - {file_rel}")
|
||||
sys.exit(1)
|
||||
|
||||
print("\nAll files validated successfully!")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
33
third_party/sglang/scripts/release/bump_kernel_version.py
vendored
Executable file
33
third_party/sglang/scripts/release/bump_kernel_version.py
vendored
Executable file
@@ -0,0 +1,33 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
|
||||
from utils import bump_version
|
||||
|
||||
|
||||
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, 0.3.11rc0, or 0.3.11.post1)",
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
version_file = Path("sgl-kernel/python/sgl_kernel/version.py")
|
||||
|
||||
files_to_update = [
|
||||
Path("sgl-kernel/pyproject.toml"),
|
||||
Path("sgl-kernel/pyproject_cpu.toml"),
|
||||
Path("sgl-kernel/pyproject_rocm.toml"),
|
||||
Path("sgl-kernel/pyproject_musa.toml"),
|
||||
Path("sgl-kernel/python/sgl_kernel/version.py"),
|
||||
]
|
||||
|
||||
bump_version(args.new_version, version_file, files_to_update)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
143
third_party/sglang/scripts/release/bump_kernel_version_to_sglang.py
vendored
Executable file
143
third_party/sglang/scripts/release/bump_kernel_version_to_sglang.py
vendored
Executable file
@@ -0,0 +1,143 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Bump sglang-kernel version in SGLang files to match the version in sgl-kernel/pyproject.toml.
|
||||
Updates:
|
||||
- python/pyproject.toml
|
||||
- python/sglang/srt/entrypoints/engine.py
|
||||
- docker/Dockerfile
|
||||
"""
|
||||
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
try:
|
||||
import tomllib # Python 3.11+
|
||||
except ImportError:
|
||||
import tomli as tomllib # Fallback for older Python versions
|
||||
|
||||
|
||||
def get_kernel_version_from_source() -> str:
|
||||
"""Extract version from sgl-kernel/pyproject.toml"""
|
||||
pyproject_path = Path("sgl-kernel/pyproject.toml")
|
||||
|
||||
if not pyproject_path.exists():
|
||||
print(f"Error: {pyproject_path} not found")
|
||||
sys.exit(1)
|
||||
|
||||
with open(pyproject_path, "rb") as f:
|
||||
data = tomllib.load(f)
|
||||
|
||||
version = data.get("project", {}).get("version")
|
||||
if not version:
|
||||
print("Error: Could not find version in sgl-kernel/pyproject.toml")
|
||||
sys.exit(1)
|
||||
|
||||
return version
|
||||
|
||||
|
||||
def update_python_pyproject(new_version: str) -> bool:
|
||||
"""Update sglang-kernel version in python/pyproject.toml"""
|
||||
pyproject_path = Path("python/pyproject.toml")
|
||||
|
||||
if not pyproject_path.exists():
|
||||
print(f"Error: {pyproject_path} not found")
|
||||
sys.exit(1)
|
||||
|
||||
content = pyproject_path.read_text()
|
||||
|
||||
# Replace "sglang-kernel==x.x.x" with new version
|
||||
new_content = re.sub(
|
||||
r'"sglang-kernel==[^"]+"',
|
||||
f'"sglang-kernel=={new_version}"',
|
||||
content,
|
||||
)
|
||||
|
||||
if content == new_content:
|
||||
print("No changes needed in python/pyproject.toml")
|
||||
return False
|
||||
|
||||
pyproject_path.write_text(new_content)
|
||||
print(f"✓ Updated python/pyproject.toml to version {new_version}")
|
||||
return True
|
||||
|
||||
|
||||
def update_engine_py(new_version: str) -> bool:
|
||||
"""Update sglang-kernel version in python/sglang/srt/entrypoints/engine.py"""
|
||||
engine_path = Path("python/sglang/srt/entrypoints/engine.py")
|
||||
|
||||
if not engine_path.exists():
|
||||
print(f"Error: {engine_path} not found")
|
||||
sys.exit(1)
|
||||
|
||||
content = engine_path.read_text()
|
||||
|
||||
# Replace version in assert_pkg_version("sglang-kernel", "version", ...)
|
||||
new_content = re.sub(
|
||||
r'(assert_pkg_version\s*\(\s*"sglang-kernel"\s*,\s*)"[^"]+"',
|
||||
rf'\1"{new_version}"',
|
||||
content,
|
||||
)
|
||||
|
||||
if content == new_content:
|
||||
print("No changes needed in engine.py")
|
||||
return False
|
||||
|
||||
engine_path.write_text(new_content)
|
||||
print(f"✓ Updated engine.py to version {new_version}")
|
||||
return True
|
||||
|
||||
|
||||
def update_dockerfile(new_version: str) -> bool:
|
||||
"""Update SGL_KERNEL_VERSION in docker/Dockerfile"""
|
||||
dockerfile_path = Path("docker/Dockerfile")
|
||||
|
||||
if not dockerfile_path.exists():
|
||||
print(f"Error: {dockerfile_path} not found")
|
||||
sys.exit(1)
|
||||
|
||||
content = dockerfile_path.read_text()
|
||||
|
||||
# Replace ARG SGL_KERNEL_VERSION=x.x.x with new version
|
||||
new_content = re.sub(
|
||||
r"^(ARG\s+SGL_KERNEL_VERSION=)(.+)$",
|
||||
rf"\g<1>{new_version}",
|
||||
content,
|
||||
flags=re.MULTILINE,
|
||||
)
|
||||
|
||||
if content == new_content:
|
||||
print("No changes needed in Dockerfile")
|
||||
return False
|
||||
|
||||
dockerfile_path.write_text(new_content)
|
||||
print(f"✓ Updated Dockerfile to version {new_version}")
|
||||
return True
|
||||
|
||||
|
||||
def main():
|
||||
kernel_version = get_kernel_version_from_source()
|
||||
print(f"Bumping sglang-kernel version to: {kernel_version}\n")
|
||||
|
||||
updated_files = []
|
||||
|
||||
if update_python_pyproject(kernel_version):
|
||||
updated_files.append("python/pyproject.toml")
|
||||
|
||||
if update_engine_py(kernel_version):
|
||||
updated_files.append("python/sglang/srt/entrypoints/engine.py")
|
||||
|
||||
if update_dockerfile(kernel_version):
|
||||
updated_files.append("docker/Dockerfile")
|
||||
|
||||
print()
|
||||
if updated_files:
|
||||
print(f"✓ Successfully updated {len(updated_files)} file(s):")
|
||||
for file in updated_files:
|
||||
print(f" - {file}")
|
||||
else:
|
||||
print("✓ All files already have the correct version")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
150
third_party/sglang/scripts/release/check_kernel_version_to_sglang.py
vendored
Executable file
150
third_party/sglang/scripts/release/check_kernel_version_to_sglang.py
vendored
Executable file
@@ -0,0 +1,150 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Check if sglang-kernel version from sgl-kernel/pyproject.toml matches the versions
|
||||
used in SGLang files (python/pyproject.toml, engine.py, and Dockerfile).
|
||||
Sets GitHub Actions output variables to indicate if sync is needed.
|
||||
"""
|
||||
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
try:
|
||||
import tomllib # Python 3.11+
|
||||
except ImportError:
|
||||
import tomli as tomllib # Fallback for older Python versions
|
||||
|
||||
|
||||
def get_kernel_version_from_source() -> str:
|
||||
"""Extract version from sgl-kernel/pyproject.toml (line 11)"""
|
||||
pyproject_path = Path("sgl-kernel/pyproject.toml")
|
||||
|
||||
if not pyproject_path.exists():
|
||||
print(f"Error: {pyproject_path} not found")
|
||||
sys.exit(1)
|
||||
|
||||
with open(pyproject_path, "rb") as f:
|
||||
data = tomllib.load(f)
|
||||
|
||||
version = data.get("project", {}).get("version")
|
||||
if not version:
|
||||
print("Error: Could not find version in sgl-kernel/pyproject.toml")
|
||||
sys.exit(1)
|
||||
|
||||
return version
|
||||
|
||||
|
||||
def get_kernel_version_from_python_pyproject() -> str:
|
||||
"""Extract sglang-kernel version from python/pyproject.toml"""
|
||||
pyproject_path = Path("python/pyproject.toml")
|
||||
|
||||
if not pyproject_path.exists():
|
||||
print(f"Error: {pyproject_path} not found")
|
||||
sys.exit(1)
|
||||
|
||||
content = pyproject_path.read_text()
|
||||
|
||||
# Match "sglang-kernel==x.x.x"
|
||||
match = re.search(r'"sglang-kernel==([^"]+)"', content)
|
||||
if not match:
|
||||
print("Error: Could not find sglang-kernel version in python/pyproject.toml")
|
||||
sys.exit(1)
|
||||
|
||||
return match.group(1)
|
||||
|
||||
|
||||
def get_kernel_version_from_engine() -> str:
|
||||
"""Extract sglang-kernel version from python/sglang/srt/entrypoints/engine.py"""
|
||||
engine_path = Path("python/sglang/srt/entrypoints/engine.py")
|
||||
|
||||
if not engine_path.exists():
|
||||
print(f"Error: {engine_path} not found")
|
||||
sys.exit(1)
|
||||
|
||||
content = engine_path.read_text()
|
||||
|
||||
# Find the assert_pkg_version call for sglang-kernel
|
||||
# Look for the pattern: assert_pkg_version("sglang-kernel", "version", ...)
|
||||
match = re.search(
|
||||
r'assert_pkg_version\s*\(\s*"sglang-kernel"\s*,\s*"([^"]+)"', content
|
||||
)
|
||||
if not match:
|
||||
print("Error: Could not find sglang-kernel version in engine.py")
|
||||
sys.exit(1)
|
||||
|
||||
return match.group(1)
|
||||
|
||||
|
||||
def get_kernel_version_from_dockerfile() -> str:
|
||||
"""Extract SGL_KERNEL_VERSION from docker/Dockerfile"""
|
||||
dockerfile_path = Path("docker/Dockerfile")
|
||||
|
||||
if not dockerfile_path.exists():
|
||||
print(f"Error: {dockerfile_path} not found")
|
||||
sys.exit(1)
|
||||
|
||||
content = dockerfile_path.read_text()
|
||||
|
||||
# Match ARG SGL_KERNEL_VERSION=x.x.x
|
||||
match = re.search(r"^ARG\s+SGL_KERNEL_VERSION=(.+)$", content, re.MULTILINE)
|
||||
if not match:
|
||||
print("Error: Could not find SGL_KERNEL_VERSION in Dockerfile")
|
||||
sys.exit(1)
|
||||
|
||||
return match.group(1).strip()
|
||||
|
||||
|
||||
def main():
|
||||
kernel_version = get_kernel_version_from_source()
|
||||
pyproject_version = get_kernel_version_from_python_pyproject()
|
||||
engine_version = get_kernel_version_from_engine()
|
||||
dockerfile_version = get_kernel_version_from_dockerfile()
|
||||
|
||||
print(f"Kernel version in sgl-kernel/pyproject.toml: {kernel_version}")
|
||||
print(
|
||||
f"SGLang kernel dependency version in python/pyproject.toml: {pyproject_version}"
|
||||
)
|
||||
print(f"SGLang kernel dependency version in engine.py: {engine_version}")
|
||||
print(f"Kernel version in Dockerfile: {dockerfile_version}")
|
||||
|
||||
# Check if any version differs from the source
|
||||
needs_sync = (
|
||||
kernel_version != pyproject_version
|
||||
or kernel_version != engine_version
|
||||
or kernel_version != dockerfile_version
|
||||
)
|
||||
|
||||
# Set GitHub Actions output
|
||||
github_output = os.getenv("GITHUB_OUTPUT")
|
||||
if github_output:
|
||||
with open(github_output, "a") as f:
|
||||
f.write(f"needs_sync={'true' if needs_sync else 'false'}\n")
|
||||
f.write(f"kernel_version={kernel_version}\n")
|
||||
|
||||
if needs_sync:
|
||||
print(f"\n✓ Sync needed to version: {kernel_version}")
|
||||
mismatches = []
|
||||
if kernel_version != pyproject_version:
|
||||
mismatches.append(
|
||||
f" - python/pyproject.toml: {pyproject_version} → {kernel_version}"
|
||||
)
|
||||
if kernel_version != engine_version:
|
||||
mismatches.append(f" - engine.py: {engine_version} → {kernel_version}")
|
||||
if kernel_version != dockerfile_version:
|
||||
mismatches.append(
|
||||
f" - Dockerfile: {dockerfile_version} → {kernel_version}"
|
||||
)
|
||||
|
||||
print("Changes needed:")
|
||||
for mismatch in mismatches:
|
||||
print(mismatch)
|
||||
|
||||
sys.exit(0)
|
||||
else:
|
||||
print("\n✓ All versions are in sync, no action needed")
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
72
third_party/sglang/scripts/release/commit_and_pr.sh
vendored
Executable file
72
third_party/sglang/scripts/release/commit_and_pr.sh
vendored
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
|
||||
81
third_party/sglang/scripts/release/commit_and_pr_kernel_to_sglang.sh
vendored
Executable file
81
third_party/sglang/scripts/release/commit_and_pr_kernel_to_sglang.sh
vendored
Executable file
@@ -0,0 +1,81 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# Script to commit kernel version bump changes to SGLang and create a pull request
|
||||
# Usage: commit_and_pr_kernel_to_sglang.sh <kernel_version> <branch_name>
|
||||
#
|
||||
# Arguments:
|
||||
# kernel_version: The kernel version being synced
|
||||
# branch_name: The git branch name to push to
|
||||
|
||||
KERNEL_VERSION="$1"
|
||||
BRANCH_NAME="$2"
|
||||
|
||||
if [ -z "$KERNEL_VERSION" ] || [ -z "$BRANCH_NAME" ]; then
|
||||
echo "Error: Missing required arguments"
|
||||
echo "Usage: $0 <kernel_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 sglang-kernel version to ${KERNEL_VERSION} in SGLang
|
||||
|
||||
This commit updates the sglang-kernel version across SGLang files to match
|
||||
the version defined in sgl-kernel/pyproject.toml.
|
||||
|
||||
Files updated:
|
||||
${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 sglang-kernel version to ${KERNEL_VERSION}" \
|
||||
--body "## Summary
|
||||
|
||||
This PR bumps the \`sglang-kernel\` version to \`${KERNEL_VERSION}\` across SGLang files to match the version defined in \`sgl-kernel/pyproject.toml\`.
|
||||
|
||||
**Kernel Version:** \`${KERNEL_VERSION}\`
|
||||
|
||||
## Files Updated
|
||||
${FILES_LIST}
|
||||
|
||||
## Context
|
||||
|
||||
The kernel version in \`sgl-kernel/pyproject.toml\` has been updated. This PR ensures that all SGLang files referencing the \`sglang-kernel\` dependency are updated accordingly:
|
||||
- \`python/pyproject.toml\` - dependency specification
|
||||
- \`python/sglang/srt/entrypoints/engine.py\` - version check
|
||||
- \`docker/Dockerfile\` - Docker build argument
|
||||
|
||||
🤖 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
|
||||
## ✅ Kernel Version Bump Complete
|
||||
|
||||
**Kernel Version:** \`${KERNEL_VERSION}\`
|
||||
|
||||
### 📝 Pull Request Created
|
||||
${PR_URL}
|
||||
|
||||
### 📦 Files Updated
|
||||
${FILES_LIST}
|
||||
EOF
|
||||
fi
|
||||
159
third_party/sglang/scripts/release/test_utils.py
vendored
Executable file
159
third_party/sglang/scripts/release/test_utils.py
vendored
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()
|
||||
220
third_party/sglang/scripts/release/utils.py
vendored
Normal file
220
third_party/sglang/scripts/release/utils.py
vendored
Normal file
@@ -0,0 +1,220 @@
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import List, Tuple
|
||||
|
||||
try:
|
||||
import tomllib # Python 3.11+
|
||||
except ImportError:
|
||||
import tomli as tomllib # Fallback for older Python versions
|
||||
|
||||
|
||||
def normalize_version(version: str) -> str:
|
||||
"""Remove 'v' prefix from version string if present."""
|
||||
return version.lstrip("v")
|
||||
|
||||
|
||||
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:
|
||||
# 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:
|
||||
return Path(__file__).parent.parent.parent
|
||||
|
||||
|
||||
def read_current_version(version_file: Path) -> str:
|
||||
content = version_file.read_text()
|
||||
match = re.search(r'__version__\s*=\s*["\']([^"\']+)["\']', content)
|
||||
if not match:
|
||||
raise ValueError(f"Could not find version in {version_file}")
|
||||
return match.group(1)
|
||||
|
||||
|
||||
def replace_in_file(file_path: Path, old_version: str, new_version: str) -> bool:
|
||||
if not file_path.exists():
|
||||
print(f"Warning: {file_path} does not exist, skipping")
|
||||
return False
|
||||
|
||||
content = file_path.read_text()
|
||||
|
||||
# For TOML files, parse and update only the [project] version field
|
||||
if file_path.suffix == ".toml":
|
||||
try:
|
||||
# Parse TOML to verify structure
|
||||
toml_data = tomllib.loads(content)
|
||||
|
||||
# Check if [project] section exists and has version field
|
||||
if "project" not in toml_data or "version" not in toml_data["project"]:
|
||||
print(
|
||||
f"Warning: {file_path} does not have [project] version field, skipping"
|
||||
)
|
||||
return False
|
||||
|
||||
# Use regex to replace only the version field in [project] section
|
||||
# This pattern matches the version field that comes after [project]
|
||||
# and before any other section marker
|
||||
pattern = r'(\[project\].*?version\s*=\s*)["\']([^"\']+)["\']'
|
||||
new_content = re.sub(
|
||||
pattern, rf'\g<1>"{new_version}"', content, flags=re.DOTALL
|
||||
)
|
||||
except Exception as e:
|
||||
print(f"Warning: Failed to parse {file_path} as TOML: {e}")
|
||||
print("Falling back to simple string replacement")
|
||||
new_content = content.replace(old_version, new_version)
|
||||
else:
|
||||
# For non-TOML files, use simple string replacement
|
||||
new_content = content.replace(old_version, new_version)
|
||||
|
||||
if content == new_content:
|
||||
print(f"No changes needed in {file_path}")
|
||||
return False
|
||||
|
||||
file_path.write_text(new_content)
|
||||
print(f"✓ Updated {file_path}")
|
||||
return True
|
||||
|
||||
|
||||
def bump_version(
|
||||
new_version: str,
|
||||
version_file: Path,
|
||||
files_to_update: List[Path],
|
||||
) -> None:
|
||||
# Normalize version (remove 'v' prefix if present)
|
||||
new_version = normalize_version(new_version)
|
||||
|
||||
if not validate_version(new_version):
|
||||
print(f"Error: Invalid version format: {new_version}")
|
||||
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()
|
||||
version_file_abs = repo_root / version_file
|
||||
|
||||
if not version_file_abs.exists():
|
||||
print(f"Error: Version file {version_file_abs} does not exist")
|
||||
sys.exit(1)
|
||||
|
||||
old_version = read_current_version(version_file_abs)
|
||||
print(f"Current version: {old_version}")
|
||||
print(f"New version: {new_version}")
|
||||
print()
|
||||
|
||||
# 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:
|
||||
file_abs = repo_root / file_rel
|
||||
if replace_in_file(file_abs, old_version, new_version):
|
||||
updated_count += 1
|
||||
|
||||
print()
|
||||
print(f"Successfully updated {updated_count} file(s)")
|
||||
print(f"Version bumped from {old_version} to {new_version}")
|
||||
|
||||
# Validate that all files now contain the new version
|
||||
print("\nValidating version updates...")
|
||||
failed_files = []
|
||||
for file_rel in files_to_update:
|
||||
file_abs = repo_root / file_rel
|
||||
if not file_abs.exists():
|
||||
print(f"Warning: File {file_rel} does not exist, skipping validation.")
|
||||
continue
|
||||
|
||||
content = file_abs.read_text()
|
||||
|
||||
# For TOML files, use regex to specifically check the version field
|
||||
if file_abs.suffix == ".toml":
|
||||
# Match version field with optional quotes
|
||||
pattern = r'version\s*=\s*["\']?' + re.escape(new_version) + r'["\']?'
|
||||
if not re.search(pattern, content):
|
||||
failed_files.append(file_rel)
|
||||
print(f"✗ {file_rel} does not contain version {new_version}")
|
||||
else:
|
||||
print(f"✓ {file_rel} validated")
|
||||
else:
|
||||
# For non-TOML files, use simple string search
|
||||
if new_version not in content:
|
||||
failed_files.append(file_rel)
|
||||
print(f"✗ {file_rel} does not contain version {new_version}")
|
||||
else:
|
||||
print(f"✓ {file_rel} validated")
|
||||
|
||||
if failed_files:
|
||||
print(f"\nError: {len(failed_files)} file(s) were not updated correctly:")
|
||||
for file_rel in failed_files:
|
||||
print(f" - {file_rel}")
|
||||
sys.exit(1)
|
||||
|
||||
print("\nAll files validated successfully!")
|
||||
Reference in New Issue
Block a user