From 0bf7ddb4814d8acb06b0320636e5721118ef366e Mon Sep 17 00:00:00 2001 From: zijiexia <37504505+zijiexia@users.noreply.github.com> Date: Tue, 7 Jul 2026 12:10:05 -0700 Subject: [PATCH] docs(install): add nightly install + docker tag guidance, and auto-bump version on release tag (#30308) --- .github/workflows/bot-bump-docs-version.yml | 88 +++++++++++ docs_new/docs/get-started/install.mdx | 21 +++ scripts/release/README.md | 12 ++ scripts/release/bump_docs_install_version.py | 149 +++++++++++++++++++ 4 files changed, 270 insertions(+) create mode 100644 .github/workflows/bot-bump-docs-version.yml create mode 100755 scripts/release/bump_docs_install_version.py diff --git a/.github/workflows/bot-bump-docs-version.yml b/.github/workflows/bot-bump-docs-version.yml new file mode 100644 index 000000000..359f26fb9 --- /dev/null +++ b/.github/workflows/bot-bump-docs-version.yml @@ -0,0 +1,88 @@ +name: Bot Bump Docs Version +# +# Bumps the "install from source" release-branch version pinned in the docs +# (the `git clone -b v ...sglang.git` line in +# docs_new/docs/get-started/install.mdx "Method 2: From source" and +# docs_new/docs/hardware-platforms/amd_gpu.mdx) whenever a release tag is +# pushed, and opens a PR with the change. +# +# Triggers mirror release-docker.yml: a pushed `v*` tag (the release), or a +# manual run with an explicit version. +on: + push: + tags: + - "v[0-9]+.*" + workflow_dispatch: + inputs: + version: + description: "Version to set (without v prefix, e.g., 0.5.13)" + required: true + +permissions: + contents: write + pull-requests: write + +jobs: + resolve-version: + if: github.repository == 'sgl-project/sglang' + runs-on: ubuntu-latest + outputs: + version: ${{ steps.version.outputs.version }} + steps: + - name: Get version + id: version + run: | + if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then + VERSION="${{ github.event.inputs.version }}" + else + VERSION="${GITHUB_REF_NAME#v}" + fi + if [ -z "$VERSION" ] || ! echo "$VERSION" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+'; then + echo "::error::Invalid version: $VERSION (expected: X.Y.Z)" + exit 1 + fi + echo "version=${VERSION}" >> $GITHUB_OUTPUT + + bump-docs-version: + needs: resolve-version + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + # Branch off main so the PR targets the docs on the default branch, + # not the (detached) tag commit that triggered this run. + ref: main + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.10' + + - name: Install Python dependencies + run: | + pip install tomli + + - name: Configure Git and branch + run: | + git config user.name "sglang-bot" + git config user.email "sglang-bot@users.noreply.github.com" + # github.run_id is unique per run repo-wide; run_attempt disambiguates re-runs. + BRANCH_NAME="bot/bump-docs-version-${{ needs.resolve-version.outputs.version }}-${{ github.run_id }}-${{ github.run_attempt }}" + git checkout -b "$BRANCH_NAME" + echo "BRANCH_NAME=$BRANCH_NAME" >> $GITHUB_ENV + + - name: Run docs version bump script + run: | + python scripts/release/bump_docs_install_version.py "${{ needs.resolve-version.outputs.version }}" + + - name: Commit and create PR + env: + GH_TOKEN: ${{ secrets.GH_PAT_FOR_PULL_REQUEST }} + run: | + if git diff --quiet; then + echo "Docs already pin this version; no PR needed." + exit 0 + fi + bash scripts/release/commit_and_pr.sh "docs install" "${{ needs.resolve-version.outputs.version }}" "$BRANCH_NAME" diff --git a/docs_new/docs/get-started/install.mdx b/docs_new/docs/get-started/install.mdx index 075517e49..9c6027536 100644 --- a/docs_new/docs/get-started/install.mdx +++ b/docs_new/docs/get-started/install.mdx @@ -35,6 +35,23 @@ uv pip install --force-reinstall sglang-kernel --index-url https://docs.sglang.a uv pip install --force-reinstall sgl-deep-gemm --index-url https://docs.sglang.ai/whl/cu129/ --no-deps ``` +### Nightly builds + +To pick up the latest features and fixes before the next stable release, install a nightly build. Nightly wheels are built from the latest `main` and published to the SGLang wheel index. Add that index with `--extra-index-url`, and combine `--prerelease=allow` with `--index-strategy unsafe-best-match` so uv considers the nightly (pre-release) version alongside PyPI: + +```bash Command +pip install --upgrade pip +pip install uv +uv pip install --prerelease=allow --index-strategy unsafe-best-match --extra-index-url https://docs.sglang.ai/whl/cu130/ sglang +``` + +To install a nightly build under Cuda 12, swap the index to `cu129`: +```bash Command +pip install --upgrade pip +pip install uv +uv pip install --prerelease=allow --index-strategy unsafe-best-match --extra-index-url https://docs.sglang.ai/whl/cu129/ sglang +``` + ### Quick fixes to common problems - If you encounter `OSError: CUDA_HOME environment variable is not set`. Please set it to your CUDA install root with either of the following solutions: 1. Use `export CUDA_HOME=/usr/local/cuda-` to set the `CUDA_HOME` environment variable. @@ -61,6 +78,10 @@ pip install -e "python" The docker images are available on Docker Hub at [lmsysorg/sglang](https://hub.docker.com/r/lmsysorg/sglang/tags), built from [Dockerfile](https://github.com/sgl-project/sglang/tree/main/docker). Replace `` below with your huggingface hub [token](https://huggingface.co/docs/hub/en/security-tokens). + +`latest` and `dev` are **mutable** tags: `latest` always points at the newest stable release, while `dev` is rebuilt daily from the latest `main` and includes build/development tools. Because they are overwritten over time, pin an immutable version tag for reproducible deployments — e.g. `lmsysorg/sglang:v0.5.12`. Browse all released versions on [Docker Hub](https://hub.docker.com/r/lmsysorg/sglang/tags). + + ```bash Command docker run --gpus all \ --shm-size 32g \ diff --git a/scripts/release/README.md b/scripts/release/README.md index df6508c52..eb5af785d 100644 --- a/scripts/release/README.md +++ b/scripts/release/README.md @@ -24,6 +24,18 @@ python scripts/release/bump_sglang_version.py 0.5.3rc0 - `python/pyproject_npu.toml` - `python/sglang/version.py` +### `bump_docs_install_version.py` +Bumps the release version pinned in the Mintlify install docs — both the `git clone -b v ...sglang.git` "install from source" line and the version-pinned `lmsysorg/sglang:v` Docker example. Mutable tags (`latest`, `dev`) are intentionally left untouched. Driven automatically on release-tag push by [`.github/workflows/bot-bump-docs-version.yml`](../../.github/workflows/bot-bump-docs-version.yml), which opens a PR with the change. + +**Usage:** +```bash +python scripts/release/bump_docs_install_version.py 0.5.13 +``` + +**Files updated:** +- `docs_new/docs/get-started/install.mdx` (Method 2: From source; Method 3: pinned Docker image) +- `docs_new/docs/hardware-platforms/amd_gpu.mdx` (Install from Source) + ### `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). diff --git a/scripts/release/bump_docs_install_version.py b/scripts/release/bump_docs_install_version.py new file mode 100755 index 000000000..37904c792 --- /dev/null +++ b/scripts/release/bump_docs_install_version.py @@ -0,0 +1,149 @@ +#!/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, +) + +# Docs pages that pin a release branch in their "install from source" snippet, +# e.g. `git clone -b v0.5.12 https://github.com/sgl-project/sglang.git`. +FILES_TO_UPDATE = [ + Path("docs_new/docs/get-started/install.mdx"), + Path("docs_new/docs/hardware-platforms/amd_gpu.mdx"), +] + +# Matches `git clone -b v https://github.com/sgl-project/sglang.git`, +# capturing the version (without the leading `v`) in group 2. +CLONE_RE = re.compile( + r"(git clone -b )v([0-9][0-9A-Za-z.\-]*)" + r"( https://github\.com/sgl-project/sglang\.git)" +) + +# Matches a version-pinned docker image such as `lmsysorg/sglang:v0.5.12` +# (leaving any suffix like `-cu130`/`-runtime` untouched), capturing the +# version in group 2. Mutable tags (`latest`, `dev`, ...) are not matched. +DOCKER_RE = re.compile(r"(lmsysorg/sglang:)v(\d+\.\d+\.\d+(?:rc\d+|\.post\d+)?)\b") + +# All version references the bump keeps in sync, each with the version in group 2. +VERSION_PATTERNS = [CLONE_RE, DOCKER_RE] + + +def read_current_version(file_path: Path) -> str: + """Read the pinned source-install version from a docs page.""" + match = CLONE_RE.search(file_path.read_text()) + if not match: + raise ValueError( + f"Could not find a 'git clone -b v ...sglang.git' line in {file_path}" + ) + return match.group(2) + + +def stale_versions(file_path: Path, new_version: str) -> list: + """Return any pinned versions in the file that differ from new_version.""" + content = file_path.read_text() + return [ + m.group(2) + for pattern in VERSION_PATTERNS + for m in pattern.finditer(content) + if m.group(2) != new_version + ] + + +def replace_version(file_path: Path, 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 = CLONE_RE.sub(rf"\g<1>v{new_version}\g<3>", content) + new_content = DOCKER_RE.sub(rf"\g<1>v{new_version}", new_content) + + 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 the 'install from source' release-branch version in the docs" + ) + parser.add_argument( + "new_version", + help="New version (e.g., 0.5.13, 0.5.13rc0, or 0.5.13.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.5.13, 0.5.13rc0, 0.5.13.post1") + sys.exit(1) + + repo_root = get_repo_root() + + # Determine the current version from the primary install page for logging. + primary = repo_root / FILES_TO_UPDATE[0] + old_version = read_current_version(primary) + print(f"Current docs install version: {old_version}") + print(f"New docs install version: {new_version}") + print() + + comparison = compare_versions(new_version, old_version) + if comparison == 0: + print("Docs are already at this version; nothing to do.") + return + elif comparison < 0: + print( + f"Warning: new version ({new_version}) is older than the docs version " + f"({old_version}); proceeding anyway." + ) + + updated_count = 0 + for file_rel in FILES_TO_UPDATE: + file_abs = repo_root / file_rel + if replace_version(file_abs, new_version): + updated_count += 1 + + print() + print(f"Successfully updated {updated_count} file(s)") + print(f"Docs install 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 + + stale = stale_versions(file_abs, new_version) + if stale: + failed_files.append(file_rel) + print(f"✗ {file_rel} still pins v{', v'.join(sorted(set(stale)))}") + 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()