diff --git a/.buildkite/pipeline.yml b/.buildkite/pipeline.yml index 96aa9e8ba..5cc52f2d5 100644 --- a/.buildkite/pipeline.yml +++ b/.buildkite/pipeline.yml @@ -1,14 +1,14 @@ # Document 1: Buildkite loads only this block on first parse. The next step resolves docs-only skip-ci # from git diff, then uploads document 2. When docs-only skip applies, image-build still runs for the nightly -# exception in upload_pipeline_with_skip_ci.sh (nightly-test label or main NIGHTLY=1); otherwise upload-nightly +# exception in upload_pipeline.py (nightly-test label or main NIGHTLY=1); otherwise upload-nightly # can be skipped together with test-ready/test-merge. Weekly uploads also depend on image-build. -# Document 2: appended after `---`; same file, read by upload_pipeline_with_skip_ci.sh (not evaluated as a second pipeline by Buildkite). Child uploads include test-ready.yml, test-merge.yml, test-nightly.yml, and test-weekly.yml. +# Document 2: appended after `---`; same file, read by upload_pipeline.py (not evaluated as a second pipeline by Buildkite). Child uploads include test-ready.yml, test-merge.yml, test-nightly.yml, and test-weekly.yml. steps: - label: ":github: Resolve skip-ci & upload pipeline" key: upload-ci-pipeline commands: - - "bash .buildkite/scripts/upload_pipeline_with_skip_ci.sh" + - "python3 .buildkite/scripts/upload_pipeline.py --upload .buildkite/pipeline.yml" agents: queue: "cpu_queue_premerge" @@ -41,7 +41,7 @@ steps: key: upload-merge-pipeline if: __UPLOAD_MERGE_IF__ commands: - - buildkite-agent pipeline upload .buildkite/test-merge.yml + - python3 .buildkite/scripts/upload_pipeline.py --upload .buildkite/test-merge.yml agents: queue: "cpu_queue_premerge" diff --git a/.buildkite/rebase-pipeline.yaml b/.buildkite/rebase-pipeline.yaml index edd98fafd..3ae553fd3 100644 --- a/.buildkite/rebase-pipeline.yaml +++ b/.buildkite/rebase-pipeline.yaml @@ -23,7 +23,7 @@ steps: depends_on: image-build key: upload-merge-pipeline commands: - - buildkite-agent pipeline upload .buildkite/test-merge.yml + - python3 .buildkite/scripts/upload_pipeline.py --upload .buildkite/test-merge.yml agents: queue: "cpu_queue_premerge" diff --git a/.buildkite/scripts/upload_pipeline.py b/.buildkite/scripts/upload_pipeline.py new file mode 100644 index 000000000..1a1254dbc --- /dev/null +++ b/.buildkite/scripts/upload_pipeline.py @@ -0,0 +1,308 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: Apache-2.0 +"""Render and optionally upload Buildkite pipeline YAML with diff-aware logic. + +Bootstrap mode (pipeline.yml with __IMAGE_BUILD_IF__ placeholders): + - Detect docs-only PR/main changes and substitute skip-ci ``if`` expressions. + +Test pipeline mode (e.g. test-merge.yml): + - Drop steps or groups whose ``source_file_dependencies`` do not match changed files. + - ``source_file_dependencies`` may be set on a leaf step or on a group step. + - Always strip ``source_file_dependencies`` from uploaded YAML (Buildkite does not + recognize this uploader-only key). + +Usage: + python3 upload_pipeline.py [--upload] + + # Bootstrap (replaces upload_pipeline_with_skip_ci.sh): + python3 upload_pipeline.py --upload .buildkite/pipeline.yml + + # Test pipeline (replaces upload_test_pipeline_with_diff_skip.py): + python3 upload_pipeline.py --upload .buildkite/test-merge.yml +""" + +from __future__ import annotations + +import argparse +import os +import subprocess +import sys +from pathlib import Path +from typing import Any + +try: + import yaml +except ImportError: + subprocess.check_call( + [sys.executable, "-m", "pip", "install", "-q", "pyyaml"], + ) + import yaml + +LOG = "upload_pipeline" +ROOT = Path(__file__).resolve().parent.parent.parent +DOC_SEP = "\n---\n" +BOOTSTRAP_MARKER = "__IMAGE_BUILD_IF__" + + +def _log(message: str) -> None: + print(f"{LOG}: {message}", file=sys.stderr) + + +def _git(*args: str) -> subprocess.CompletedProcess[str]: + return subprocess.run( + ["git", *args], + check=False, + capture_output=True, + text=True, + ) + + +def resolve_changed_files() -> list[str] | None: + """Return changed file paths, or None when diff cannot be resolved.""" + is_pr = os.environ.get("BUILDKITE_PULL_REQUEST", "false") != "false" and os.environ.get( + "BUILDKITE_PULL_REQUEST", "" + ) + commit = os.environ.get("BUILDKITE_COMMIT", "") + + if is_pr: + base_branch = os.environ.get("BUILDKITE_PULL_REQUEST_BASE_BRANCH", "main") + base_ref = f"origin/{base_branch}" + if _git("rev-parse", "--verify", base_ref).returncode != 0: + _log(f"origin/{base_branch} not found locally; trying fetch") + _git("fetch", "--depth=200", "origin", base_branch) + if _git("rev-parse", "--verify", base_ref).returncode != 0: + if _git("rev-parse", "--verify", base_branch).returncode == 0: + base_ref = base_branch + else: + _log(f"cannot resolve PR base {base_branch}; using safe defaults") + return None + diff_range = f"{base_ref}...{commit}" + elif os.environ.get("BUILDKITE_BRANCH", "") == "main": + if _git("rev-parse", "--verify", f"{commit}^").returncode != 0: + _log("main commit has no parent; using safe defaults") + return None + diff_range = f"{commit}^..{commit}" + else: + _log("not PR/main build; using safe defaults") + return None + + result = _git("diff", "--name-only", diff_range) + if result.returncode != 0: + _log(f"git diff failed ({diff_range}); using safe defaults") + return None + + files = [line for line in result.stdout.splitlines() if line.strip()] + _log(f"{len(files)} changed file(s)") + return files + + +def is_docs_only_change(changed_files: list[str]) -> bool: + has_any = False + for file_path in changed_files: + if not file_path: + continue + has_any = True + if file_path.startswith("docs/"): + continue + if file_path.endswith(".md"): + continue + if file_path == "mkdocs.yml": + continue + return False + return has_any + + +def resolve_skip_ci(changed_files: list[str] | None) -> bool: + if changed_files is None: + _log("skip-ci=0 (could not resolve changed files)") + return False + if is_docs_only_change(changed_files): + _log("docs-only change detected; skip-ci=1") + return True + _log("non-doc changes detected; skip-ci=0") + return False + + +def render_bootstrap_pipeline(text: str, *, skip_ci: bool) -> str: + if DOC_SEP in text: + _, continuation = text.split(DOC_SEP, 1) + else: + continuation = text + + nightly_only = ( + '(build.pull_request.labels includes "nightly-test") || (build.branch == "main" && build.env("NIGHTLY") == "1")' + ) + if skip_ci: + image_if = f"'{nightly_only}'" + ready_if = "'false'" + merge_if = "'false'" + else: + image_if = "'true'" + ready_if = '\'build.branch != "main" && build.pull_request.labels includes "ready"\'' + merge_if = ( + '\'(build.branch == "main" && build.env("NIGHTLY") != "1" ' + '&& build.env("WEEKLY") != "1") || ' + '(build.branch != "main" && build.pull_request.labels includes "merge-test")\'' + ) + + return ( + continuation.replace("__IMAGE_BUILD_IF__", image_if) + .replace("__UPLOAD_READY_IF__", ready_if) + .replace("__UPLOAD_MERGE_IF__", merge_if) + ) + + +def _matches_dependencies(changed_files: list[str], prefixes: list[str]) -> bool: + for path in changed_files: + for prefix in prefixes: + normalized = prefix.rstrip("/") + if path == normalized or path.startswith(f"{normalized}/"): + return True + return False + + +def _strip_source_file_dependencies(step: dict[str, Any]) -> dict[str, Any]: + return {key: value for key, value in step.items() if key != "source_file_dependencies"} + + +def _step_label(step: dict[str, Any]) -> str: + return str(step.get("group") or step.get("label") or "") + + +def _filter_steps(steps: list[Any], changed_files: list[str]) -> list[Any]: + filtered: list[Any] = [] + for step in steps: + if not isinstance(step, dict): + filtered.append(step) + continue + + deps = step.get("source_file_dependencies") + if deps is not None and not isinstance(deps, list): + raise ValueError( + f"source_file_dependencies must be a list in step {_step_label(step)!r}", + ) + if deps is not None and not _matches_dependencies(changed_files, deps): + _log( + f"skip {_step_label(step)!r} (no changes under {deps})", + ) + continue + + nested = step.get("steps") + if nested is not None: + kept_nested = _filter_steps(nested, changed_files) + if not kept_nested: + _log(f"omit empty group {_step_label(step)!r}") + continue + new_step = _strip_source_file_dependencies(step) + new_step["steps"] = kept_nested + filtered.append(new_step) + continue + + if deps is not None: + filtered.append(_strip_source_file_dependencies(step)) + else: + filtered.append(step) + + return filtered + + +def _strip_uploader_metadata_from_steps(steps: list[Any]) -> list[Any]: + """Remove uploader-only keys while keeping all steps (no diff filtering).""" + stripped: list[Any] = [] + for step in steps: + if not isinstance(step, dict): + stripped.append(step) + continue + + deps = step.get("source_file_dependencies") + if deps is not None and not isinstance(deps, list): + raise ValueError( + f"source_file_dependencies must be a list in step {_step_label(step)!r}", + ) + + nested = step.get("steps") + new_step = _strip_source_file_dependencies(step) + if nested is not None: + new_step["steps"] = _strip_uploader_metadata_from_steps(nested) + stripped.append(new_step) + + return stripped + + +def render_test_pipeline( + doc: dict[str, Any], + changed_files: list[str] | None, +) -> dict[str, Any]: + steps = doc.get("steps") + if not isinstance(steps, list): + return doc + if changed_files is not None: + steps = _filter_steps(steps, changed_files) + else: + steps = _strip_uploader_metadata_from_steps(steps) + return {**doc, "steps": steps} + + +def resolve_pipeline_path(arg: str) -> Path: + path = Path(arg) + if path.is_absolute(): + return path + return ROOT / path + + +def render_pipeline(path: Path) -> str: + text = path.read_text(encoding="utf-8") + changed_files = resolve_changed_files() + + if BOOTSTRAP_MARKER in text: + rendered = render_bootstrap_pipeline(text, skip_ci=resolve_skip_ci(changed_files)) + return rendered + + doc = yaml.safe_load(text) + if not isinstance(doc, dict): + raise ValueError(f"invalid pipeline YAML: {path}") + + doc = render_test_pipeline(doc, changed_files) + + return yaml.safe_dump(doc, sort_keys=False) + + +def upload_to_buildkite(content: str) -> None: + subprocess.run( + ["buildkite-agent", "pipeline", "upload"], + input=content, + text=True, + check=True, + ) + + +def main() -> int: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument( + "pipeline", + nargs="?", + default=".buildkite/pipeline.yml", + help="Pipeline YAML path (default: .buildkite/pipeline.yml)", + ) + parser.add_argument( + "--upload", + action="store_true", + help="Pipe rendered YAML to buildkite-agent pipeline upload", + ) + args = parser.parse_args() + + path = resolve_pipeline_path(args.pipeline) + if not path.is_file(): + _log(f"missing pipeline file: {path}") + return 1 + + rendered = render_pipeline(path) + if args.upload: + upload_to_buildkite(rendered) + else: + sys.stdout.write(rendered) + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/.buildkite/scripts/upload_pipeline_with_skip_ci.sh b/.buildkite/scripts/upload_pipeline_with_skip_ci.sh deleted file mode 100644 index c19fe7063..000000000 --- a/.buildkite/scripts/upload_pipeline_with_skip_ci.sh +++ /dev/null @@ -1,146 +0,0 @@ -#!/usr/bin/env bash -# Evaluate docs-only skip-ci and upload continuation steps from the given pipeline YAML -# (YAML document after the first `---`). Buildkite `if` is evaluated at upload time. -# -# Usage: upload_pipeline_with_skip_ci.sh [pipeline_yaml] -# pipeline_yaml: path relative to repo root or absolute (default: .buildkite/pipeline.yml) -set -euo pipefail - -ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" -PIPELINE_ARG="${1:-.buildkite/pipeline.yml}" -if [[ "${PIPELINE_ARG}" = /* ]]; then - PIPELINE_YML="${PIPELINE_ARG}" -else - PIPELINE_YML="${ROOT}/${PIPELINE_ARG}" -fi - -# Prints a single digit to stdout: 1 = skip image CI, 0 = run. Logs go to stderr. -is_docs_only_change() { - local file_path - local has_any=0 - - while IFS= read -r file_path; do - [[ -z "${file_path}" ]] && continue - has_any=1 - - if [[ "${file_path}" == docs/* ]]; then - continue - fi - if [[ "${file_path}" == *.md ]]; then - continue - fi - if [[ "${file_path}" == "mkdocs.yml" ]]; then - continue - fi - return 1 - done - - [[ "${has_any}" -eq 1 ]] -} - -resolve_skip_ci() { - local is_pr_build=0 - local files - local base_branch base_ref - - if [[ "${BUILDKITE_PULL_REQUEST:-false}" != "false" && -n "${BUILDKITE_PULL_REQUEST:-}" ]]; then - is_pr_build=1 - fi - - if [[ "${is_pr_build}" -eq 1 ]]; then - base_branch="${BUILDKITE_PULL_REQUEST_BASE_BRANCH:-main}" - if ! git rev-parse --verify "origin/${base_branch}" >/dev/null 2>&1; then - echo "resolve_skip_ci: origin/${base_branch} not found locally; trying fetch" >&2 - git fetch --depth=200 origin "${base_branch}" >/dev/null 2>&1 || true - fi - - base_ref="" - if git rev-parse --verify "origin/${base_branch}" >/dev/null 2>&1; then - base_ref="origin/${base_branch}" - elif git rev-parse --verify "${base_branch}" >/dev/null 2>&1; then - base_ref="${base_branch}" - else - echo "resolve_skip_ci: cannot resolve PR base ${base_branch}; skip-ci=0" >&2 - echo -n 0 - return 0 - fi - - if ! files="$(git diff --name-only "${base_ref}...${BUILDKITE_COMMIT}" 2>/dev/null)"; then - echo "resolve_skip_ci: failed to compute PR changed files; skip-ci=0" >&2 - echo -n 0 - return 0 - fi - elif [[ "${BUILDKITE_BRANCH:-}" == "main" ]]; then - if ! git rev-parse --verify "${BUILDKITE_COMMIT}^" >/dev/null 2>&1; then - echo "resolve_skip_ci: commit has no parent on main; skip-ci=0" >&2 - echo -n 0 - return 0 - fi - if ! files="$(git diff --name-only "${BUILDKITE_COMMIT}^..${BUILDKITE_COMMIT}" 2>/dev/null)"; then - echo "resolve_skip_ci: failed to compute main changed files; skip-ci=0" >&2 - echo -n 0 - return 0 - fi - else - echo "resolve_skip_ci: not PR/main build; skip-ci=0" >&2 - echo -n 0 - return 0 - fi - - if is_docs_only_change <<< "${files}"; then - echo "resolve_skip_ci: docs-only change detected; skip-ci=1" >&2 - echo -n 1 - return 0 - fi - - echo "resolve_skip_ci: non-doc changes detected; skip-ci=0" >&2 - echo -n 0 -} - -SKIP_CI="$(resolve_skip_ci)" - -if [[ ! -f "${PIPELINE_YML}" ]]; then - echo "upload_pipeline_with_skip_ci: missing ${PIPELINE_YML}" >&2 - exit 1 -fi - -export ROOT SKIP_CI PIPELINE_YML -python3 <<'PY' | buildkite-agent pipeline upload -import os -import pathlib - -path = pathlib.Path(os.environ["PIPELINE_YML"]) -text = path.read_text(encoding="utf-8") -sep = "\n---\n" -# Two supported layouts: -# - multi-doc: doc 1 = bootstrap (loaded by Buildkite), doc 2 (after `---`) = uploaded steps. -# - single-doc: whole file is the uploaded steps; caller (UI init step) is the bootstrap. -if sep in text: - _, continuation = text.split(sep, 1) -else: - continuation = text - -skip = os.environ.get("SKIP_CI") == "1" -# When docs-only skip-ci: skip default CI image, but still build for L4 nightly (PR label nightly-test or -# main NIGHTLY=1), otherwise upload-nightly (depends_on image-build) would be skipped too. -nightly_only = ( - '(build.pull_request.labels includes "nightly-test") ' - '|| (build.branch == "main" && build.env("NIGHTLY") == "1")' -) -# Placeholder in pipeline.yml is `if: __IMAGE_BUILD_IF__` (valid YAML); replace value only. -if skip: - rep = f"'{nightly_only}'" - ready_rep = "'false'" - merge_rep = "'false'" -else: - rep = "'true'" - ready_rep = "'build.branch != \"main\" && build.pull_request.labels includes \"ready\"'" - merge_rep = "'(build.branch == \"main\" && build.env(\"NIGHTLY\") != \"1\" && build.env(\"WEEKLY\") != \"1\") || (build.branch != \"main\" && build.pull_request.labels includes \"merge-test\")'" -rendered = ( - continuation - .replace("__IMAGE_BUILD_IF__", rep) - .replace("__UPLOAD_READY_IF__", ready_rep) - .replace("__UPLOAD_MERGE_IF__", merge_rep) -) -print(rendered, end="") -PY diff --git a/.buildkite/test-merge.yml b/.buildkite/test-merge.yml index 191b7f214..410695f4b 100644 --- a/.buildkite/test-merge.yml +++ b/.buildkite/test-merge.yml @@ -44,6 +44,9 @@ steps: depends_on: upload-merge-pipeline steps: - label: "Diffusion · LoRA Test" + source_file_dependencies: + - tests/diffusion/lora/ + - vllm_omni/diffusion/lora/ timeout_in_minutes: 30 commands: - pytest -sv tests/diffusion/lora/ -m 'advanced_model and cuda' --run-level "advanced_model" @@ -61,6 +64,9 @@ steps: - "/fsx/hf_cache:/fsx/hf_cache" - label: "Distributed Test" + source_file_dependencies: + - tests/distributed/ + - vllm_omni/distributed/ timeout_in_minutes: 60 commands: - | @@ -105,6 +111,9 @@ steps: - group: ":card_index_dividers: Entrypoints Test" depends_on: upload-merge-pipeline + source_file_dependencies: + - tests/entrypoints/ + - vllm_omni/entrypoints/ steps: - label: "Entrypoint Test with H100" timeout_in_minutes: 60 @@ -165,6 +174,13 @@ steps: depends_on: upload-merge-pipeline steps: - label: "TTS · Qwen3-TTS CustomVoice Test" + source_file_dependencies: + - tests/e2e/online_serving/test_qwen3_tts_customvoice.py + - tests/e2e/offline_inference/test_qwen3_tts_customvoice.py + - vllm_omni/model_executor/models/qwen3_tts/ + - vllm_omni/model_executor/stage_input_processors/qwen3_tts.py + - vllm_omni/deploy/qwen3_tts.yaml + - vllm_omni/model_executor/stage_configs/qwen3_tts_uniproc.yaml commands: - | timeout 20m bash -c " @@ -186,6 +202,12 @@ steps: - "/fsx/hf_cache:/fsx/hf_cache" - label: "TTS · Qwen3-TTS Base Test" + source_file_dependencies: + - tests/e2e/online_serving/test_qwen3_tts_base.py + - tests/e2e/offline_inference/test_qwen3_tts_base.py + - vllm_omni/model_executor/models/qwen3_tts/ + - vllm_omni/model_executor/stage_input_processors/qwen3_tts.py + - vllm_omni/deploy/qwen3_tts.yaml commands: - | timeout 20m bash -c " @@ -207,6 +229,12 @@ steps: - "/fsx/hf_cache:/fsx/hf_cache" - label: "TTS · Voxtral-TTS Test" + source_file_dependencies: + - tests/e2e/offline_inference/test_voxtral_tts.py + - tests/e2e/online_serving/test_voxtral_tts.py + - vllm_omni/model_executor/models/voxtral_tts/ + - vllm_omni/model_executor/stage_input_processors/voxtral_tts.py + - vllm_omni/deploy/voxtral_tts.yaml timeout_in_minutes: 20 commands: - | @@ -249,6 +277,12 @@ steps: type: DirectoryOrCreate - label: "TTS · GLM-TTS Test" + source_file_dependencies: + - tests/e2e/online_serving/test_glm_tts.py + - tests/e2e/offline_inference/test_glm_tts.py + - vllm_omni/model_executor/models/glm_tts/ + - vllm_omni/model_executor/stage_input_processors/glm_tts.py + - vllm_omni/deploy/glm_tts.yaml timeout_in_minutes: 20 commands: - | @@ -291,6 +325,12 @@ steps: type: DirectoryOrCreate - label: "Omni · Qwen3-Omni Test" + source_file_dependencies: + - tests/e2e/offline_inference/test_qwen3_omni.py + - tests/e2e/online_serving/test_qwen3_omni.py + - vllm_omni/model_executor/models/qwen3_omni/ + - vllm_omni/model_executor/stage_input_processors/qwen3_omni.py + - vllm_omni/deploy/qwen3_omni_moe.yaml timeout_in_minutes: 30 commands: - pytest -s -v tests/e2e/offline_inference/test_qwen3_omni.py tests/e2e/online_serving/test_qwen3_omni.py -m 'advanced_model and cuda' --run-level 'advanced_model' @@ -329,6 +369,11 @@ steps: type: DirectoryOrCreate - label: "Omni · Mimo Audio Test" + source_file_dependencies: + - tests/e2e/online_serving/test_mimo_audio.py + - vllm_omni/model_executor/models/mimo_audio/ + - vllm_omni/model_executor/stage_input_processors/mimo_audio.py + - vllm_omni/deploy/mimo_audio.yaml timeout_in_minutes: 30 commands: - pytest -s -v tests/e2e/online_serving/test_mimo_audio.py -m 'advanced_model and cuda' --run-level 'advanced_model' @@ -366,37 +411,19 @@ steps: path: /mnt/hf-cache type: DirectoryOrCreate - - label: "Omni · VoxCPM2 Test" - timeout_in_minutes: 20 - commands: - - | - timeout 20m bash -c " - export VLLM_LOGGING_LEVEL=DEBUG - export VLLM_WORKER_MULTIPROC_METHOD=spawn - pytest -s -v tests/e2e/offline_inference/test_voxcpm2.py -m 'advanced_model and cuda' --run-level 'advanced_model' - " - agents: - queue: "gpu_1_queue" - plugins: - - docker#v5.2.0: - image: public.ecr.aws/q9t5s3a7/vllm-ci-test-repo:$BUILDKITE_COMMIT - always-pull: true - propagate-environment: true - shm-size: "8gb" - environment: - - "HF_HOME=/fsx/hf_cache" - - "HF_TOKEN" - volumes: - - "/fsx/hf_cache:/fsx/hf_cache" - - - label: "TTS · VoxCPM2 Online Test" + - label: "TTS · VoxCPM2 Test" + source_file_dependencies: + - tests/e2e/offline_inference/test_voxcpm2_tts.py + - tests/e2e/online_serving/test_voxcpm2_tts.py + - vllm_omni/model_executor/models/voxcpm2/ + - vllm_omni/deploy/voxcpm2.yaml timeout_in_minutes: 30 commands: - | timeout 30m bash -c " export VLLM_LOGGING_LEVEL=DEBUG export VLLM_WORKER_MULTIPROC_METHOD=spawn - pytest -s -v tests/e2e/online_serving/test_voxcpm2_tts.py -m 'advanced_model and cuda' --run-level 'advanced_model' + pytest -s -v tests/e2e/offline_inference/test_voxcpm2_tts.py tests/e2e/online_serving/test_voxcpm2_tts.py -m 'advanced_model and cuda' --run-level 'advanced_model' " agents: queue: "gpu_1_queue" @@ -413,6 +440,12 @@ steps: - "/fsx/hf_cache:/fsx/hf_cache" - label: "Omni · Higgs-Audio V2 Test" + source_file_dependencies: + - tests/e2e/online_serving/test_higgs_audio_v2.py + - tests/e2e/offline_inference/test_higgs_audio_v2.py + - vllm_omni/model_executor/models/higgs_audio_v2/ + - vllm_omni/model_executor/stage_input_processors/higgs_audio_v2.py + - vllm_omni/deploy/higgs_audio_v2.yaml timeout_in_minutes: 30 commands: - | @@ -438,6 +471,9 @@ steps: - "/fsx/hf_cache:/fsx/hf_cache" - label: "Diffusion · Qwen Image Edit Test" + source_file_dependencies: + - tests/e2e/online_serving/test_qwen_image_edit.py + - vllm_omni/diffusion/models/qwen_image/ timeout_in_minutes: 20 commands: - pytest -s -v tests/e2e/online_serving/test_qwen_image_edit.py -m 'advanced_model and cuda' --run-level 'advanced_model' @@ -476,6 +512,9 @@ steps: type: DirectoryOrCreate - label: "Diffusion · Longcat Image Edit Test" + source_file_dependencies: + - tests/e2e/online_serving/test_longcat_image_edit.py + - vllm_omni/diffusion/models/longcat_image/ timeout_in_minutes: 20 commands: - pytest -s -v tests/e2e/online_serving/test_longcat_image_edit.py -m 'advanced_model and cuda' --run-level 'advanced_model' @@ -514,6 +553,9 @@ steps: type: DirectoryOrCreate - label: "Diffusion · Longcat Image Test" + source_file_dependencies: + - tests/e2e/online_serving/test_longcat_image.py + - vllm_omni/diffusion/models/longcat_image/ timeout_in_minutes: 20 commands: - pytest -s -v tests/e2e/online_serving/test_longcat_image.py -m 'advanced_model and cuda' --run-level 'advanced_model' @@ -552,6 +594,13 @@ steps: type: DirectoryOrCreate - label: "Diffusion · Bagel Test" + source_file_dependencies: + - tests/e2e/offline_inference/test_bagel.py + - tests/e2e/online_serving/test_bagel.py + - vllm_omni/model_executor/models/bagel/ + - vllm_omni/diffusion/models/bagel/ + - vllm_omni/model_executor/stage_input_processors/bagel.py + - vllm_omni/deploy/bagel.yaml timeout_in_minutes: 20 commands: - pytest -s -v tests/e2e/offline_inference/test_bagel.py tests/e2e/online_serving/test_bagel.py -m 'advanced_model and cuda' --run-level 'advanced_model' @@ -591,6 +640,9 @@ steps: - label: "Diffusion · Qwen Image Test" + source_file_dependencies: + - tests/e2e/online_serving/test_qwen_image.py + - vllm_omni/diffusion/models/qwen_image/ commands: - | timeout 40m bash -c ' @@ -632,6 +684,9 @@ steps: type: DirectoryOrCreate - label: "Diffusion · Qwen Image Layered Test" + source_file_dependencies: + - tests/e2e/online_serving/test_qwen_image_layered.py + - vllm_omni/diffusion/models/qwen_image/ commands: - | timeout 40m bash -c " @@ -673,6 +728,10 @@ steps: type: DirectoryOrCreate - label: "Diffusion · Wan22 Test" + source_file_dependencies: + - tests/e2e/offline_inference/test_wan22_t2v.py + - tests/e2e/online_serving/test_wan22_t2v.py + - vllm_omni/diffusion/models/wan2_2/ commands: - | timeout 40m bash -c " @@ -714,6 +773,9 @@ steps: type: DirectoryOrCreate - label: "Diffusion · HunyuanVideo 1.5 Test" + source_file_dependencies: + - tests/e2e/online_serving/test_hunyuan_video_15.py + - vllm_omni/diffusion/models/hunyuan_video/ timeout_in_minutes: 40 commands: - | @@ -755,6 +817,10 @@ steps: type: DirectoryOrCreate - label: "Diffusion · Z Image Test" + source_file_dependencies: + - tests/e2e/offline_inference/test_z_image.py + - tests/e2e/online_serving/test_z_image.py + - vllm_omni/diffusion/models/z_image/ timeout_in_minutes: 30 commands: - pytest -s -v tests/e2e/offline_inference/test_z_image.py tests/e2e/online_serving/test_z_image.py -m 'advanced_model and cuda and diffusion' --run-level 'advanced_model' @@ -772,6 +838,10 @@ steps: - "/fsx/hf_cache:/fsx/hf_cache" - label: "Diffusion · FLUX.2 Klein Test" + source_file_dependencies: + - tests/e2e/offline_inference/test_flux2_klein.py + - tests/e2e/online_serving/test_flux2_klein.py + - vllm_omni/diffusion/models/flux2_klein/ timeout_in_minutes: 30 commands: - pytest -s -v tests/e2e/offline_inference/test_flux2_klein.py tests/e2e/online_serving/test_flux2_klein.py -m 'advanced_model and cuda and diffusion' --run-level 'advanced_model' @@ -789,6 +859,9 @@ steps: - "/fsx/hf_cache:/fsx/hf_cache" - label: "Diffusion · SD3 Test" + source_file_dependencies: + - tests/e2e/online_serving/test_sd3.py + - vllm_omni/diffusion/models/sd3/ timeout_in_minutes: 45 commands: - | diff --git a/.buildkite/test-ready.yml b/.buildkite/test-ready.yml index 8db0dba97..1881b4496 100644 --- a/.buildkite/test-ready.yml +++ b/.buildkite/test-ready.yml @@ -309,37 +309,14 @@ steps: path: /mnt/hf-cache type: DirectoryOrCreate - - label: "Omni · VoxCPM2 Test" - timeout_in_minutes: 20 - commands: - - | - timeout 20m bash -c " - export VLLM_LOGGING_LEVEL=DEBUG - export VLLM_WORKER_MULTIPROC_METHOD=spawn - pytest -s -v tests/e2e/offline_inference/test_voxcpm2.py -m 'core_model' --run-level 'core_model' - " - agents: - queue: "gpu_1_queue" - plugins: - - docker#v5.2.0: - image: public.ecr.aws/q9t5s3a7/vllm-ci-test-repo:$BUILDKITE_COMMIT - always-pull: true - propagate-environment: true - shm-size: "8gb" - environment: - - "HF_HOME=/fsx/hf_cache" - - "HF_TOKEN" - volumes: - - "/fsx/hf_cache:/fsx/hf_cache" - - - label: "TTS · VoxCPM2 Online Test" + - label: "TTS · VoxCPM2 Test" timeout_in_minutes: 30 commands: - | timeout 30m bash -c " export VLLM_LOGGING_LEVEL=DEBUG export VLLM_WORKER_MULTIPROC_METHOD=spawn - pytest -s -v tests/e2e/online_serving/test_voxcpm2_tts.py -m 'core_model and tts' --run-level 'core_model' + pytest -s -v tests/e2e/offline_inference/test_voxcpm2_tts.py tests/e2e/online_serving/test_voxcpm2_tts.py -m 'core_model' --run-level 'core_model' " agents: queue: "gpu_1_queue" diff --git a/tests/e2e/offline_inference/test_voxcpm2.py b/tests/e2e/offline_inference/test_voxcpm2_tts.py similarity index 100% rename from tests/e2e/offline_inference/test_voxcpm2.py rename to tests/e2e/offline_inference/test_voxcpm2_tts.py