This is an automated email from the ASF dual-hosted git repository.

tqchen pushed a commit to branch jenkins-wheel-test-artifacts
in repository https://gitbox.apache.org/repos/asf/tvm.git


The following commit(s) were added to refs/heads/jenkins-wheel-test-artifacts 
by this push:
     new a6d7f3b274 [CI] Bootstrap declared build requirements before wheel 
creation
a6d7f3b274 is described below

commit a6d7f3b2747c0d21a0607d82bd05b6793304776a
Author: Tianqi Chen <[email protected]>
AuthorDate: Thu Oct 15 00:37:45 2026 +0000

    [CI] Bootstrap declared build requirements before wheel creation
    
    Install missing build requirements in the selected Python environment 
before the offline no-isolation wheel build. Keep installed-wheel consumers 
offline without dependency installation and stop immediately when build setup 
fails.
---
 ci/jenkins/README.md                    | 17 +++++++-------
 ci/jenkins/generated/common.groovy      |  5 +++--
 tests/python/ci/test_wheel_artifacts.py | 40 +++++++++++++++++++++++++++++++++
 tests/scripts/ci.py                     |  1 +
 4 files changed, 53 insertions(+), 10 deletions(-)

diff --git a/ci/jenkins/README.md b/ci/jenkins/README.md
index e3292c13a8..0bf17757e2 100644
--- a/ci/jenkins/README.md
+++ b/ci/jenkins/README.md
@@ -104,13 +104,14 @@ path overrides, and verify the package and native-library 
paths. FFI comes from
 the image. GPU Java tests also receive their existing native runtime libraries;
 the separate runtime-only compile check and Emscripten runtime build remain.
 
-The selected images must already provide the requirements in `pyproject.toml`
-(including scikit-build-core, setuptools-scm and compatible apache-tvm-ffi), 
the
-platform runtime dependencies, and the test dependencies. The pinned image must
-be checked before rollout: the current image recipe does not provision all 
these
-wheel prerequisites. Missing dependencies are errors, not permission for a test
-stage to fetch or build replacements. No image publication or Jenkins 
deployment
-is performed by this change.
+Immediately before building, the same container and Python install the declared
+`pyproject.toml` build requirements (scikit-build-core, setuptools-scm and
+mlc-z3-static) without requesting upgrades to already-satisfying versions. A
+failed bootstrap stops the build. `uv build` then runs offline without 
isolation.
+
+The selected images must already provide compatible runtime and test 
dependencies,
+including apache-tvm-ffi. Consumer wheel installation remains `--no-deps 
--offline`;
+missing runtime dependencies are errors rather than permission to fetch 
replacements.
 
 `CMAKE_BUILD_PARALLEL_LEVEL` is passed through Docker as an environment 
variable.
 An explicit value wins; otherwise builds use at least one CPU and divide the
@@ -123,7 +124,7 @@ Jenkins may select the old trusted-main Jenkinsfile while 
checking out a newer
 PR revision. Retain `tests/scripts/task_build.py`, the original raw-artifact
 bundles, and the source-mode test interfaces until trusted main has migrated.
 The native pipelines and local wheel commands explicitly pass
-`TVM_TEST_USE_WHEEL=1`; only that mode installs wheel artifacts without 
fetching
+`TVM_TEST_USE_WHEEL=1`; only that mode installs wheel artifacts without 
fetching runtime
 dependencies. Calls without the flag retain the old source setup and dependency
 installation behavior. A missing wheel in wheel mode is an error, not a 
fallback
 to source mode.
