From 75ee7bdfe5dc5816e1161aaaa2efd7979cf88a66 Mon Sep 17 00:00:00 2001 From: zhouaihui Date: Fri, 6 Nov 2026 14:29:08 +0800 Subject: [PATCH] Separate tag-triggered release builds from CI --- .github/workflows/build-release.yml | 82 +++++++++++++++++++++++++++++ .github/workflows/ci.yml | 53 +++---------------- CONTRIBUTING.md | 9 ++-- docs/releasing.md | 22 ++++++-- 4 files changed, 115 insertions(+), 51 deletions(-) create mode 100644 .github/workflows/build-release.yml diff --git a/.github/workflows/build-release.yml b/.github/workflows/build-release.yml new file mode 100644 index 0000000..08ea1d4 --- /dev/null +++ b/.github/workflows/build-release.yml @@ -0,0 +1,82 @@ +name: Build release + +on: + push: + tags: ["v*"] + +permissions: + contents: read + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v7 + - uses: actions/setup-python@v7 + with: + python-version: "3.11" + - name: Verify tag matches package version + env: + RELEASE_TAG: ${{ github.ref_name }} + run: | + python - <<'PY' + import os + import tomllib + from pathlib import Path + + version = tomllib.loads(Path("pyproject.toml").read_text())["project"]["version"] + expected = f"v{version}" + tag = os.environ["RELEASE_TAG"] + if tag != expected: + raise SystemExit(f"Release tag {tag!r} does not match package version: expected {expected!r}") + print(f"PASS release tag {tag}") + PY + - name: Install build tools + run: | + python -m venv "$RUNNER_TEMP/aspec-build-venv" + source "$RUNNER_TEMP/aspec-build-venv/bin/activate" + echo "$VIRTUAL_ENV/bin" >> "$GITHUB_PATH" + echo "VIRTUAL_ENV=$VIRTUAL_ENV" >> "$GITHUB_ENV" + python -m pip install --upgrade pip build + - name: Build source and wheel distributions + run: python -m tools.build_release --outdir dist + - name: Save audited distributions and runtime requirements + uses: actions/upload-artifact@v7 + with: + name: aspec-distributions + path: dist/ + if-no-files-found: error + + wheel-install: + needs: build + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v7 + - uses: actions/setup-python@v7 + with: + python-version: "3.11" + - uses: actions/download-artifact@v8 + with: + name: aspec-distributions + path: dist/ + - name: Verify distribution checksums + working-directory: dist + run: sha256sum --check SHA256SUMS + - name: Prepare isolated CPU installation fixture + run: | + python -m venv "$RUNNER_TEMP/aspec-wheel-venv" + source "$RUNNER_TEMP/aspec-wheel-venv/bin/activate" + echo "$VIRTUAL_ENV/bin" >> "$GITHUB_PATH" + echo "VIRTUAL_ENV=$VIRTUAL_ENV" >> "$GITHUB_ENV" + python -m pip install --upgrade pip + python -m pip install --index-url https://download.pytorch.org/whl/cpu torch==2.13.0+cpu + python -m pip install -r requirements/ci-cpu.txt + # Deliberately test the wheel and patch CLI with a CPU dependency subset. + # This is not installation/acceptance of the production GPU runtime. + python -m pip install --no-deps dist/*.whl sglang==0.5.21 + - name: Exercise installed commands outside the checkout + env: + CUDA_VISIBLE_DEVICES: "" + HF_HUB_OFFLINE: "1" + TRANSFORMERS_OFFLINE: "1" + run: python tools/check_wheel_install.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 190e491..e1a5480 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,29 +10,26 @@ permissions: contents: read jobs: - quality-and-package: + quality: runs-on: ubuntu-latest steps: - uses: actions/checkout@v7 - uses: actions/setup-python@v7 with: python-version: "3.11" - - name: Install build tools - run: python -m pip install --upgrade build ruff + - name: Install quality tools + run: | + python -m venv "$RUNNER_TEMP/aspec-quality-venv" + source "$RUNNER_TEMP/aspec-quality-venv/bin/activate" + echo "$VIRTUAL_ENV/bin" >> "$GITHUB_PATH" + echo "VIRTUAL_ENV=$VIRTUAL_ENV" >> "$GITHUB_ENV" + python -m pip install --upgrade pip ruff - name: Lint run: python -m ruff check aspec tests tools setup.py - name: Compile Python sources run: python -m compileall -q aspec tests tools - name: Check maintained documentation links run: python -m tools.check_docs - - name: Build source and wheel distributions - run: python -m tools.build_release --outdir dist - - name: Save audited distributions and runtime requirements - uses: actions/upload-artifact@v7 - with: - name: aspec-distributions - path: dist/ - if-no-files-found: error cpu-contract-tests: runs-on: ubuntu-latest @@ -89,37 +86,3 @@ jobs: tests/test_reporting.py \ tests/test_training_config_validation.py python -m pytest -q tests/test_wheel_assets.py tests/test_sglang_patch_contract.py - - wheel-install: - needs: quality-and-package - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v7 - - uses: actions/setup-python@v7 - with: - python-version: "3.11" - - uses: actions/download-artifact@v8 - with: - name: aspec-distributions - path: dist/ - - name: Verify distribution checksums - working-directory: dist - run: sha256sum --check SHA256SUMS - - name: Prepare isolated CPU installation fixture - run: | - python -m venv "$RUNNER_TEMP/aspec-wheel-venv" - source "$RUNNER_TEMP/aspec-wheel-venv/bin/activate" - echo "$VIRTUAL_ENV/bin" >> "$GITHUB_PATH" - echo "VIRTUAL_ENV=$VIRTUAL_ENV" >> "$GITHUB_ENV" - python -m pip install --upgrade pip - python -m pip install --index-url https://download.pytorch.org/whl/cpu torch==2.13.0+cpu - python -m pip install -r requirements/ci-cpu.txt - # Deliberately test the wheel and patch CLI with a CPU dependency subset. - # This is not installation/acceptance of the production GPU runtime. - python -m pip install --no-deps dist/*.whl sglang==0.5.21 - - name: Exercise installed commands outside the checkout - env: - CUDA_VISIBLE_DEVICES: "" - HF_HUB_OFFLINE: "1" - TRANSFORMERS_OFFLINE: "1" - run: python tools/check_wheel_install.py diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d748489..b7a2c14 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -30,9 +30,12 @@ python -m tools.build_release --outdir /absolute/path/to/new-release-dist Default tests are fast/offline. GPU, tokenizer, training and cuDNN gates need explicit switches declared in their test files. A skip is not GPU acceptance. Public CI checks lint, local doc links, -compilation and packaging, plus a curated CPU/offline contract suite installed from -`requirements/ci-cpu.txt`; it does not certify GPU health or replace the complete pinned-runtime -suite above. Equivalent remote checks are not proof that hosted GitHub Actions has already run. +compilation, plus a curated CPU/offline contract suite installed from `requirements/ci-cpu.txt` +on pull requests and configured branch pushes. The separate [release build](.github/workflows/build-release.yml) +workflow builds and audits sdist/wheel artifacts and checks wheel installation only when a `v*` tag +is pushed; see [release instructions](docs/releasing.md). Neither workflow certifies GPU health or +replaces the complete pinned-runtime suite above. Equivalent remote checks are not proof that hosted +GitHub Actions has already run. For runtime/attention/data-plane changes, use the relevant [GPU and fault checks](docs/contributing/validation.md). Do not clean shared hosts with host-wide Ray/process commands. Follow the current task's remote environment diff --git a/docs/releasing.md b/docs/releasing.md index c45ecbe..aa50eba 100644 --- a/docs/releasing.md +++ b/docs/releasing.md @@ -27,9 +27,16 @@ This command builds the sdist and then its wheel, audits both, collects the two files under `runtime/`, and writes `SHA256SUMS`. It rejects a nonempty output directory. `python -m build` and `python -m tools.audit_release DIST` remain available separately. -[GitHub CI](../.github/workflows/ci.yml) runs the same build command, saves the audited release bundle -as the `aspec-distributions` workflow artifact, and runs an independent `wheel-install` job on -Python 3.11. That job checks SHA256s, installs the built wheel in a dedicated CPU venv, and executes: +[GitHub CI](../.github/workflows/ci.yml) runs source quality checks and CPU/offline contracts on pull +requests and configured branch pushes. It does not build distributions. Packaging-related source +contracts remain in that suite so resource and audit regressions can be found before tagging. + +The separate [release build workflow](../.github/workflows/build-release.yml) runs when a `v*` tag is +pushed to GitHub. Creating a local tag alone does not trigger it. The tag must exactly match `v` plus +the version in `pyproject.toml`, for example `v0.1.0rc1` for `0.1.0rc1`; a mismatch fails before +building. The workflow runs the same build command, saves the audited release bundle as the +`aspec-distributions` workflow artifact, and runs a dependent `wheel-install` job on Python 3.11. +That job checks SHA256s, installs the built wheel in a dedicated CPU venv, and executes: ```bash python tools/check_wheel_install.py @@ -61,6 +68,15 @@ an enclosing checkout; unavailable build revision remains unknown. ## Publish +Before pushing a version tag, verify that its exact commit has passed the CI source checks and the +applicable release checks above. The tag workflow does not rerun the source test suite. After pushing, +require both `build` and `wheel-install` to pass; an uploaded artifact alone is not installation +acceptance. A failed run can be rerun for the same tag after an infrastructure issue is resolved; +source fixes require a new reviewed commit and version/tag. + +The release build only saves Actions artifacts. It does not create a GitHub Release or publish to +PyPI; publication is a separate, explicitly authorized step. + Review the exact artifacts, repository destination, version/tag and release notes. Summarize checks actually performed and any known limitations. Publish only the reviewed source and artifacts; retain the corresponding build and validation records separately.