chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
# Since dependabot cannot update workflows using docker,
|
||||
# we use this indirection since dependabot can update this file.
|
||||
FROM rhysd/actionlint:1.7.7@sha256:887a259a5a534f3c4f36cb02dca341673c6089431057242cdc931e9f133147e9
|
||||
@@ -0,0 +1,52 @@
|
||||
name: Lint GitHub Actions workflows
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- "dev"
|
||||
- "release-**"
|
||||
paths:
|
||||
- '.github/actions/*.ya?ml'
|
||||
- '.github/workflows/*.ya?ml'
|
||||
- '.github/workflows/actionlint.*' # This workflow
|
||||
pull_request:
|
||||
branches:
|
||||
- "dev"
|
||||
- "release-**"
|
||||
paths:
|
||||
- '.github/actions/*.ya?ml'
|
||||
- '.github/workflows/*.ya?ml'
|
||||
- '.github/workflows/actionlint.*' # This workflow
|
||||
|
||||
env:
|
||||
LC_ALL: en_US.UTF-8
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
actionlint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: "Harden Runner"
|
||||
uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0
|
||||
with:
|
||||
disable-sudo-and-containers: false
|
||||
egress-policy: audit
|
||||
|
||||
- name: "Checkout"
|
||||
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: "Download actionlint"
|
||||
run: |
|
||||
docker build --tag actionlint - < .github/workflows/actionlint.dockerfile
|
||||
|
||||
- name: "Check workflow files"
|
||||
run: |
|
||||
echo "::add-matcher::.github/workflows/matchers/actionlint.json"
|
||||
docker run --volume="${PWD}:/repo" --workdir=/repo actionlint -color
|
||||
@@ -0,0 +1,142 @@
|
||||
# Optional Aerospike native L2 integration (BUILD_AEROSPIKE=1 + CE Docker).
|
||||
name: Aerospike integration
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- "dev"
|
||||
- "release-**"
|
||||
paths:
|
||||
- "csrc/storage_backends/aerospike/**"
|
||||
- "lmcache/v1/distributed/l2_adapters/aerospike_l2_adapter.py"
|
||||
- "lmcache/v1/storage_backend/native_clients/aerospike_client.py"
|
||||
- "setup.py"
|
||||
- "tests/aerospike_ce.conf.template"
|
||||
- "tests/v1/distributed/test_aerospike_*"
|
||||
- ".github/workflows/aerospike_integration.yml"
|
||||
pull_request:
|
||||
branches:
|
||||
- "dev"
|
||||
- "release-**"
|
||||
paths:
|
||||
- "csrc/storage_backends/aerospike/**"
|
||||
- "lmcache/v1/distributed/l2_adapters/aerospike_l2_adapter.py"
|
||||
- "lmcache/v1/storage_backend/native_clients/aerospike_client.py"
|
||||
- "setup.py"
|
||||
- "tests/aerospike_ce.conf.template"
|
||||
- "tests/v1/distributed/test_aerospike_*"
|
||||
- ".github/workflows/aerospike_integration.yml"
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
env:
|
||||
AEROSPIKE_CLIENT_C_VERSION: "7.3.0"
|
||||
AEROSPIKE_CLIENT_C_UBUNTU: "ubuntu22.04"
|
||||
AEROSPIKE_CONTAINER_NAME: lmcache-aerospike-ci
|
||||
|
||||
jobs:
|
||||
aerospike-native-l2:
|
||||
name: Aerospike native L2
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
||||
with:
|
||||
python-version: "3.12"
|
||||
cache: pip
|
||||
|
||||
- name: Install Aerospike C client (prebuilt)
|
||||
run: |
|
||||
set -euo pipefail
|
||||
DEPS="${GITHUB_WORKSPACE}/.deps"
|
||||
INSTALL="${DEPS}/aerospike-install"
|
||||
VERSION="${AEROSPIKE_CLIENT_C_VERSION}"
|
||||
UBUNTU="${AEROSPIKE_CLIENT_C_UBUNTU}"
|
||||
BASE="aerospike-client-c-libuv_${VERSION}_${UBUNTU}_x86_64"
|
||||
URL="https://download.aerospike.com/artifacts/aerospike-client-c/${VERSION}/${BASE}.tgz"
|
||||
mkdir -p "${DEPS}"
|
||||
curl -fsSL -o "${DEPS}/${BASE}.tgz" "${URL}"
|
||||
tar xzf "${DEPS}/${BASE}.tgz" -C "${DEPS}"
|
||||
rm -rf "${INSTALL}"
|
||||
mkdir -p "${INSTALL}"
|
||||
dpkg-deb -x "${DEPS}/${BASE}/aerospike-client-c-libuv-devel_${VERSION}-${UBUNTU}_amd64.deb" "${INSTALL}"
|
||||
dpkg-deb -x "${DEPS}/${BASE}/aerospike-client-c-libuv_${VERSION}-${UBUNTU}_amd64.deb" "${INSTALL}"
|
||||
sudo apt-get update -qq
|
||||
sudo apt-get install -y -qq libyaml-0-2 libuv1-dev
|
||||
(cd "${DEPS}" && apt download libyaml-dev && \
|
||||
rm -rf libyaml-install && mkdir -p libyaml-install && \
|
||||
dpkg-deb -x libyaml-dev_*.deb libyaml-install)
|
||||
{
|
||||
echo "AEROSPIKE_INCLUDE_DIR=${INSTALL}/usr/include"
|
||||
echo "AEROSPIKE_LIBRARY_DIR=${INSTALL}/usr/lib"
|
||||
echo "LD_LIBRARY_PATH=${INSTALL}/usr/lib:${DEPS}/libyaml-install/usr/lib/x86_64-linux-gnu"
|
||||
} >> "${GITHUB_ENV}"
|
||||
|
||||
- name: Build LMCache with Aerospike extension
|
||||
run: |
|
||||
set -euo pipefail
|
||||
python -m pip install --upgrade pip wheel
|
||||
python -m pip install 'setuptools>=77.0.3,<81.0.0' 'pybind11>=2.12'
|
||||
python -m pip install numpy
|
||||
python -m pip install torch --index-url https://download.pytorch.org/whl/cpu
|
||||
export BUILD_AEROSPIKE=1
|
||||
export NO_GPU_EXT=1
|
||||
python -m pip install -e . --no-build-isolation
|
||||
python -m pip install 'aerospike>=14.0.0,<19.0.0' pytest
|
||||
python -c "from lmcache.lmcache_aerospike import LMCacheAerospikeClient; print('OK:', LMCacheAerospikeClient)"
|
||||
|
||||
- name: Start Aerospike CE
|
||||
id: aerospike
|
||||
run: |
|
||||
set -euo pipefail
|
||||
HOST_PORT=$(python -c 'import socket; s=socket.socket(); s.bind(("", 0)); print(s.getsockname()[1]); s.close()')
|
||||
CONF_DIR=$(mktemp -d)
|
||||
sed "s/__ACCESS_PORT__/${HOST_PORT}/g" tests/aerospike_ce.conf.template > "${CONF_DIR}/aerospike.conf"
|
||||
docker rm -f "${AEROSPIKE_CONTAINER_NAME}" 2>/dev/null || true
|
||||
docker run -d \
|
||||
--name "${AEROSPIKE_CONTAINER_NAME}" \
|
||||
-p "${HOST_PORT}:3000" \
|
||||
-v "${CONF_DIR}/aerospike.conf:/etc/aerospike/aerospike.template.conf:ro" \
|
||||
aerospike/aerospike-server:latest
|
||||
deadline=$((SECONDS + 90))
|
||||
until docker exec "${AEROSPIKE_CONTAINER_NAME}" asinfo -v status 2>/dev/null | grep -qE 'ok|normal'; do
|
||||
if (( SECONDS >= deadline )); then
|
||||
docker logs "${AEROSPIKE_CONTAINER_NAME}" 2>&1 | tail -80
|
||||
exit 1
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
host_deadline=$((SECONDS + 90))
|
||||
until python -c "
|
||||
import aerospike
|
||||
c = aerospike.client({'hosts': [('127.0.0.1', ${HOST_PORT})]})
|
||||
c.connect()
|
||||
info = c.info_random_node('namespace/lmcache')
|
||||
c.close()
|
||||
assert 'nsup-period=120' in info
|
||||
"; do
|
||||
if (( SECONDS >= host_deadline )); then
|
||||
docker logs "${AEROSPIKE_CONTAINER_NAME}" 2>&1 | tail -80
|
||||
exit 1
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
{
|
||||
echo "AEROSPIKE_TEST_HOST=127.0.0.1"
|
||||
echo "AEROSPIKE_TEST_PORT=${HOST_PORT}"
|
||||
echo "AEROSPIKE_TEST_NAMESPACE=lmcache"
|
||||
echo "RUN_AEROSPIKE_INTEGRATION=1"
|
||||
} >> "${GITHUB_ENV}"
|
||||
|
||||
- name: Integration tests
|
||||
run: |
|
||||
pytest tests/v1/distributed/test_aerospike_l2_integration.py -v --tb=short
|
||||
|
||||
- name: Stop Aerospike CE
|
||||
if: always()
|
||||
run: docker rm -f "${AEROSPIKE_CONTAINER_NAME}" 2>/dev/null || true
|
||||
@@ -0,0 +1,17 @@
|
||||
name: Label auto-merge PRs
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [ auto_merge_enabled, auto_merge_disabled ]
|
||||
|
||||
permissions:
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
add_remove_labels:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: ubuntudroid/automerge-labeler@v1
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
label: 'full'
|
||||
@@ -0,0 +1,106 @@
|
||||
name: Build CLI Artifacts
|
||||
|
||||
# Reusable workflow that builds the pure-Python lmcache-cli wheel (no CUDA).
|
||||
# Uploaded as the `release-cli-artifacts` GHA artifact.
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
pull_request:
|
||||
branches:
|
||||
- dev
|
||||
- "release-**"
|
||||
paths:
|
||||
- 'lmcache/cli/**.py'
|
||||
- 'pyproject_cli.toml'
|
||||
- 'requirements/cli.txt'
|
||||
- '.github/workflows/build_cli_artifacts.yml'
|
||||
|
||||
env:
|
||||
LC_ALL: en_US.UTF-8
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
# Cancel older in-flight runs on the same PR / branch.
|
||||
concurrency:
|
||||
group: build-cli-${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build-cli-artifacts:
|
||||
name: Build CLI artifacts
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: "Harden Runner"
|
||||
uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0
|
||||
with:
|
||||
disable-sudo-and-containers: false
|
||||
egress-policy: audit
|
||||
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
# Keep stable vX.Y.Z and rc/a/b pre-release tags; strip variant tags
|
||||
# (v*-cu129, v*-alpha) that yield invalid PEP 440 versions (see #3123).
|
||||
- name: Remove non-release tags (keep stable + rc/a/b pre-releases)
|
||||
run: git tag -l | grep -vE '^v[0-9]+\.[0-9]+\.[0-9]+((rc|a|b)[0-9]+)?$' | xargs -r git tag -d
|
||||
|
||||
- name: Setup Python 3.13
|
||||
uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0
|
||||
with:
|
||||
python-version: "3.13"
|
||||
|
||||
- name: Install build tooling
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install build
|
||||
|
||||
- name: Clean up release artifacts
|
||||
run: |
|
||||
rm -rf dist/
|
||||
|
||||
- name: Build lmcache-cli wheel (pure Python, no native extensions)
|
||||
run: |
|
||||
cp pyproject_cli.toml pyproject.toml
|
||||
NO_NATIVE_EXT=1 python -m build --wheel
|
||||
|
||||
- name: Smoke-test CLI wheel (no torch)
|
||||
run: |
|
||||
pip install dist/lmcache_cli-*.whl
|
||||
|
||||
# CLI wheel must be pure-Python: no compiled extension bundled.
|
||||
if unzip -l dist/lmcache_cli-*.whl | grep -E '\.(so|pyd)$'; then
|
||||
echo "::error::CLI wheel contains compiled extensions; should be pure-Python"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Pure-Python surface must import without torch / native ops.
|
||||
python -c "import lmcache"
|
||||
|
||||
# Native CUDA ops must be unreachable from the slim wheel.
|
||||
if python -c "import lmcache.c_ops" 2>/dev/null; then
|
||||
echo "::error::CLI wheel can import lmcache.c_ops; native ops must be absent from the pure-Python wheel"
|
||||
exit 1
|
||||
fi
|
||||
echo "OK: lmcache.c_ops is not importable from the CLI wheel"
|
||||
|
||||
lmcache --help
|
||||
|
||||
# Slim-supported subcommands only (server is full-only).
|
||||
for cmd in mock kvcache describe ping query bench tool trace; do
|
||||
echo "::group::lmcache $cmd --help"
|
||||
lmcache "$cmd" --help
|
||||
echo "::endgroup::"
|
||||
done
|
||||
|
||||
- name: Upload CLI release artifacts to GHA
|
||||
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
|
||||
with:
|
||||
name: release-cli-artifacts
|
||||
path: dist/
|
||||
@@ -0,0 +1,122 @@
|
||||
name: Build CPU Artifacts
|
||||
|
||||
# Build LMCache with NO_GPU_EXT=1 (common C++ extensions only).
|
||||
# Gates the CPU-only build path against regression.
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
pull_request:
|
||||
branches:
|
||||
- dev
|
||||
- "release-**"
|
||||
paths:
|
||||
- 'setup.py'
|
||||
- 'pyproject.toml'
|
||||
- 'csrc/**'
|
||||
- 'requirements/common.txt'
|
||||
- 'requirements/build.txt'
|
||||
- 'lmcache/__init__.py'
|
||||
- '.github/workflows/build_cpu_artifacts.yml'
|
||||
|
||||
env:
|
||||
LC_ALL: en_US.UTF-8
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
# Cancel stale runs per ref.
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build-cpu-artifacts:
|
||||
name: Build CPU artifacts
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: "Harden Runner"
|
||||
uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0
|
||||
with:
|
||||
disable-sudo-and-containers: false
|
||||
egress-policy: audit
|
||||
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Remove non-release tags
|
||||
run: git tag -l | grep -vE '^v[0-9]+\.[0-9]+\.[0-9]+$' | xargs -r git tag -d
|
||||
|
||||
- name: Setup Python 3.13
|
||||
uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0
|
||||
with:
|
||||
python-version: "3.13"
|
||||
|
||||
- name: Install build tooling and CPU torch
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install --index-url https://download.pytorch.org/whl/cpu torch
|
||||
# Pre-install build deps for --no-isolation below.
|
||||
pip install -r requirements/build.txt
|
||||
pip install build
|
||||
|
||||
- name: Clean up release artifacts
|
||||
run: |
|
||||
rm -rf dist/
|
||||
|
||||
- name: Build CPU-only wheel (common C++ extensions, no GPU backend)
|
||||
# --skip-dependency-check: the pre-installed CPU torch may not
|
||||
# match pyproject.toml's exact build-system pin, but is ABI-
|
||||
# compatible for compiling CppExtensions.
|
||||
run: |
|
||||
NO_GPU_EXT=1 python -m build --wheel --no-isolation \
|
||||
--skip-dependency-check
|
||||
|
||||
- name: Verify CPU wheel contents
|
||||
run: |
|
||||
set -e
|
||||
# Required: common C++ extensions.
|
||||
for mod in native_storage_ops lmcache_redis lmcache_fs; do
|
||||
if ! unzip -l dist/lmcache-*.whl | grep -qE "lmcache/${mod}\..*\.so"; then
|
||||
echo "::error::missing common C++ extension: ${mod}"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
# Forbidden: GPU extensions.
|
||||
for mod in c_ops xpu_ops; do
|
||||
if unzip -l dist/lmcache-*.whl | grep -qE "lmcache/${mod}\..*\.so"; then
|
||||
echo "::error::unexpected GPU extension in CPU wheel: ${mod}"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
- name: Smoke-test CPU wheel
|
||||
# Run from $RUNNER_TEMP so Python resolves `lmcache` from the
|
||||
# installed wheel, not the checkout on CWD.
|
||||
working-directory: ${{ runner.temp }}
|
||||
run: |
|
||||
set -e
|
||||
pip install ${{ github.workspace }}/dist/lmcache-*.whl
|
||||
python -c "
|
||||
import lmcache
|
||||
assert lmcache.torch_device_type == 'cpu', lmcache.torch_device_type
|
||||
"
|
||||
python -c "import lmcache.native_storage_ops"
|
||||
python -c "import lmcache.lmcache_redis"
|
||||
python -c "import lmcache.lmcache_fs"
|
||||
# c_ops resolves to the python_ops_fallback shim on CPU.
|
||||
python -c "
|
||||
import sys, lmcache, lmcache.c_ops
|
||||
assert sys.modules['lmcache.c_ops'].__name__ == 'lmcache.python_ops_fallback'
|
||||
"
|
||||
|
||||
- name: Upload CPU release artifacts to GHA
|
||||
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
|
||||
with:
|
||||
name: release-cpu-artifacts
|
||||
path: dist/
|
||||
@@ -0,0 +1,105 @@
|
||||
name: Build cu129 Artifacts
|
||||
|
||||
# Reusable workflow that builds the cu129 CUDA 12.9 wheel via cibuildwheel
|
||||
# against the pytorch manylinux cu12.9 base image.
|
||||
# Uploaded as the `release-cu129-artifacts` GHA artifact.
|
||||
# The cu12.9 wheel carries no local version suffix and is published to a
|
||||
# dedicated v{tag}-cu12 GitHub Release (not PyPI).
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
|
||||
env:
|
||||
LC_ALL: en_US.UTF-8
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build-cu129-artifacts:
|
||||
name: Build cu129 artifacts
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: "Harden Runner"
|
||||
uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0
|
||||
with:
|
||||
disable-sudo-and-containers: false
|
||||
egress-policy: audit
|
||||
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
# Keep stable vX.Y.Z and rc/a/b pre-release tags; strip variant tags
|
||||
# (v*-cu129, v*-alpha) that yield invalid PEP 440 versions (see #3123).
|
||||
- name: Remove non-release tags (keep stable + rc/a/b pre-releases)
|
||||
run: git tag -l | grep -vE '^v[0-9]+\.[0-9]+\.[0-9]+((rc|a|b)[0-9]+)?$' | xargs -r git tag -d
|
||||
|
||||
- name: Login to DockerHub
|
||||
# Skip when either the username var or the token secret is
|
||||
# absent. Secrets are not inherited into reusable workflows
|
||||
# without `secrets: inherit`, and fork PRs never get secrets,
|
||||
# so the token can legitimately be empty on some runs.
|
||||
if: vars.DOCKERHUB_USERNAME != '' && env.DOCKERHUB_TOKEN != ''
|
||||
env:
|
||||
DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
|
||||
with:
|
||||
username: ${{ vars.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Free disk space
|
||||
uses: ./.github/actions/free-disk-space
|
||||
|
||||
- name: Setup Python 3.13
|
||||
uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0
|
||||
with:
|
||||
python-version: "3.13"
|
||||
|
||||
- name: Install build tooling
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install build cibuildwheel
|
||||
|
||||
- name: Clean up release artifacts
|
||||
run: |
|
||||
rm -rf dist/
|
||||
|
||||
- name: Get base version for cu12.9 wheel
|
||||
run: |
|
||||
if [[ "${GITHUB_REF}" == refs/tags/v* ]]; then
|
||||
BASE="${GITHUB_REF_NAME#v}"
|
||||
else
|
||||
BASE=$(git tag --list 'v[0-9]*' | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | sort -V | tail -1 | sed 's/^v//' || echo "0.0.0.dev")
|
||||
fi
|
||||
echo "CU129_VERSION=${BASE}" >> "$GITHUB_ENV"
|
||||
|
||||
- name: Build cu12.9 CUDA wheels with cibuildwheel
|
||||
env:
|
||||
CIBW_MANYLINUX_X86_64_IMAGE: docker.io/pytorch/manylinux2_28-builder:cuda12.9
|
||||
CIBW_ENVIRONMENT: 'TORCH_CUDA_ARCH_LIST="7.0;7.5;8.0;8.6;8.9;9.0;10.0;12.0" ENABLE_CXX11_ABI=1 LMCACHE_CUDA_MAJOR=12 SETUPTOOLS_SCM_PRETEND_VERSION=${{ env.CU129_VERSION }} PIP_EXTRA_INDEX_URL=https://download.pytorch.org/whl/cu129'
|
||||
CIBW_REPAIR_WHEEL_COMMAND_LINUX: >-
|
||||
auditwheel repair
|
||||
--plat manylinux_2_28_x86_64
|
||||
--exclude libtorch.so
|
||||
--exclude libtorch_cuda.so
|
||||
--exclude libtorch_python.so
|
||||
--exclude libtorch_cpu.so
|
||||
--exclude libc10.so
|
||||
--exclude libc10_cuda.so
|
||||
--exclude libcudart.so.12
|
||||
-w {dest_dir} {wheel}
|
||||
CIBW_TEST_COMMAND: "python -c 'import lmcache.c_ops'"
|
||||
run: |
|
||||
python -m cibuildwheel --output-dir dist
|
||||
|
||||
- name: Upload cu12.9 release artifacts to GHA
|
||||
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
|
||||
with:
|
||||
name: release-cu129-artifacts
|
||||
path: dist/
|
||||
@@ -0,0 +1,106 @@
|
||||
name: Build and Deploy Online Documentation
|
||||
|
||||
on:
|
||||
# Trigger the workflow on push request,
|
||||
# for the dev branch
|
||||
push:
|
||||
branches:
|
||||
- 'dev'
|
||||
paths:
|
||||
- 'docs/**'
|
||||
- 'lmcache/**'
|
||||
- 'examples/**'
|
||||
- '.github/workflows/build_doc.yml'
|
||||
jobs:
|
||||
build-docs:
|
||||
name: Build docs
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
||||
with:
|
||||
# Full git history needed for sphinx-multiversion to detect all tags/branches
|
||||
fetch-depth: 0
|
||||
# Fetch all branches and tags
|
||||
fetch-tags: true
|
||||
|
||||
- name: Setup Python 3.13
|
||||
uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0
|
||||
with:
|
||||
python-version: "3.13"
|
||||
|
||||
- name: Install Dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install -r requirements/docs.txt
|
||||
|
||||
- name: Build Versioned Sphinx Documentation
|
||||
run: |
|
||||
sphinx-multiversion docs/source output
|
||||
SPHINX_LANGUAGE=zh_CN sphinx-multiversion docs/source output-zh
|
||||
continue-on-error: false
|
||||
|
||||
- name: Setup root docs, .nojekyll, and Chinese docs
|
||||
run: |
|
||||
touch output/.nojekyll
|
||||
# Copy dev docs to root (latest docs at root URL)
|
||||
cp -r output/dev/* output/
|
||||
# Remove dev directory to avoid duplication
|
||||
rm -rf output/dev
|
||||
# Copy Chinese dev docs to /zh_CN/ and versioned docs under /zh_CN/<version>/
|
||||
mkdir -p output/zh_CN
|
||||
cp -r output-zh/dev/* output/zh_CN/
|
||||
rm -rf output-zh/dev
|
||||
cp -r output-zh/. output/zh_CN/
|
||||
rm -rf output-zh
|
||||
|
||||
- name: Upload doc artifacts to GHA
|
||||
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
|
||||
with:
|
||||
name: doc-artifacts
|
||||
path: output/
|
||||
|
||||
deploy-docs:
|
||||
name: Deploy docs online
|
||||
runs-on: ubuntu-latest
|
||||
needs: build-docs
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Fetch doc artifacts
|
||||
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
|
||||
with:
|
||||
name: doc-artifacts
|
||||
path: output
|
||||
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
||||
with:
|
||||
repository: LM-Cache-Website/lm-cache-website.github.io
|
||||
token: ${{ secrets.LMCACHE_DOC }}
|
||||
path: target-repo
|
||||
|
||||
- name: Copy Files to Target Repository
|
||||
run: |
|
||||
cp -r output/* target-repo/
|
||||
|
||||
- name: Commit and Push to Target Repository
|
||||
run: |
|
||||
cd target-repo
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "github-actions@github.com"
|
||||
git add .
|
||||
if ! git diff --cached --quiet; then
|
||||
git commit -m "Deploy updated online docs"
|
||||
git push https://x-access-token:${{ secrets.LMCACHE_DOC }}@github.com/LM-Cache-Website/lm-cache-website.github.io.git main --force
|
||||
else
|
||||
echo "No changes to commit."
|
||||
fi
|
||||
@@ -0,0 +1,82 @@
|
||||
name: Build Main Artifacts
|
||||
|
||||
# Reusable workflow that builds the main release artifacts:
|
||||
# - source distribution (tar ball)
|
||||
# - CUDA wheel (built via cibuildwheel, latest torch)
|
||||
# Uploaded as the `release-artifacts` GHA artifact.
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
|
||||
env:
|
||||
LC_ALL: en_US.UTF-8
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build-artifacts:
|
||||
name: Build artifacts
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: "Harden Runner"
|
||||
uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0
|
||||
with:
|
||||
disable-sudo-and-containers: false
|
||||
egress-policy: audit
|
||||
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
||||
with:
|
||||
# for setuptools-scm
|
||||
fetch-depth: 0
|
||||
|
||||
# Keep stable vX.Y.Z and rc/a/b pre-release tags; strip variant tags
|
||||
# (v*-cu129, v*-alpha) that yield invalid PEP 440 versions (see #3123).
|
||||
- name: Remove non-release tags (keep stable + rc/a/b pre-releases)
|
||||
run: git tag -l | grep -vE '^v[0-9]+\.[0-9]+\.[0-9]+((rc|a|b)[0-9]+)?$' | xargs -r git tag -d
|
||||
|
||||
- name: Pin release version from tag (setuptools-scm)
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
run: echo "SETUPTOOLS_SCM_PRETEND_VERSION=${GITHUB_REF_NAME#v}" >> "$GITHUB_ENV"
|
||||
|
||||
- name: Free disk space
|
||||
uses: ./.github/actions/free-disk-space
|
||||
|
||||
- name: Setup Python 3.13
|
||||
uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0
|
||||
with:
|
||||
python-version: "3.13"
|
||||
|
||||
- name: Install build tooling
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install build cibuildwheel
|
||||
|
||||
- name: Clean up release artifacts
|
||||
run: |
|
||||
rm -rf dist/
|
||||
|
||||
- name: Build source distribution (no native extensions)
|
||||
run: |
|
||||
NO_NATIVE_EXT=1 python -m build --sdist
|
||||
|
||||
- name: Build CUDA wheels with cibuildwheel
|
||||
# Configuration is set in pyproject.toml
|
||||
# this will build lmcache with the latest version of torch
|
||||
# building from source will be required if a serving engine uses
|
||||
# an earlier non-ABI compatible version of torch
|
||||
env:
|
||||
CIBW_TEST_COMMAND: "python -c 'import lmcache.c_ops'"
|
||||
run: |
|
||||
python -m cibuildwheel --output-dir dist
|
||||
|
||||
- name: Upload release artifacts to GHA
|
||||
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
|
||||
with:
|
||||
name: release-artifacts
|
||||
path: dist/
|
||||
@@ -0,0 +1,68 @@
|
||||
name: Code Quality
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
pull_request:
|
||||
|
||||
# Cancel older in-flight runs on the same PR / branch.
|
||||
concurrency:
|
||||
group: code-quality-${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
changes:
|
||||
name: Detect changes
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
pull-requests: read
|
||||
outputs:
|
||||
lmcache: ${{ github.event_name == 'release' || steps.filter.outputs.lmcache == 'true' }}
|
||||
steps:
|
||||
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
||||
if: github.event_name == 'push'
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
- uses: dorny/paths-filter@v3
|
||||
if: github.event_name == 'push' || github.event_name == 'pull_request'
|
||||
id: filter
|
||||
with:
|
||||
filters: |
|
||||
lmcache:
|
||||
- '**'
|
||||
- '!operator/**'
|
||||
- '!.github/workflows/operator_*.yml'
|
||||
|
||||
pre-commit:
|
||||
needs: changes
|
||||
if: needs.changes.outputs.lmcache == 'true'
|
||||
name: Check code quality
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0
|
||||
with:
|
||||
disable-sudo-and-containers: true
|
||||
egress-policy: audit
|
||||
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
||||
with:
|
||||
# for setuptools-scm
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup Python 3.13
|
||||
uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0
|
||||
with:
|
||||
python-version: "3.13"
|
||||
|
||||
- run: echo "::add-matcher::.github/workflows/matchers/mypy.json"
|
||||
|
||||
- name: Run code quality checks - lint, format, spell, & static checks
|
||||
uses: pre-commit/action@2c7b3805fd2a0fd8c1884dcaebf91fc102a13ecd # v3.0.1
|
||||
with:
|
||||
extra_args: --all-files
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
# For most projects, this workflow file will not need changing; you simply need
|
||||
# to commit it to your repository.
|
||||
#
|
||||
# You may wish to alter this file to override the set of languages analyzed,
|
||||
# or to provide custom queries or build logic.
|
||||
#
|
||||
# ******** NOTE ********
|
||||
# We have attempted to detect the languages in your repository. Please check
|
||||
# the `language` matrix defined below to confirm you have the correct set of
|
||||
# supported CodeQL languages.
|
||||
#
|
||||
name: "CodeQL Advanced"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "dev" ]
|
||||
pull_request:
|
||||
branches: [ "dev" ]
|
||||
schedule:
|
||||
- cron: '29 4 * * 0'
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze (${{ matrix.language }})
|
||||
# Runner size impacts CodeQL analysis time. To learn more, please see:
|
||||
# - https://gh.io/recommended-hardware-resources-for-running-codeql
|
||||
# - https://gh.io/supported-runners-and-hardware-resources
|
||||
# - https://gh.io/using-larger-runners (GitHub.com only)
|
||||
# Consider using larger runners or machines with greater resources for possible analysis time improvements.
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
# required for all workflows
|
||||
security-events: write
|
||||
|
||||
# required to fetch internal or private CodeQL packs
|
||||
packages: read
|
||||
|
||||
# only required for workflows in private repositories
|
||||
actions: read
|
||||
contents: read
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- language: actions
|
||||
build-mode: none
|
||||
# Disable C/CPP scan for now until GPU runner available for the repo
|
||||
# - language: c-cpp
|
||||
# build-mode: autobuild
|
||||
- language: python
|
||||
build-mode: none
|
||||
# CodeQL supports the following values keywords for 'language': 'actions', 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'rust', 'swift'
|
||||
# Use `c-cpp` to analyze code written in C, C++ or both
|
||||
# Use 'java-kotlin' to analyze code written in Java, Kotlin or both
|
||||
# Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both
|
||||
# To learn more about changing the languages that are analyzed or customizing the build mode for your analysis,
|
||||
# see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning.
|
||||
# If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how
|
||||
# your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages
|
||||
steps:
|
||||
- name: "Harden Runner"
|
||||
uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0
|
||||
with:
|
||||
disable-sudo-and-containers: true
|
||||
egress-policy: audit
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
||||
with:
|
||||
# for setuptools-scm
|
||||
fetch-depth: 0
|
||||
|
||||
# Add any setup steps before running the `github/codeql-action/init` action.
|
||||
# This includes steps like installing compilers or runtimes (`actions/setup-node`
|
||||
# or others). This is typically only required for manual builds.
|
||||
# - name: Setup runtime (example)
|
||||
# uses: actions/setup-example@v1
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@f443b600d91635bebf5b0d9ebc620189c0d6fba5 # v4.30.8
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
build-mode: ${{ matrix.build-mode }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
# By default, queries listed here will override any specified in a config file.
|
||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||
|
||||
# For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
|
||||
# queries: security-extended,security-and-quality
|
||||
|
||||
# If the analyze step fails for one of the languages you are analyzing with
|
||||
# "We were unable to automatically build your code", modify the matrix above
|
||||
# to set the build mode to "manual" for that language. Then modify this step
|
||||
# to build your code.
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
||||
- if: matrix.build-mode == 'manual'
|
||||
shell: bash
|
||||
run: |
|
||||
echo 'If you are using a "manual" build mode for one or more of the' \
|
||||
'languages you are analyzing, replace this with the commands to build' \
|
||||
'your code, for example:'
|
||||
echo ' make bootstrap'
|
||||
echo ' make release'
|
||||
exit 1
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@f443b600d91635bebf5b0d9ebc620189c0d6fba5 # v4.30.8
|
||||
with:
|
||||
category: "/language:${{matrix.language}}"
|
||||
@@ -0,0 +1,174 @@
|
||||
name: CPU Device Tests
|
||||
|
||||
# CPU device tests: server bench + vLLM e2e. Both job types share a
|
||||
# single environment (built once per OS) to avoid re-installing vLLM.
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
workflow_dispatch:
|
||||
pull_request:
|
||||
branches:
|
||||
- "dev"
|
||||
- "release-**"
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
changes:
|
||||
name: Detect changes
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
pull-requests: read
|
||||
outputs:
|
||||
lmcache: >-
|
||||
${{
|
||||
github.event_name == 'workflow_dispatch' ||
|
||||
github.event_name == 'workflow_call' ||
|
||||
steps.filter.outputs.lmcache == 'true'
|
||||
}}
|
||||
steps:
|
||||
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
||||
if: github.event_name == 'push'
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
- uses: dorny/paths-filter@v3
|
||||
if: >-
|
||||
github.event_name == 'push' ||
|
||||
github.event_name == 'pull_request'
|
||||
id: filter
|
||||
with:
|
||||
filters: |
|
||||
lmcache:
|
||||
- 'lmcache/**'
|
||||
- 'pyproject.toml'
|
||||
- 'setup.py'
|
||||
- 'requirements/**.txt'
|
||||
- '.github/workflows/cpu_device.yml'
|
||||
- '.github/scripts/cpu_device_test.sh'
|
||||
- '.github/scripts/cpu_server_bench_test.sh'
|
||||
- '.github/scripts/cpu_vllm_e2e_test.sh'
|
||||
- '.github/scripts/install_vllm_cpu.sh'
|
||||
- '.github/scripts/install_lmcache_cpu.sh'
|
||||
- '.github/scripts/download_model.sh'
|
||||
- '.github/scripts/run-cpu-e2e-validation.sh'
|
||||
- '!operator/**'
|
||||
|
||||
cpu-device-test:
|
||||
needs: changes
|
||||
if: needs.changes.outputs.lmcache == 'true'
|
||||
name: CPU device (${{ matrix.os }})
|
||||
runs-on: ${{ matrix.os }}
|
||||
timeout-minutes: 120
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-22.04, macos-latest]
|
||||
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
||||
with:
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Setup Python 3.12
|
||||
uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0
|
||||
with:
|
||||
python-version: "3.12"
|
||||
cache: pip
|
||||
cache-dependency-path: |
|
||||
pyproject.toml
|
||||
requirements/*.txt
|
||||
|
||||
- name: Install FFmpeg (macOS)
|
||||
if: runner.os == 'macOS'
|
||||
run: |
|
||||
if ! command -v ffmpeg >/dev/null 2>&1; then
|
||||
brew install ffmpeg
|
||||
else
|
||||
echo "ffmpeg already installed: $(ffmpeg -version | head -n1)"
|
||||
fi
|
||||
|
||||
- name: Cache opt-125m model (GitHub release)
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.cache/huggingface
|
||||
key: opt-125m-gh-v2
|
||||
|
||||
- name: Install vLLM CPU (prebuilt nightly from PyPI)
|
||||
run: bash .github/scripts/install_vllm_cpu.sh
|
||||
|
||||
- name: Install lmcache (CPU-only, no vLLM)
|
||||
run: bash .github/scripts/install_lmcache_cpu.sh
|
||||
|
||||
- name: Download facebook/opt-125m (GitHub release)
|
||||
run: bash .github/scripts/download_opt125m_github.sh
|
||||
|
||||
- name: Server bench — LMCache-driven
|
||||
run: |
|
||||
LMCACHE_BENCH_TRANSFER_MODE=lmcache_driven \
|
||||
LMCACHE_HTTP_PORT_BENCH=18080 \
|
||||
LMCACHE_ZMQ_PORT_BENCH=15555 \
|
||||
bash .github/scripts/cpu_device_test.sh server_bench
|
||||
|
||||
- name: Server bench — Engine-driven
|
||||
run: |
|
||||
LMCACHE_BENCH_TRANSFER_MODE=engine_driven \
|
||||
LMCACHE_HTTP_PORT_BENCH=18081 \
|
||||
LMCACHE_ZMQ_PORT_BENCH=15556 \
|
||||
bash .github/scripts/cpu_device_test.sh server_bench
|
||||
|
||||
- name: vLLM e2e — Engine-driven (pickle)
|
||||
env:
|
||||
HF_TOKEN: ${{ secrets.HF_TOKEN }}
|
||||
run: |
|
||||
LMCACHE_E2E_TRANSPORT_MODE=pickle \
|
||||
LMCACHE_HTTP_PORT_E2E=18082 \
|
||||
LMCACHE_ZMQ_PORT_E2E=15557 \
|
||||
VLLM_PORT_E2E=18000 \
|
||||
bash .github/scripts/cpu_device_test.sh vllm_e2e
|
||||
|
||||
# POSIX SHM transport is Linux-only.
|
||||
- name: vLLM e2e — Engine-driven (shm)
|
||||
if: runner.os == 'Linux'
|
||||
env:
|
||||
HF_TOKEN: ${{ secrets.HF_TOKEN }}
|
||||
run: |
|
||||
LMCACHE_E2E_TRANSPORT_MODE=shm \
|
||||
LMCACHE_HTTP_PORT_E2E=18083 \
|
||||
LMCACHE_ZMQ_PORT_E2E=15558 \
|
||||
VLLM_PORT_E2E=18001 \
|
||||
bash .github/scripts/cpu_device_test.sh vllm_e2e
|
||||
|
||||
- name: vLLM e2e — Engine-driven
|
||||
env:
|
||||
HF_TOKEN: ${{ secrets.HF_TOKEN }}
|
||||
run: |
|
||||
LMCACHE_E2E_TRANSPORT_MODE=engine_driven \
|
||||
LMCACHE_HTTP_PORT_E2E=18084 \
|
||||
LMCACHE_ZMQ_PORT_E2E=15559 \
|
||||
VLLM_PORT_E2E=18002 \
|
||||
bash .github/scripts/cpu_device_test.sh vllm_e2e
|
||||
|
||||
- name: Upload logs on failure
|
||||
if: failure()
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: cpu-device-logs-${{ matrix.os }}
|
||||
path: |
|
||||
/tmp/cpu_device_*.log
|
||||
if-no-files-found: ignore
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"problemMatcher": [
|
||||
{
|
||||
"owner": "actionlint",
|
||||
"pattern": [
|
||||
{
|
||||
"regexp": "^(?:\\x1b\\[\\d+m)?(.+?)(?:\\x1b\\[\\d+m)*:(?:\\x1b\\[\\d+m)*(\\d+)(?:\\x1b\\[\\d+m)*:(?:\\x1b\\[\\d+m)*(\\d+)(?:\\x1b\\[\\d+m)*: (?:\\x1b\\[\\d+m)*(.+?)(?:\\x1b\\[\\d+m)* \\[(.+?)\\]$",
|
||||
"file": 1,
|
||||
"line": 2,
|
||||
"column": 3,
|
||||
"message": 4,
|
||||
"code": 5
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"problemMatcher": [
|
||||
{
|
||||
"owner": "mypy",
|
||||
"pattern": [
|
||||
{
|
||||
"regexp": "^(.+):(\\d+):\\s(error|warning):\\s(.+)$",
|
||||
"file": 1,
|
||||
"line": 2,
|
||||
"severity": 3,
|
||||
"message": 4
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,221 @@
|
||||
name: Build nightly container image of latest code
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '30 7 * * *'
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
nightly-wheels:
|
||||
name: Build and publish nightly wheels
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0
|
||||
with:
|
||||
disable-sudo-and-containers: false
|
||||
egress-policy: audit
|
||||
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Remove non-release tags
|
||||
run: git tag -l | grep -vE '^v[0-9]+\.[0-9]+\.[0-9]+$' | xargs -r git tag -d
|
||||
|
||||
- name: Free disk space
|
||||
uses: ./.github/actions/free-disk-space
|
||||
|
||||
- name: Setup Python 3.13
|
||||
uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0
|
||||
with:
|
||||
python-version: "3.13"
|
||||
|
||||
- name: Login to DockerHub
|
||||
if: vars.DOCKERHUB_USERNAME != ''
|
||||
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
|
||||
with:
|
||||
username: ${{ vars.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Install build tooling
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install cibuildwheel
|
||||
|
||||
|
||||
- name: Build cu13.0 nightly wheel
|
||||
env:
|
||||
CIBW_TEST_COMMAND: "python -c 'import lmcache.c_ops'"
|
||||
run: |
|
||||
python -m cibuildwheel --output-dir dist/cu130
|
||||
|
||||
- name: Publish cu13.0 wheels to rolling nightly release
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
gh release delete nightly --yes --cleanup-tag --repo ${{ github.repository }} 2>/dev/null || true
|
||||
gh release create nightly \
|
||||
--repo ${{ github.repository }} \
|
||||
--title "Nightly $(date +'%Y-%m-%d') · CUDA 13.0" \
|
||||
--notes "Nightly CUDA 13.0 wheels built from \`dev\` on $(date +'%Y-%m-%d').
|
||||
|
||||
\`\`\`
|
||||
uv pip install lmcache --pre \\
|
||||
--extra-index-url https://download.pytorch.org/whl/cu130 \\
|
||||
--find-links https://github.com/${{ github.repository }}/releases/expanded_assets/nightly \\
|
||||
--index-strategy unsafe-best-match
|
||||
\`\`\`" \
|
||||
--prerelease \
|
||||
dist/cu130/*.whl
|
||||
|
||||
- name: Build cu12.9 nightly wheel
|
||||
env:
|
||||
CIBW_MANYLINUX_X86_64_IMAGE: docker.io/pytorch/manylinux2_28-builder:cuda12.9
|
||||
CIBW_ENVIRONMENT: 'TORCH_CUDA_ARCH_LIST="7.0;7.5;8.0;8.6;8.9;9.0;10.0" ENABLE_CXX11_ABI=1 LMCACHE_CUDA_MAJOR=12 PIP_EXTRA_INDEX_URL=https://download.pytorch.org/whl/cu129'
|
||||
CIBW_REPAIR_WHEEL_COMMAND_LINUX: >-
|
||||
auditwheel repair
|
||||
--plat manylinux_2_28_x86_64
|
||||
--exclude libtorch.so
|
||||
--exclude libtorch_cuda.so
|
||||
--exclude libtorch_python.so
|
||||
--exclude libtorch_cpu.so
|
||||
--exclude libc10.so
|
||||
--exclude libc10_cuda.so
|
||||
--exclude libcudart.so.12
|
||||
-w {dest_dir} {wheel}
|
||||
CIBW_TEST_COMMAND: "python -c 'import lmcache.c_ops'"
|
||||
run: |
|
||||
python -m cibuildwheel --output-dir dist/cu129
|
||||
|
||||
- name: Publish cu12.9 wheels to rolling nightly-cu129 release
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
gh release delete nightly-cu129 --yes --cleanup-tag --repo ${{ github.repository }} 2>/dev/null || true
|
||||
gh release create nightly-cu129 \
|
||||
--repo ${{ github.repository }} \
|
||||
--title "Nightly $(date +'%Y-%m-%d') · CUDA 12.9" \
|
||||
--notes "Nightly CUDA 12.9 wheels built from \`dev\` on $(date +'%Y-%m-%d').
|
||||
|
||||
\`\`\`
|
||||
uv pip install lmcache --pre \\
|
||||
--extra-index-url https://download.pytorch.org/whl/cu129 \\
|
||||
--find-links https://github.com/${{ github.repository }}/releases/expanded_assets/nightly-cu129 \\
|
||||
--index-strategy unsafe-best-match
|
||||
\`\`\`" \
|
||||
--prerelease \
|
||||
dist/cu129/*.whl
|
||||
|
||||
nightly-build:
|
||||
name: Build image
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0
|
||||
with:
|
||||
disable-sudo-and-containers: false
|
||||
egress-policy: audit
|
||||
|
||||
- name: Login to DockerHub
|
||||
if: vars.DOCKERHUB_USERNAME != ''
|
||||
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
|
||||
with:
|
||||
username: ${{ vars.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
|
||||
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
||||
with:
|
||||
# for setuptools-scm
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Remove non-release tags
|
||||
run: git tag -l | grep -vE '^v[0-9]+\.[0-9]+\.[0-9]+$' | xargs -r git tag -d
|
||||
|
||||
- name: Free disk space
|
||||
uses: ./.github/actions/free-disk-space
|
||||
|
||||
- name: Setup Python 3.13
|
||||
uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0
|
||||
with:
|
||||
python-version: "3.13"
|
||||
|
||||
- name: Get the current date
|
||||
run: |
|
||||
echo "NOW=$(date +'%Y-%m-%d')" >> "$GITHUB_ENV"
|
||||
|
||||
- name: Build lmcache/vllm-openai container image (cu13 nightly)
|
||||
run: |
|
||||
docker system prune -f --all
|
||||
docker builder prune -af
|
||||
docker build \
|
||||
--build-arg BASE_IMAGE=nvcr.io/nvidia/cuda-dl-base:25.09-cuda13.0-devel-ubuntu24.04 \
|
||||
--build-arg CUDA_VERSION=13.0 \
|
||||
--build-arg torch_cuda_arch_list='7.5 8.0 8.6 8.9 9.0 10.0 12.0+PTX' \
|
||||
--target image-build \
|
||||
--tag lmcache/vllm-openai:latest-nightly --tag lmcache/vllm-openai:nightly-${{ env.NOW }} \
|
||||
--file docker/Dockerfile .
|
||||
|
||||
- name: Push lmcache/vllm-openai container image to DockerHub
|
||||
run: |
|
||||
docker push lmcache/vllm-openai:latest-nightly
|
||||
docker push lmcache/vllm-openai:nightly-${{ env.NOW }}
|
||||
|
||||
- name: Build lmcache/standalone container image (cu13 nightly)
|
||||
run: |
|
||||
docker system prune -f --all
|
||||
docker builder prune -af
|
||||
docker build \
|
||||
--build-arg BASE_IMAGE=nvcr.io/nvidia/cuda-dl-base:25.09-cuda13.0-devel-ubuntu24.04 \
|
||||
--build-arg CUDA_VERSION=13.0 \
|
||||
--build-arg torch_cuda_arch_list='7.5 8.0 8.6 8.9 9.0 10.0 12.0+PTX' \
|
||||
--target lmcache-final \
|
||||
--tag lmcache/standalone:nightly --tag lmcache/standalone:nightly-${{ env.NOW }} \
|
||||
--file docker/Dockerfile.standalone .
|
||||
|
||||
- name: Push lmcache/standalone container image to DockerHub
|
||||
run: |
|
||||
docker push lmcache/standalone:nightly
|
||||
docker push lmcache/standalone:nightly-${{ env.NOW }}
|
||||
|
||||
- name: Build lmcache/vllm-openai container image (cu12.9 nightly)
|
||||
run: |
|
||||
docker system prune -f --all
|
||||
docker builder prune -af
|
||||
docker build \
|
||||
--build-arg BASE_IMAGE=nvcr.io/nvidia/cuda-dl-base:25.05-cuda12.9-devel-ubuntu24.04 \
|
||||
--build-arg CUDA_VERSION=12.9 --build-arg UBUNTU_VERSION=24.04 \
|
||||
--target image-build \
|
||||
--tag lmcache/vllm-openai:latest-nightly-cu129 --tag lmcache/vllm-openai:nightly-${{ env.NOW }}-cu129 \
|
||||
--file docker/Dockerfile .
|
||||
|
||||
- name: Push lmcache/vllm-openai cu12.9 nightly image to DockerHub
|
||||
run: |
|
||||
docker push lmcache/vllm-openai:latest-nightly-cu129
|
||||
docker push lmcache/vllm-openai:nightly-${{ env.NOW }}-cu129
|
||||
|
||||
- name: Build lmcache/standalone container image (cu12.9 nightly)
|
||||
run: |
|
||||
docker system prune -f --all
|
||||
docker builder prune -af
|
||||
docker build \
|
||||
--build-arg BASE_IMAGE=nvcr.io/nvidia/cuda-dl-base:25.05-cuda12.9-devel-ubuntu24.04 \
|
||||
--build-arg CUDA_VERSION=12.9 --build-arg UBUNTU_VERSION=24.04 \
|
||||
--target lmcache-final \
|
||||
--tag lmcache/standalone:nightly-cu129 --tag lmcache/standalone:nightly-${{ env.NOW }}-cu129 \
|
||||
--file docker/Dockerfile.standalone .
|
||||
|
||||
- name: Push lmcache/standalone cu12.9 nightly image to DockerHub
|
||||
run: |
|
||||
docker push lmcache/standalone:nightly-cu129
|
||||
docker push lmcache/standalone:nightly-${{ env.NOW }}-cu129
|
||||
@@ -0,0 +1,76 @@
|
||||
name: "Operator: CI"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- dev
|
||||
- "release-**"
|
||||
pull_request:
|
||||
branches:
|
||||
- dev
|
||||
- "release-**"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
working-directory: operator
|
||||
|
||||
jobs:
|
||||
changes:
|
||||
name: Detect changes
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
pull-requests: read
|
||||
outputs:
|
||||
operator: ${{ steps.filter.outputs.operator == 'true' }}
|
||||
steps:
|
||||
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
||||
if: github.event_name == 'push'
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
- uses: dorny/paths-filter@v3
|
||||
if: github.event_name == 'push' || github.event_name == 'pull_request'
|
||||
id: filter
|
||||
with:
|
||||
filters: |
|
||||
operator:
|
||||
- 'operator/**'
|
||||
- '.github/workflows/operator_ci.yml'
|
||||
|
||||
ci:
|
||||
needs: changes
|
||||
if: needs.changes.outputs.operator == 'true'
|
||||
name: Format, lint, and test
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
||||
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version-file: operator/go.mod
|
||||
|
||||
- name: Check formatting
|
||||
run: |
|
||||
test -z "$(gofmt -l .)" || { gofmt -d .; exit 1; }
|
||||
|
||||
- name: Check linter configuration
|
||||
run: make lint-config
|
||||
|
||||
- name: Lint
|
||||
run: make lint
|
||||
|
||||
- name: Test
|
||||
run: |
|
||||
go mod tidy
|
||||
make test
|
||||
@@ -0,0 +1,80 @@
|
||||
name: "Operator: Nightly"
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 0 * * *"
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
IMAGE_NAME: lmcache/lmcache-operator
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
working-directory: operator
|
||||
|
||||
jobs:
|
||||
nightly:
|
||||
name: Build, push, and release nightly
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
|
||||
with:
|
||||
username: ${{ vars.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Compute nightly tag
|
||||
id: tag
|
||||
run: |
|
||||
DATE=$(date -u +%Y-%m-%d)
|
||||
echo "TAG=nightly-${DATE}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Build and push image
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: operator
|
||||
platforms: linux/amd64
|
||||
push: true
|
||||
tags: |
|
||||
${{ env.IMAGE_NAME }}:${{ steps.tag.outputs.TAG }}
|
||||
${{ env.IMAGE_NAME }}:nightly
|
||||
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version-file: operator/go.mod
|
||||
|
||||
- name: Build installer manifest
|
||||
run: make build-installer IMG=${{ env.IMAGE_NAME }}:${{ steps.tag.outputs.TAG }}
|
||||
|
||||
- name: Update nightly release
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
tag_name: operator-nightly-latest
|
||||
name: "Operator Nightly Latest (${{ steps.tag.outputs.TAG }})"
|
||||
prerelease: true
|
||||
make_latest: false
|
||||
body: |
|
||||
Automated nightly operator build from `dev` branch.
|
||||
|
||||
**Image:** `${{ env.IMAGE_NAME }}:${{ steps.tag.outputs.TAG }}`
|
||||
|
||||
```bash
|
||||
kubectl apply -f https://github.com/${{ github.repository }}/releases/download/operator-nightly-latest/install.yaml
|
||||
```
|
||||
files: operator/dist/install.yaml
|
||||
@@ -0,0 +1,100 @@
|
||||
name: "Operator: Release"
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
env:
|
||||
IMAGE_NAME: lmcache/lmcache-operator
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
working-directory: operator
|
||||
|
||||
jobs:
|
||||
release:
|
||||
name: Build, push, and release
|
||||
# Filter out main lmcache `v*` releases — only fire for operator-prefixed tags.
|
||||
if: startsWith(github.ref_name, 'operator-v')
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
|
||||
with:
|
||||
username: ${{ vars.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Extract version from tag
|
||||
id: version
|
||||
run: |
|
||||
# Strip "operator-" prefix from tag to get version (e.g. operator-v0.4.8rc1 -> v0.4.8rc1).
|
||||
VERSION="${GITHUB_REF_NAME#operator-}"
|
||||
echo "VERSION=${VERSION}" >> "$GITHUB_OUTPUT"
|
||||
# Pre-releases (rc/alpha/beta) get the floating ":latest-rc" tag and must
|
||||
# never move the stable ":latest" image tag or the "operator-latest" alias.
|
||||
# Detect from the version string rather than the GitHub "pre-release" flag
|
||||
# so behavior is robust whether or not that box is ticked in the UI.
|
||||
if [[ "${VERSION}" =~ (rc|alpha|beta) ]]; then
|
||||
echo "FLOATING_TAG=latest-rc" >> "$GITHUB_OUTPUT"
|
||||
echo "IS_PRERELEASE=true" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "FLOATING_TAG=latest" >> "$GITHUB_OUTPUT"
|
||||
echo "IS_PRERELEASE=false" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
- name: Build and push image
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: operator
|
||||
platforms: linux/amd64
|
||||
push: true
|
||||
tags: |
|
||||
${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}
|
||||
${{ env.IMAGE_NAME }}:${{ steps.version.outputs.FLOATING_TAG }}
|
||||
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version-file: operator/go.mod
|
||||
|
||||
- name: Build installer manifest
|
||||
run: make build-installer IMG=${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}
|
||||
|
||||
- name: Attach installer to GitHub Release
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
files: operator/dist/install.yaml
|
||||
|
||||
- name: Update latest release alias
|
||||
# Skip for pre-releases: an rc/alpha/beta must not repoint the stable
|
||||
# "operator-latest" alias (or its install.yaml) at a pre-release build.
|
||||
if: steps.version.outputs.IS_PRERELEASE == 'false'
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
tag_name: operator-latest
|
||||
name: "Operator Latest (${{ steps.version.outputs.VERSION }})"
|
||||
make_latest: false
|
||||
body: |
|
||||
Points to the latest stable operator release: `${{ steps.version.outputs.VERSION }}`
|
||||
|
||||
**Image:** `${{ env.IMAGE_NAME }}:latest`
|
||||
|
||||
```bash
|
||||
kubectl apply -f https://github.com/${{ github.repository }}/releases/download/operator-latest/install.yaml
|
||||
```
|
||||
files: operator/dist/install.yaml
|
||||
@@ -0,0 +1,52 @@
|
||||
name: PR Full Build
|
||||
|
||||
# Build all release artifacts (sdist + CUDA wheel, CLI wheel, cu129 wheel)
|
||||
# on PRs carrying the `full` label. The `full` label is added automatically
|
||||
# by automerge-labeler.yml when auto-merge is enabled on a code-change PR,
|
||||
# so this acts as a pre-merge sanity check that wheels still build.
|
||||
#
|
||||
# No tests, no code-quality checks, no publishing — those are covered by
|
||||
# test.yml / code_quality_checks.yml (per-PR) and publish.yml (on merge).
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- dev
|
||||
- "release-**"
|
||||
types: [opened, synchronize, reopened, labeled]
|
||||
|
||||
# Cancel older in-flight runs on the same PR. github.ref is
|
||||
# refs/pull/<N>/merge on pull_request events, so each PR gets its own group.
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
# Each build runs independently — a failure in one does not skip the
|
||||
# others, matching publish.yml's isolation model.
|
||||
|
||||
build-main:
|
||||
name: Build main
|
||||
if: contains(github.event.pull_request.labels.*.name, 'full')
|
||||
uses: ./.github/workflows/build_main_artifacts.yml
|
||||
|
||||
build-cli:
|
||||
name: Build CLI
|
||||
if: contains(github.event.pull_request.labels.*.name, 'full')
|
||||
uses: ./.github/workflows/build_cli_artifacts.yml
|
||||
|
||||
build-cpu:
|
||||
name: Build CPU
|
||||
if: contains(github.event.pull_request.labels.*.name, 'full')
|
||||
uses: ./.github/workflows/build_cpu_artifacts.yml
|
||||
|
||||
build-cu129:
|
||||
name: Build cu129
|
||||
if: contains(github.event.pull_request.labels.*.name, 'full')
|
||||
uses: ./.github/workflows/build_cu129_artifacts.yml
|
||||
# Fork PRs won't expose DOCKERHUB_TOKEN even with `inherit`; the login
|
||||
# step in build_cu129_artifacts.yml guards on the token being non-empty.
|
||||
secrets: inherit
|
||||
@@ -0,0 +1,531 @@
|
||||
name: Build and Publish to PyPI
|
||||
|
||||
on:
|
||||
# Trigger the workflow on push to the dev and any release branches,
|
||||
# and on release tag pushes / GitHub release publication.
|
||||
# Per-PR verification lives in test.yml, code_quality_checks.yml, and
|
||||
# pr_full_build.yml — this workflow is the release pipeline.
|
||||
push:
|
||||
branches:
|
||||
- dev
|
||||
- "release-**"
|
||||
tags:
|
||||
- "v*"
|
||||
release:
|
||||
types:
|
||||
- published
|
||||
|
||||
env:
|
||||
LC_ALL: en_US.UTF-8
|
||||
|
||||
# Cancel superseded runs on the same ref, but never abort a tag/release publish.
|
||||
concurrency:
|
||||
group: publish-${{ github.ref }}
|
||||
cancel-in-progress: ${{ !startsWith(github.ref, 'refs/tags/') && github.event_name != 'release' }}
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: read
|
||||
|
||||
jobs:
|
||||
changes:
|
||||
name: Detect changes
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
pull-requests: read
|
||||
outputs:
|
||||
# Skip the whole pipeline for operator releases (tags like `operator-v*`).
|
||||
# operator_release.yml handles those; this workflow is lmcache-only.
|
||||
lmcache: ${{ !startsWith(github.ref_name, 'operator-') && (github.event_name == 'release' || startsWith(github.ref, 'refs/tags/') || steps.filter.outputs.lmcache == 'true') }}
|
||||
steps:
|
||||
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
||||
if: github.event_name == 'push' && !startsWith(github.ref, 'refs/tags/')
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
- uses: dorny/paths-filter@v3
|
||||
if: github.event_name == 'push' && !startsWith(github.ref, 'refs/tags/')
|
||||
id: filter
|
||||
with:
|
||||
filters: |
|
||||
lmcache:
|
||||
- '**.py'
|
||||
- 'pyproject.toml'
|
||||
- 'pyproject_cli.toml'
|
||||
- 'requirements/**.txt'
|
||||
- 'docker/**'
|
||||
- '.github/workflows/test.yml'
|
||||
- '.github/workflows/code_quality_checks.yml'
|
||||
- '.github/workflows/publish.yml'
|
||||
- '.github/workflows/build_main_artifacts.yml'
|
||||
- '.github/workflows/build_cli_artifacts.yml'
|
||||
- '.github/workflows/build_cu129_artifacts.yml'
|
||||
- '!operator/**'
|
||||
|
||||
# Build each artifact group in its own reusable workflow so that a
|
||||
# failure in one (e.g. cu129) does not block publishing of the others.
|
||||
|
||||
build-main:
|
||||
needs: changes
|
||||
if: needs.changes.outputs.lmcache == 'true'
|
||||
name: Build main
|
||||
uses: ./.github/workflows/build_main_artifacts.yml
|
||||
|
||||
build-cli:
|
||||
needs: changes
|
||||
if: needs.changes.outputs.lmcache == 'true'
|
||||
name: Build CLI
|
||||
uses: ./.github/workflows/build_cli_artifacts.yml
|
||||
|
||||
build-cu129:
|
||||
needs: changes
|
||||
if: needs.changes.outputs.lmcache == 'true'
|
||||
name: Build cu129
|
||||
uses: ./.github/workflows/build_cu129_artifacts.yml
|
||||
# DockerHub creds needed for the cu12.9 manylinux image pull;
|
||||
# reusable workflows do not auto-inherit secrets.
|
||||
secrets: inherit
|
||||
|
||||
# Run tests and code quality checks before publishing
|
||||
test:
|
||||
needs: changes
|
||||
if: needs.changes.outputs.lmcache == 'true'
|
||||
name: Run tests
|
||||
uses: ./.github/workflows/test.yml
|
||||
|
||||
code-quality:
|
||||
needs: changes
|
||||
if: needs.changes.outputs.lmcache == 'true'
|
||||
name: Run code quality checks
|
||||
uses: ./.github/workflows/code_quality_checks.yml
|
||||
|
||||
# Push to Test PyPI when:
|
||||
# - a new GitHub release is published
|
||||
# - a commit lands on dev (PR merged)
|
||||
publish-test-pypi:
|
||||
name: Publish packages to test.pypi.org
|
||||
# Require upstream jobs to have succeeded so a cancelled/skipped build
|
||||
# doesn't trigger a publish that fails on the missing artifact.
|
||||
if: |
|
||||
needs.build-main.result == 'success' &&
|
||||
needs.test.result == 'success' &&
|
||||
needs.code-quality.result == 'success' &&
|
||||
needs.changes.outputs.lmcache == 'true' &&
|
||||
github.repository_owner == 'LMCache' &&
|
||||
github.event_name == 'push' && github.ref == 'refs/heads/dev'
|
||||
permissions:
|
||||
contents: read
|
||||
# see https://docs.pypi.org/trusted-publishers/
|
||||
id-token: write
|
||||
runs-on: ubuntu-latest
|
||||
needs: [changes, build-main, test, code-quality]
|
||||
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0
|
||||
with:
|
||||
disable-sudo-and-containers: false
|
||||
egress-policy: audit
|
||||
|
||||
- name: Fetch release artifacts
|
||||
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
|
||||
with:
|
||||
name: release-artifacts
|
||||
path: dist
|
||||
|
||||
- name: Upload to Test PyPI
|
||||
uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # v1.13.0
|
||||
with:
|
||||
repository-url: https://test.pypi.org/legacy/
|
||||
verbose: true
|
||||
|
||||
publish-cli-test-pypi:
|
||||
name: Publish lmcache-cli packages to test.pypi.org
|
||||
if: |
|
||||
needs.build-cli.result == 'success' &&
|
||||
needs.test.result == 'success' &&
|
||||
needs.code-quality.result == 'success' &&
|
||||
needs.changes.outputs.lmcache == 'true' &&
|
||||
github.repository_owner == 'LMCache' &&
|
||||
github.event_name == 'push' && github.ref == 'refs/heads/dev'
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
runs-on: ubuntu-latest
|
||||
needs: [changes, build-cli, test, code-quality]
|
||||
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0
|
||||
with:
|
||||
disable-sudo-and-containers: false
|
||||
egress-policy: audit
|
||||
|
||||
- name: Fetch CLI release artifacts
|
||||
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
|
||||
with:
|
||||
name: release-cli-artifacts
|
||||
path: dist
|
||||
|
||||
- name: Upload lmcache-cli to Test PyPI
|
||||
uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # v1.13.0
|
||||
with:
|
||||
repository-url: https://test.pypi.org/legacy/
|
||||
verbose: true
|
||||
|
||||
# Push to PyPI (production) when:
|
||||
# - a new GitHub release is created
|
||||
publish-pypi:
|
||||
name: Publish release to pypi.org
|
||||
if: |
|
||||
needs.build-main.result == 'success' &&
|
||||
needs.test.result == 'success' &&
|
||||
needs.code-quality.result == 'success' &&
|
||||
needs.changes.outputs.lmcache == 'true' &&
|
||||
github.repository_owner == 'LMCache' && github.event.action == 'published'
|
||||
permissions:
|
||||
# see https://docs.pypi.org/trusted-publishers/
|
||||
id-token: write
|
||||
# allow gh release upload
|
||||
contents: write
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
needs: [changes, build-main, test, code-quality]
|
||||
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0
|
||||
with:
|
||||
disable-sudo-and-containers: false
|
||||
egress-policy: audit
|
||||
|
||||
- name: Fetch release artifacts
|
||||
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
|
||||
with:
|
||||
name: release-artifacts
|
||||
path: dist
|
||||
|
||||
- name: Upload release artifacts to GitHub release
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
run: >-
|
||||
gh release upload '${{ github.ref_name }}' dist/* --repo '${{ github.repository }}'
|
||||
|
||||
- name: Upload to PyPI
|
||||
uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # v1.13.0
|
||||
with:
|
||||
verbose: true
|
||||
|
||||
publish-cli-pypi:
|
||||
name: Publish lmcache-cli release to pypi.org
|
||||
if: |
|
||||
needs.build-cli.result == 'success' &&
|
||||
needs.test.result == 'success' &&
|
||||
needs.code-quality.result == 'success' &&
|
||||
needs.changes.outputs.lmcache == 'true' &&
|
||||
github.repository_owner == 'LMCache' && github.event.action == 'published'
|
||||
permissions:
|
||||
id-token: write
|
||||
contents: write
|
||||
runs-on: ubuntu-latest
|
||||
needs: [changes, build-cli, test, code-quality]
|
||||
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0
|
||||
with:
|
||||
disable-sudo-and-containers: false
|
||||
egress-policy: audit
|
||||
|
||||
- name: Fetch CLI release artifacts
|
||||
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
|
||||
with:
|
||||
name: release-cli-artifacts
|
||||
path: dist
|
||||
|
||||
- name: Upload lmcache-cli release artifacts to GitHub release
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
run: >-
|
||||
gh release upload '${{ github.ref_name }}' dist/* --repo '${{ github.repository }}'
|
||||
|
||||
- name: Upload lmcache-cli to PyPI
|
||||
uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # v1.13.0
|
||||
with:
|
||||
verbose: true
|
||||
|
||||
# Publish cu12.9 wheel to GitHub Release (not PyPI) when a release is published
|
||||
publish-cu129-github-release:
|
||||
name: Publish cu129 wheel to GitHub Release
|
||||
if: |
|
||||
needs.build-cu129.result == 'success' &&
|
||||
needs.test.result == 'success' &&
|
||||
needs.code-quality.result == 'success' &&
|
||||
needs.changes.outputs.lmcache == 'true' &&
|
||||
github.repository_owner == 'LMCache' && github.event.action == 'published'
|
||||
permissions:
|
||||
contents: write
|
||||
runs-on: ubuntu-latest
|
||||
needs: [changes, build-cu129, test, code-quality]
|
||||
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0
|
||||
with:
|
||||
disable-sudo-and-containers: false
|
||||
egress-policy: audit
|
||||
|
||||
- name: Fetch cu12.9 release artifacts
|
||||
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
|
||||
with:
|
||||
name: release-cu129-artifacts
|
||||
path: dist
|
||||
|
||||
- name: Publish cu12.9 wheel to dedicated GitHub Release
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
gh release create "${{ github.ref_name }}-cu129" \
|
||||
--repo ${{ github.repository }} \
|
||||
--latest=false \
|
||||
--title "Release ${{ github.ref_name }} · CUDA 12.9" \
|
||||
--notes "CUDA 12.9 wheel for LMCache ${{ github.ref_name }}.
|
||||
|
||||
\`\`\`
|
||||
VERSION=${{ github.ref_name }}
|
||||
uv pip install lmcache==${VERSION#v} \\
|
||||
--extra-index-url https://download.pytorch.org/whl/cu129 \\
|
||||
--find-links https://github.com/${{ github.repository }}/releases/expanded_assets/${VERSION}-cu129 \\
|
||||
--index-strategy unsafe-best-match
|
||||
\`\`\`" \
|
||||
dist/*.whl
|
||||
|
||||
# Build container image and push to DockerHub when:
|
||||
# - a new stable GitHub release is created (non-RC)
|
||||
publish-image:
|
||||
name: Publish image to DockerHub
|
||||
if: |
|
||||
needs.publish-pypi.result == 'success' &&
|
||||
!cancelled() &&
|
||||
github.repository_owner == 'LMCache' && github.event.action == 'published' &&
|
||||
!contains(github.ref_name, 'rc')
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
needs: [publish-pypi, publish-cu129-github-release]
|
||||
|
||||
steps:
|
||||
- name: "Harden Runner"
|
||||
uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0
|
||||
with:
|
||||
disable-sudo-and-containers: false
|
||||
egress-policy: audit
|
||||
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
|
||||
with:
|
||||
username: ${{ vars.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
|
||||
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
||||
with:
|
||||
# for setuptools-scm
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Free disk space
|
||||
uses: ./.github/actions/free-disk-space
|
||||
|
||||
- name: Resolve the release tag that triggered this run
|
||||
run: |
|
||||
echo "LATEST_TAG=${{ github.ref_name }}" >> "$GITHUB_ENV"
|
||||
|
||||
- name: Build lmcache/vllm-openai container image (cu13)
|
||||
run: |
|
||||
docker build \
|
||||
--build-arg BASE_IMAGE=nvcr.io/nvidia/cuda-dl-base:25.09-cuda13.0-devel-ubuntu24.04 \
|
||||
--build-arg CUDA_VERSION=13.0 \
|
||||
--build-arg LMCACHE_VERSION=${{ env.LATEST_TAG }} \
|
||||
--build-arg torch_cuda_arch_list='7.5 8.0 8.6 8.9 9.0 10.0 12.0+PTX' \
|
||||
--target image-release \
|
||||
--tag lmcache/vllm-openai:latest --tag lmcache/vllm-openai:${{ env.LATEST_TAG }} \
|
||||
--file docker/Dockerfile .
|
||||
|
||||
# `lmcache --help` exercises eager CLI subcommand discovery,
|
||||
# so a missing runtime dep fails the build before the image ships.
|
||||
- name: Smoke test lmcache/vllm-openai (cu13)
|
||||
run: |
|
||||
docker run --rm --entrypoint lmcache lmcache/vllm-openai:${{ env.LATEST_TAG }} --help
|
||||
|
||||
- name: Push lmcache/vllm-openai container image to DockerHub
|
||||
run: |
|
||||
docker push lmcache/vllm-openai:latest
|
||||
docker push lmcache/vllm-openai:${{ env.LATEST_TAG }}
|
||||
|
||||
- name: Clean up Docker layers and cache
|
||||
run: |
|
||||
docker system prune -f --all
|
||||
docker builder prune -af
|
||||
|
||||
- name: Build lmcache/vllm-openai:lightweight
|
||||
run: |
|
||||
docker build \
|
||||
--tag lmcache/vllm-openai:lightweight --tag lmcache/vllm-openai:${{ env.LATEST_TAG }}-lightweight \
|
||||
--file docker/Dockerfile.lightweight .
|
||||
|
||||
- name: Smoke test lmcache/vllm-openai:lightweight
|
||||
run: |
|
||||
docker run --rm --entrypoint lmcache lmcache/vllm-openai:${{ env.LATEST_TAG }}-lightweight --help
|
||||
|
||||
- name: Push lmcache/vllm-openai:lightweight image to DockerHub
|
||||
run: |
|
||||
docker push lmcache/vllm-openai:lightweight
|
||||
docker push lmcache/vllm-openai:${{ env.LATEST_TAG }}-lightweight
|
||||
|
||||
- name: Clean up Docker layers and cache
|
||||
run: |
|
||||
docker system prune -f --all
|
||||
docker builder prune -af
|
||||
|
||||
- name: Build lmcache/standalone container image (cu13)
|
||||
run: |
|
||||
docker build \
|
||||
--build-arg BASE_IMAGE=nvcr.io/nvidia/cuda-dl-base:25.09-cuda13.0-devel-ubuntu24.04 \
|
||||
--build-arg CUDA_VERSION=13.0 \
|
||||
--build-arg torch_cuda_arch_list='7.5 8.0 8.6 8.9 9.0 10.0 12.0+PTX' \
|
||||
--target lmcache-final \
|
||||
--tag lmcache/standalone:latest --tag lmcache/standalone:${{ env.LATEST_TAG }} \
|
||||
--tag lmcache/standalone:latest-cu130 --tag lmcache/standalone:${{ env.LATEST_TAG }}-cu130 \
|
||||
--file docker/Dockerfile.standalone .
|
||||
|
||||
- name: Smoke test lmcache/standalone (cu13)
|
||||
run: |
|
||||
docker run --rm --entrypoint lmcache lmcache/standalone:${{ env.LATEST_TAG }} --help
|
||||
|
||||
- name: Push lmcache/standalone container image to DockerHub
|
||||
run: |
|
||||
docker push lmcache/standalone:latest
|
||||
docker push lmcache/standalone:${{ env.LATEST_TAG }}
|
||||
docker push lmcache/standalone:latest-cu130
|
||||
docker push lmcache/standalone:${{ env.LATEST_TAG }}-cu130
|
||||
|
||||
- name: Clean up Docker layers and cache
|
||||
run: |
|
||||
docker system prune -f --all
|
||||
docker builder prune -af
|
||||
|
||||
- name: Build lmcache/vllm-openai container image (cu12.9)
|
||||
if: needs.publish-cu129-github-release.result == 'success'
|
||||
run: |
|
||||
docker build \
|
||||
--build-arg BASE_IMAGE=nvcr.io/nvidia/cuda-dl-base:25.05-cuda12.9-devel-ubuntu24.04 \
|
||||
--build-arg CUDA_VERSION=12.9 \
|
||||
--build-arg LMCACHE_VERSION=${{ env.LATEST_TAG }} \
|
||||
--target image-release-cu129 \
|
||||
--tag lmcache/vllm-openai:latest-cu129 --tag lmcache/vllm-openai:${{ env.LATEST_TAG }}-cu129 \
|
||||
--file docker/Dockerfile .
|
||||
|
||||
- name: Smoke test lmcache/vllm-openai (cu12.9)
|
||||
if: needs.publish-cu129-github-release.result == 'success'
|
||||
run: |
|
||||
docker run --rm --entrypoint lmcache lmcache/vllm-openai:${{ env.LATEST_TAG }}-cu129 --help
|
||||
|
||||
- name: Push lmcache/vllm-openai cu129 container image to DockerHub
|
||||
if: needs.publish-cu129-github-release.result == 'success'
|
||||
run: |
|
||||
docker push lmcache/vllm-openai:latest-cu129
|
||||
docker push lmcache/vllm-openai:${{ env.LATEST_TAG }}-cu129
|
||||
|
||||
- name: Clean up Docker layers and cache
|
||||
run: |
|
||||
docker system prune -f --all
|
||||
docker builder prune -af
|
||||
|
||||
- name: Build lmcache/standalone container image (cu12.9)
|
||||
if: needs.publish-cu129-github-release.result == 'success'
|
||||
run: |
|
||||
docker build \
|
||||
--build-arg BASE_IMAGE=nvcr.io/nvidia/cuda-dl-base:25.05-cuda12.9-devel-ubuntu24.04 \
|
||||
--build-arg CUDA_VERSION=12.9 \
|
||||
--target lmcache-final \
|
||||
--tag lmcache/standalone:latest-cu129 --tag lmcache/standalone:${{ env.LATEST_TAG }}-cu129 \
|
||||
--file docker/Dockerfile.standalone .
|
||||
|
||||
- name: Smoke test lmcache/standalone (cu12.9)
|
||||
if: needs.publish-cu129-github-release.result == 'success'
|
||||
run: |
|
||||
docker run --rm --entrypoint lmcache lmcache/standalone:${{ env.LATEST_TAG }}-cu129 --help
|
||||
|
||||
- name: Push lmcache/standalone cu129 container image to DockerHub
|
||||
if: needs.publish-cu129-github-release.result == 'success'
|
||||
run: |
|
||||
docker push lmcache/standalone:latest-cu129
|
||||
docker push lmcache/standalone:${{ env.LATEST_TAG }}-cu129
|
||||
|
||||
# Build RC container image and push to DockerHub when:
|
||||
# - a new RC GitHub release is created (e.g. v0.4.8rc1)
|
||||
# Only pushes lmcache/vllm-openai:<tag> — does not touch latest or other image variants.
|
||||
publish-image-rc:
|
||||
name: Publish RC image to DockerHub
|
||||
if: |
|
||||
needs.publish-pypi.result == 'success' &&
|
||||
!cancelled() &&
|
||||
github.repository_owner == 'LMCache' && github.event.action == 'published' &&
|
||||
contains(github.ref_name, 'rc')
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
needs: [publish-pypi]
|
||||
|
||||
steps:
|
||||
- name: "Harden Runner"
|
||||
uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0
|
||||
with:
|
||||
disable-sudo-and-containers: false
|
||||
egress-policy: audit
|
||||
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
|
||||
with:
|
||||
username: ${{ vars.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
|
||||
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Free disk space
|
||||
uses: ./.github/actions/free-disk-space
|
||||
|
||||
- name: Get the release tag
|
||||
run: |
|
||||
REF="${{ github.ref_name }}"
|
||||
[[ "$REF" =~ ^v[0-9]+\.[0-9]+\.[0-9]+rc[0-9]+$ ]] && echo "LATEST_RC_TAG=$REF" >> "$GITHUB_ENV"
|
||||
|
||||
- name: Build lmcache/vllm-openai container image (cu13)
|
||||
run: |
|
||||
docker build \
|
||||
--build-arg BASE_IMAGE=nvcr.io/nvidia/cuda-dl-base:25.09-cuda13.0-devel-ubuntu24.04 \
|
||||
--build-arg CUDA_VERSION=13.0 \
|
||||
--build-arg LMCACHE_VERSION=${{ env.LATEST_RC_TAG }} \
|
||||
--build-arg torch_cuda_arch_list='7.5 8.0 8.6 8.9 9.0 10.0 12.0+PTX' \
|
||||
--target image-release \
|
||||
--tag lmcache/vllm-openai:${{ env.LATEST_RC_TAG }} \
|
||||
--file docker/Dockerfile .
|
||||
|
||||
- name: Smoke test lmcache/vllm-openai (cu13)
|
||||
run: |
|
||||
docker run --rm --entrypoint lmcache lmcache/vllm-openai:${{ env.LATEST_RC_TAG }} --help
|
||||
|
||||
- name: Push lmcache/vllm-openai RC image to DockerHub
|
||||
run: |
|
||||
docker push lmcache/vllm-openai:${{ env.LATEST_RC_TAG }}
|
||||
@@ -0,0 +1,84 @@
|
||||
# This workflow uses actions that are not certified by GitHub. They are provided
|
||||
# by a third-party and are governed by separate terms of service, privacy
|
||||
# policy, and support documentation.
|
||||
|
||||
name: Scorecard supply-chain security
|
||||
on:
|
||||
# For Branch-Protection check. Only the default branch is supported. See
|
||||
# https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection
|
||||
branch_protection_rule:
|
||||
# To guarantee Maintained check is occasionally updated. See
|
||||
# https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained
|
||||
schedule:
|
||||
- cron: '23 8 * * 6'
|
||||
push:
|
||||
branches: [ "dev" ]
|
||||
|
||||
# Declare default permissions as read only.
|
||||
permissions: read-all
|
||||
|
||||
jobs:
|
||||
analysis:
|
||||
name: Scorecard analysis
|
||||
runs-on: ubuntu-latest
|
||||
# `publish_results: true` only works when run from the default branch. conditional can be removed if disabled.
|
||||
if: github.event.repository.default_branch == github.ref_name || github.event_name == 'pull_request'
|
||||
permissions:
|
||||
# Needed to upload the results to code-scanning dashboard.
|
||||
security-events: write
|
||||
# Needed to publish results and get a badge (see publish_results below).
|
||||
id-token: write
|
||||
# Uncomment the permissions below if installing in a private repository.
|
||||
# contents: read
|
||||
# actions: read
|
||||
|
||||
steps:
|
||||
- name: "Harden Runner"
|
||||
uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0
|
||||
with:
|
||||
disable-sudo-and-containers: false
|
||||
egress-policy: audit
|
||||
|
||||
- name: "Checkout code"
|
||||
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: "Run analysis"
|
||||
uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3
|
||||
with:
|
||||
results_file: results.sarif
|
||||
results_format: sarif
|
||||
# (Optional) "write" PAT token. Uncomment the `repo_token` line below if:
|
||||
# - you want to enable the Branch-Protection check on a *public* repository, or
|
||||
# - you are installing Scorecard on a *private* repository
|
||||
# To create the PAT, follow the steps in https://github.com/ossf/scorecard-action?tab=readme-ov-file#authentication-with-fine-grained-pat-optional.
|
||||
# repo_token: ${{ secrets.SCORECARD_TOKEN }}
|
||||
|
||||
# Public repositories:
|
||||
# - Publish results to OpenSSF REST API for easy access by consumers
|
||||
# - Allows the repository to include the Scorecard badge.
|
||||
# - See https://github.com/ossf/scorecard-action#publishing-results.
|
||||
# For private repositories:
|
||||
# - `publish_results` will always be set to `false`, regardless
|
||||
# of the value entered here.
|
||||
publish_results: true
|
||||
|
||||
# (Optional) Uncomment file_mode if you have a .gitattributes with files marked export-ignore
|
||||
# file_mode: git
|
||||
|
||||
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
|
||||
# format to the repository Actions tab.
|
||||
- name: "Upload artifact"
|
||||
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
|
||||
with:
|
||||
name: SARIF file
|
||||
path: results.sarif
|
||||
retention-days: 5
|
||||
|
||||
# Upload the results to GitHub's code scanning dashboard (optional).
|
||||
# Commenting out will disable upload of results to your repo's Code Scanning dashboard
|
||||
- name: "Upload to code-scanning"
|
||||
uses: github/codeql-action/upload-sarif@v4
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
@@ -0,0 +1,51 @@
|
||||
name: 'Close stale issues and PRs'
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '30 1 * * *'
|
||||
|
||||
env:
|
||||
LC_ALL: en_US.UTF-8
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
stale:
|
||||
permissions:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: "Harden Runner"
|
||||
uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0
|
||||
with:
|
||||
disable-sudo-and-containers: true
|
||||
egress-policy: audit
|
||||
|
||||
- name: "Stale Action"
|
||||
uses: actions/stale@997185467fa4f803885201cee163a9f38240193d # v10.1.1
|
||||
with:
|
||||
stale-issue-label: 'stale'
|
||||
stale-issue-message: >
|
||||
This issue has been automatically marked as stale because it has not had activity within 60 days.
|
||||
It will be automatically closed if no further activity occurs within 30 days.
|
||||
close-issue-message: >
|
||||
This issue has been automatically closed due to inactivity.
|
||||
Please feel free to reopen if you feel it is still relevant!
|
||||
days-before-issue-stale: 60
|
||||
days-before-issue-close: 30
|
||||
stale-pr-label: 'stale'
|
||||
stale-pr-message: >
|
||||
This pull request has been automatically marked as stale because it has not had activity within 60 days.
|
||||
It will be automatically closed if no further activity occurs within 30 days.
|
||||
close-pr-message: >
|
||||
This pull request has been automatically closed due to inactivity.
|
||||
Please feel free to reopen if you intend to continue working on it!
|
||||
days-before-pr-stale: 60
|
||||
days-before-pr-close: 30
|
||||
operations-per-run: 300
|
||||
@@ -0,0 +1,147 @@
|
||||
name: Sync Torch Version
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: "0 2 * * 1"
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
|
||||
concurrency:
|
||||
group: sync-torch-version
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
sync:
|
||||
name: Sync torch pin with vLLM
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
|
||||
steps:
|
||||
- name: Check out dev branch
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: dev
|
||||
token: ${{ github.token }}
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Sync torch version with vLLM
|
||||
id: sync
|
||||
shell: bash
|
||||
run: |
|
||||
set -Eeuo pipefail
|
||||
|
||||
readonly UPSTREAM_URL="https://raw.githubusercontent.com/vllm-project/vllm/main/pyproject.toml"
|
||||
readonly TARGET_FILE="pyproject.toml"
|
||||
|
||||
tmp_upstream="$(mktemp)"
|
||||
tmp_output="$(mktemp)"
|
||||
|
||||
cleanup() {
|
||||
rm -f "$tmp_upstream" "$tmp_output"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
echo "Fetching upstream pyproject.toml from vLLM..."
|
||||
curl \
|
||||
--fail \
|
||||
--show-error \
|
||||
--silent \
|
||||
--location \
|
||||
--retry 3 \
|
||||
--retry-delay 2 \
|
||||
--connect-timeout 10 \
|
||||
"$UPSTREAM_URL" \
|
||||
-o "$tmp_upstream"
|
||||
|
||||
extract_torch_version() {
|
||||
local file="$1"
|
||||
sed -nE 's/.*torch[[:space:]]*==[[:space:]]*([0-9]+(\.[0-9]+){1,2}).*/\1/p' "$file"
|
||||
}
|
||||
|
||||
mapfile -t upstream_matches < <(extract_torch_version "$tmp_upstream")
|
||||
mapfile -t current_matches < <(extract_torch_version "$TARGET_FILE")
|
||||
|
||||
if [[ "${#upstream_matches[@]}" -ne 1 ]]; then
|
||||
echo "Expected exactly one torch pin in upstream file, found ${#upstream_matches[@]}"
|
||||
printf 'Matches: %s\n' "${upstream_matches[@]:-<none>}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "${#current_matches[@]}" -ne 1 ]]; then
|
||||
echo "Expected exactly one torch pin in ${TARGET_FILE}, found ${#current_matches[@]}"
|
||||
printf 'Matches: %s\n' "${current_matches[@]:-<none>}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
upstream="${upstream_matches[0]}"
|
||||
current="${current_matches[0]}"
|
||||
|
||||
echo "Current torch version : $current"
|
||||
echo "Upstream torch version: $upstream"
|
||||
|
||||
{
|
||||
echo "current=$current"
|
||||
echo "upstream=$upstream"
|
||||
} >> "$GITHUB_OUTPUT"
|
||||
|
||||
if [[ "$upstream" == "$current" ]]; then
|
||||
echo "Torch version already up to date."
|
||||
echo "changed=false" >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
awk -v new_ver="$upstream" '
|
||||
BEGIN { updated = 0 }
|
||||
{
|
||||
if ($0 ~ /torch[[:space:]]*==[[:space:]]*[0-9]+(\.[0-9]+){1,2}/) {
|
||||
sub(/torch[[:space:]]*==[[:space:]]*[0-9]+(\.[0-9]+){1,2}/, "torch==" new_ver)
|
||||
updated++
|
||||
}
|
||||
print
|
||||
}
|
||||
END {
|
||||
if (updated != 1) {
|
||||
printf("Expected to update exactly one torch pin, updated %d\n", updated) > "/dev/stderr"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
' "$TARGET_FILE" > "$tmp_output"
|
||||
|
||||
mv "$tmp_output" "$TARGET_FILE"
|
||||
|
||||
if git diff --quiet -- "$TARGET_FILE"; then
|
||||
echo "No file change detected after update."
|
||||
echo "changed=false" >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "changed=true" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Create pull request
|
||||
if: steps.sync.outputs.changed == 'true'
|
||||
uses: peter-evans/create-pull-request@v8
|
||||
with:
|
||||
token: ${{ github.token }}
|
||||
branch: automation/sync-torch-version
|
||||
base: dev
|
||||
delete-branch: true
|
||||
signoff: true
|
||||
add-paths: |
|
||||
pyproject.toml
|
||||
commit-message: "[Build] sync torch version with vLLM (${{
|
||||
steps.sync.outputs.upstream }})"
|
||||
title: "[Build] sync torch version with vLLM (${{
|
||||
steps.sync.outputs.upstream }})"
|
||||
body: |
|
||||
Auto-sync the pinned torch version in `pyproject.toml` with vLLM.
|
||||
|
||||
- Current: `${{ steps.sync.outputs.current }}`
|
||||
- Upstream: `${{ steps.sync.outputs.upstream }}`
|
||||
|
||||
This PR was generated automatically by GitHub Actions.
|
||||
labels: |
|
||||
dependencies
|
||||
automation
|
||||
@@ -0,0 +1,170 @@
|
||||
name: Test
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
workflow_dispatch:
|
||||
pull_request:
|
||||
branches:
|
||||
- "dev"
|
||||
- "release-**"
|
||||
|
||||
env:
|
||||
LC_ALL: en_US.UTF-8
|
||||
PYTHONHASHSEED: 0
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
# Cancel older in-flight runs on the same PR / branch.
|
||||
concurrency:
|
||||
group: test-${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
changes:
|
||||
name: Detect changes
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
pull-requests: read
|
||||
outputs:
|
||||
lmcache: ${{ github.event_name == 'workflow_dispatch' || github.event_name == 'release' || steps.filter.outputs.lmcache == 'true' }}
|
||||
raw_block: ${{ github.event_name == 'workflow_dispatch' || github.event_name == 'release' || steps.filter.outputs.raw_block == 'true' }}
|
||||
steps:
|
||||
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
||||
if: github.event_name == 'push'
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
- uses: dorny/paths-filter@v3
|
||||
if: github.event_name == 'push' || github.event_name == 'pull_request'
|
||||
id: filter
|
||||
with:
|
||||
filters: |
|
||||
lmcache:
|
||||
- '**.py'
|
||||
- 'pyproject.toml'
|
||||
- 'requirements/**.txt'
|
||||
- '.github/workflows/test.yml'
|
||||
- '!operator/**'
|
||||
raw_block:
|
||||
- 'rust/raw_block/**'
|
||||
- 'lmcache/v1/storage_backend/raw_block/**'
|
||||
- 'lmcache/v1/distributed/l2_adapters/raw_block_l2_adapter.py'
|
||||
- 'lmcache/v1/multiprocess/**'
|
||||
- 'tests/v1/storage_backend/test_raw_block*.py'
|
||||
- 'tests/v1/storage_backend/raw_block_test_utils.py'
|
||||
- 'tests/v1/multiprocess/test_raw_block_l2_adapter.py'
|
||||
- '.github/workflows/test.yml'
|
||||
|
||||
test:
|
||||
needs: changes
|
||||
if: needs.changes.outputs.lmcache == 'true'
|
||||
name: "test: ${{ matrix.python }} on ${{ matrix.platform }}"
|
||||
runs-on: "${{ matrix.platform }}"
|
||||
strategy:
|
||||
matrix:
|
||||
python:
|
||||
- "3.10"
|
||||
- "3.11"
|
||||
- "3.12"
|
||||
- "3.13"
|
||||
platform:
|
||||
- "ubuntu-latest"
|
||||
|
||||
steps:
|
||||
- name: "Harden Runner"
|
||||
uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
||||
with:
|
||||
# https://github.com/actions/checkout/issues/249
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Free disk space
|
||||
uses: ./.github/actions/free-disk-space
|
||||
|
||||
- name: Setup Python ${{ matrix.python }}
|
||||
uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0
|
||||
with:
|
||||
python-version: ${{ matrix.python }}
|
||||
cache: pip
|
||||
cache-dependency-path: |
|
||||
**/pyproject.toml
|
||||
**/requirements/*.txt
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
python -m pip install vllm
|
||||
python -m pip install -r requirements/test.txt
|
||||
python -m pip install -r requirements/common.txt
|
||||
|
||||
- name: "Run non-CUDA unit tests"
|
||||
run: |
|
||||
pytest --ignore=tests/disagg \
|
||||
--ignore=tests/v1/multiprocess/ \
|
||||
--ignore=tests/v1/distributed/ \
|
||||
--ignore=tests/v1/mp_observability/ \
|
||||
--ignore=tests/skipped \
|
||||
--ignore=tests/cli/commands/trace \
|
||||
--ignore=tests/v1/storage_backend/test_eic.py \
|
||||
--ignore=tests/v1/storage_backend/test_p2p_backend_with_controller.py
|
||||
|
||||
raw-block-tests:
|
||||
needs: changes
|
||||
if: needs.changes.outputs.raw_block == 'true'
|
||||
name: raw-block temp-file tests
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
LMCACHE_LOG_LEVEL: CRITICAL
|
||||
|
||||
steps:
|
||||
- name: "Harden Runner"
|
||||
uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0
|
||||
with:
|
||||
egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup Python 3.11
|
||||
uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0
|
||||
with:
|
||||
python-version: "3.11"
|
||||
cache: pip
|
||||
cache-dependency-path: |
|
||||
**/pyproject.toml
|
||||
**/requirements/*.txt
|
||||
|
||||
- name: Install Rust
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
|
||||
- name: Install Python dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
python -m pip install maturin
|
||||
python -m pip install -r requirements/test.txt
|
||||
python -m pip install -r requirements/common.txt
|
||||
|
||||
- name: Build raw-block Rust extension
|
||||
run: |
|
||||
python -m maturin build --release \
|
||||
--manifest-path rust/raw_block/Cargo.toml \
|
||||
--out .pytest-tmp/raw-block-dist
|
||||
python -m pip install .pytest-tmp/raw-block-dist/*.whl
|
||||
|
||||
- name: Run raw-block tests
|
||||
run: |
|
||||
pytest -q --basetemp=.pytest-tmp/raw-block \
|
||||
tests/v1/storage_backend/test_raw_block_device.py \
|
||||
tests/v1/storage_backend/test_raw_block_core.py \
|
||||
tests/v1/multiprocess/test_raw_block_l2_adapter.py
|
||||
@@ -0,0 +1,109 @@
|
||||
name: Update Chinese Documentation Translations
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 9 * * 1"
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
max_entries:
|
||||
description: "Maximum entries to translate in this run"
|
||||
required: false
|
||||
default: "50"
|
||||
|
||||
concurrency:
|
||||
group: update-chinese-docs
|
||||
cancel-in-progress: false
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
translate-docs:
|
||||
name: Update Chinese docs translations
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
||||
with:
|
||||
ref: dev
|
||||
|
||||
- name: Setup Python 3.13
|
||||
uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0
|
||||
with:
|
||||
python-version: "3.13"
|
||||
|
||||
- name: Install Dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install -r requirements/docs.txt
|
||||
|
||||
- name: Reuse translations from open PR
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
# Reuse the automation branch only while its PR is open; a closed PR's
|
||||
# branch is stale and would overwrite human edits merged to dev.
|
||||
open_prs=$(gh pr list --repo "$GITHUB_REPOSITORY" \
|
||||
--head automation/update-chinese-docs --state open \
|
||||
--json number --jq 'length' || echo 0)
|
||||
if [ "${open_prs:-0}" -gt 0 ] && \
|
||||
git fetch origin automation/update-chinese-docs 2>/dev/null; then
|
||||
echo "Open translation PR found; reusing its translations."
|
||||
git checkout FETCH_HEAD -- docs/source/locale/zh_CN/LC_MESSAGES/ || true
|
||||
else
|
||||
echo "No open translation PR; using dev as the translation base."
|
||||
fi
|
||||
|
||||
- name: Update gettext catalogs
|
||||
run: |
|
||||
sphinx-build -b gettext docs/source docs/build/gettext
|
||||
sphinx-intl update -p docs/build/gettext -l zh_CN -d docs/source/locale -j 1
|
||||
|
||||
- name: Delete translations for renamed or removed docs
|
||||
run: |
|
||||
find docs/source/locale/zh_CN/LC_MESSAGES -name '*.po' | while read -r po; do
|
||||
rel="${po#docs/source/locale/zh_CN/LC_MESSAGES/}"
|
||||
if [ ! -f "docs/build/gettext/${rel%.po}.pot" ]; then
|
||||
echo "deleting $po (no matching source doc)"
|
||||
git rm -fq --ignore-unmatch "$po"
|
||||
fi
|
||||
done
|
||||
|
||||
- name: Translate missing Chinese entries
|
||||
env:
|
||||
TRANSLATION_API_BASE_URL: ${{ secrets.TRANSLATION_API_BASE_URL }}
|
||||
TRANSLATION_API_KEY: ${{ secrets.TRANSLATION_API_KEY }}
|
||||
TRANSLATION_MODEL: ${{ secrets.TRANSLATION_MODEL }}
|
||||
TRANSLATION_MAX_ENTRIES: ${{ inputs.max_entries || '500' }}
|
||||
run: |
|
||||
python tools/translate_docs_zh.py
|
||||
|
||||
- name: Validate Chinese docs build
|
||||
run: |
|
||||
SPHINX_LANGUAGE=zh_CN sphinx-build -b html docs/source docs/build/html/zh_CN
|
||||
|
||||
- name: Open or update translation PR
|
||||
uses: peter-evans/create-pull-request@v8
|
||||
with:
|
||||
token: ${{ github.token }}
|
||||
branch: automation/update-chinese-docs
|
||||
base: dev
|
||||
delete-branch: true
|
||||
signoff: true
|
||||
add-paths: |
|
||||
docs/source/locale/zh_CN/LC_MESSAGES
|
||||
commit-message: "Update Chinese documentation translations"
|
||||
title: "Update Chinese documentation translations"
|
||||
body: |
|
||||
Automated weekly update for Chinese documentation translations.
|
||||
|
||||
Generated by `.github/workflows/translate_doc_zh.yml`.
|
||||
labels: |
|
||||
documentation
|
||||
automation
|
||||
Reference in New Issue
Block a user