diff --git a/ci/jenkins/generated/common.groovy 
b/ci/jenkins/generated/common.groovy
index 57c8e7eb57..422d806c09 100644
--- a/ci/jenkins/generated/common.groovy
+++ b/ci/jenkins/generated/common.groovy
@@ -315,10 +315,11 @@ def build_docker() {
 }
 
 def wheel_build(image, cpp_tests = false) {
-  // uv build never resolves runtime dependencies. No isolation plus offline 
uses
-  // only the backend and FFI already provisioned in the image.
+  // Bootstrap only the declared build requirements in the selected 
interpreter.
+  // The build itself stays offline; runtime dependencies belong to the image.
   def commands = build_environment() + '''
     rm -rf build/wheels
+    uv pip install --python python3 "scikit-build-core>=0.11" 
"setuptools-scm>=8" "mlc-z3-static>=4.16.0"
     uv build --wheel --no-build-isolation --offline --python python3 --out-dir 
build/wheels . \
       -Cbuild-dir=build -Ccmake.build-type=RelWithDebInfo 
-Cbuild.verbose="${VERBOSE:-true}"
   '''.stripIndent().trim()
diff --git a/tests/python/ci/test_wheel_artifacts.py 
b/tests/python/ci/test_wheel_artifacts.py
index ae0c8c5141..3551bfab25 100644
--- a/tests/python/ci/test_wheel_artifacts.py
+++ b/tests/python/ci/test_wheel_artifacts.py
@@ -16,9 +16,11 @@
 # under the License.
 """Wheel artifact transport and local CI command contracts, without a TVM 
import."""
 
+import ast
 import importlib.util
 import json
 import os
+import re
 import shutil
 import subprocess
 import sys
@@ -245,3 +247,41 @@ def 
test_wheel_mode_does_not_fall_back_when_install_fails(tmp_path):
     )
     assert result.returncode == 37
     assert "uv pip install" not in result.stderr
+
+
[email protected]("bootstrap_fails", [False, True])
+def test_build_bootstrap_precedes_offline_build(tmp_path, monkeypatch, 
bootstrap_fails):
+    import shlex
+
+    ci = load_local_ci()
+    calls = []
+    monkeypatch.setattr(ci, "docker", lambda **kwargs: calls.append(kwargs))
+    command, _, _ = ci.generate_command("cpu", {}, "wheel build")
+    command()
+    commands = [script for script in calls[0]["scripts"] if 
script.startswith("uv ")]
+    bootstrap, build = commands
+    arguments = shlex.split(bootstrap)
+    # The declared build requirements are a flat string list; keep this test 
usable on Python 3.10.
+    requires = re.search(r"(?ms)^requires = (\[.*?\])", (ROOT / 
"pyproject.toml").read_text())
+    expected = ast.literal_eval(requires[1])
+    assert arguments[:5] == ["uv", "pip", "install", "--python", "python3"]
+    assert arguments[5:] == expected
+    assert "--no-build-isolation --offline --python python3" in build
+    binary = tmp_path / "uv"
+    binary.write_text(
+        f"#!{sys.executable}\n"
+        "import json, pathlib, sys\n"
+        "with pathlib.Path('calls').open('a') as out: 
out.write(json.dumps(sys.argv[1:]) + '\\n')\n"
+        f"sys.exit(17 if {bootstrap_fails!r} and sys.argv[1] == 'pip' else 
0)\n"
+    )
+    binary.chmod(0o755)
+    result = subprocess.run(
+        [shutil.which("bash"), "-ec", "\n".join(commands)],
+        cwd=tmp_path,
+        env={**os.environ, "PATH": f"{tmp_path}:{os.environ['PATH']}"},
+        capture_output=True,
+        text=True,
+    )
+    assert result.returncode == (17 if bootstrap_fails else 0)
+    recorded = [json.loads(line) for line in (tmp_path / 
"calls").read_text().splitlines()]
+    assert [call[0] for call in recorded] == (["pip"] if bootstrap_fails else 
["pip", "build"])
diff --git a/tests/scripts/ci.py b/tests/scripts/ci.py
index a39abaff49..9d6423f9ff 100755
--- a/tests/scripts/ci.py
+++ b/tests/scripts/ci.py
@@ -403,6 +403,7 @@ def generate_command(
             scripts = [
                 f"./tests/scripts/task_config_build_{name}.sh {build_dir}",
                 f"rm -rf {build_dir}/wheels",
+                'uv pip install --python python3 "scikit-build-core>=0.11" 
"setuptools-scm>=8" "mlc-z3-static>=4.16.0"',
                 f"uv build --wheel --no-build-isolation --offline --python 
python3 --out-dir {build_dir}/wheels . "
                 f"-Cbuild-dir={build_dir} -Ccmake.build-type=RelWithDebInfo "
                 f"-Cbuild.verbose={'true' if verbose else 'false'}"

Reply via email to