--- a/contrib/heptapod-ci.yml Mon Oct 28 16:31:49 2024 +0100
+++ b/contrib/heptapod-ci.yml Tue Oct 29 09:38:48 2024 +0100
@@ -20,7 +20,12 @@
when: always
stages:
+ - build
+ - checks
- tests
+ - platform-compat
+ - py-version-compat
+
image: registry.heptapod.net/mercurial/ci-images/mercurial-core:$HG_CI_IMAGE_TAG
@@ -32,7 +37,37 @@
.all_template: &all
when: on_success
+ needs: []
+# TODO: we should use an image based on manylinux instead "all-in-one" image
+# used for all test so far.
+.build-wheel: &wheel
+ <<: *all
+ stage: build
+ variables:
+ WHEEL_TYPE: ""
+ FLAVOR: ""
+ before_script:
+ - echo "python used, $PYTHON"
+ - $PYTHON --version
+ - echo $WHEEL_TYPE
+ - test -n "$WHEEL_TYPE"
+ - echo $FLAVOR
+ - mkdir -p wheels/$WHEEL_TYPE
+ script:
+ - $PYTHON setup.py bdist_wheel $FLAVOR --dist-dir wheels/$WHEEL_TYPE
+ artifacts:
+ paths:
+ - wheels/$WHEEL_TYPE
+ expire_in: 1 week
+
+build-c-wheel:
+ <<: *wheel
+ variables:
+ WHEEL_TYPE: "c"
+
+# TODO: We should select the wheel compatible with the python (and plateform)
+# we use. This is necessary to build multiple wheel.
.runtests_template: &runtests
<<: *all
stage: tests
@@ -48,10 +83,23 @@
- ls -1 tests/test-check-*.* > /tmp/check-tests.txt
script:
- echo "$RUNTEST_ARGS"
- - HGTESTS_ALLOW_NETIO="$TEST_HGTESTS_ALLOW_NETIO" "$PYTHON" tests/run-tests.py --color=always $RUNTEST_ARGS
+ - echo "$WHEEL_TYPE"
+ - WHEEL=""
+ - if test -n "$WHEEL_TYPE"; then
+ WHEEL="`ls -1 $CI_PROJECT_DIR/wheels/$WHEEL_TYPE/*.whl`";
+ test -n "$WHEEL";
+ fi
+ - if test -n "$WHEEL"; then
+ echo installing from $WHEEL;
+ HGTESTS_ALLOW_NETIO="$TEST_HGTESTS_ALLOW_NETIO" "$PYTHON" tests/run-tests.py --hg-wheel $WHEEL --color=always $RUNTEST_ARGS;
+ else
+ echo installing from source;
+ HGTESTS_ALLOW_NETIO="$TEST_HGTESTS_ALLOW_NETIO" "$PYTHON" tests/run-tests.py --color=always $RUNTEST_ARGS;
+ fi
checks:
<<: *runtests
+ stage: checks
variables:
SHOW_VERSION_OF: "$PYTHON black clang-format"
RUNTEST_ARGS: "--time --test-list /tmp/check-tests.txt"
@@ -59,19 +107,27 @@
rust-cargo-test:
<<: *all
- stage: tests
+ stage: checks
script:
- make rust-tests
- make cargo-clippy
variables:
CI_CLEVER_CLOUD_FLAVOR: S
-test-c: &test_c
+.test-c: &test_c
<<: *runtests
variables:
RUNTEST_ARGS: " --no-rust --blacklist /tmp/check-tests.txt"
TEST_HGTESTS_ALLOW_NETIO: "1"
+test-c:
+ <<: *test_c
+ needs: [build-c-wheel]
+ variables:
+ WHEEL_TYPE: "c"
+ RUNTEST_ARGS: "--blacklist /tmp/check-tests.txt"
+ TEST_HGTESTS_ALLOW_NETIO: "1"
+
test-pure:
<<: *runtests
variables:
@@ -99,36 +155,42 @@
# version (and 3.12 have been giving us various troubles)
test-3.8-c:
<<: *test_c
+ stage: py-version-compat
when: manual # avoid overloading the CI by default
variables:
PYTHON: python3.8
test-3.12-c:
<<: *test_c
+ stage: py-version-compat
when: manual # avoid overloading the CI by default
variables:
PYTHON: python3.12
test-3.12-rust:
<<: *test_rust
+ stage: py-version-compat
when: manual # avoid overloading the CI by default
variables:
PYTHON: python3.12
test-3.13-c:
<<: *test_c
+ stage: py-version-compat
when: manual # avoid overloading the CI by default
variables:
PYTHON: python3.13
test-3.13-rust:
<<: *test_rust
+ stage: py-version-compat
when: manual # avoid overloading the CI by default
variables:
PYTHON: python3.13
check-pytype:
- extends: .runtests_template
+ <<: *test_rust
+ stage: checks
before_script:
- export PATH="/home/ci-runner/vendor/pyenv/pyenv-2.4.7-adf3c2bccf09cdb81febcfd15b186711a33ac7a8/shims:/home/ci-runner/vendor/pyenv/pyenv-2.4.7-adf3c2bccf09cdb81febcfd15b186711a33ac7a8/bin:$PATH"
- echo "PATH, $PATH"
@@ -149,7 +211,7 @@
.window_runtests_template: &windows_runtests
<<: *all
when: manual # we don't have any Windows runners anymore at the moment
- stage: tests
+ stage: platform-compat
before_script:
- C:/MinGW/msys/1.0/bin/sh.exe --login -c 'cd "$OLDPWD" && ls -1 tests/test-check-*.* > C:/Temp/check-tests.txt'
# TODO: find/install cvs, bzr, perforce, gpg, sqlite3
@@ -183,6 +245,7 @@
macos:
<<: *test_c
+ stage: platform-compat
when: manual # avoid overloading the CI by default
tags:
- macos
--- a/tests/run-tests.py Mon Oct 28 16:31:49 2024 +0100
+++ b/tests/run-tests.py Tue Oct 29 09:38:48 2024 +0100
@@ -61,6 +61,7 @@
import shlex
import shutil
import signal
+import site
import socket
import subprocess
import sys
@@ -625,6 +626,13 @@
help="prefer IPv6 to IPv4 for network related tests",
)
hgconf.add_argument(
+ "--hg-wheel",
+ default=None,
+ metavar="WHEEL_PATH",
+ dest="wheel",
+ help="install mercurial from the given wheel",
+ )
+ hgconf.add_argument(
"--pure",
action="store_true",
help="use pure Python code instead of C extensions",
@@ -3219,7 +3227,12 @@
# detect and enforce an alternative way to specify rust extension usage
if (
- not (self.options.pure or self.options.rust or self.options.no_rust)
+ not (
+ self.options.wheel
+ or self.options.pure
+ or self.options.rust
+ or self.options.no_rust
+ )
and os.environ.get("HGWITHRUSTEXT") == "cpython"
):
self.options.rust = True
@@ -3257,7 +3270,12 @@
self._installdir = os.path.join(self._hgtmp, b"install")
self._bindir = os.path.join(self._installdir, b"bin")
self._hgcommand = b'hg'
- self._pythondir = os.path.join(self._installdir, b"lib", b"python")
+
+ if self.options.wheel:
+ suffix = _sys2bytes(site.USER_SITE[len(site.USER_BASE) + 1 :])
+ else:
+ suffix = os.path.join(b"lib", b"python")
+ self._pythondir = os.path.join(self._installdir, suffix)
# Force the use of hg.exe instead of relying on MSYS to recognize hg is
# a python script and feed it to python.exe. Legacy stdio is force
@@ -3782,59 +3800,113 @@
os.symlink(real_exec, target_exec)
self._createdfiles.append(target_exec)
+ def _install_hg_cmd_wheel(self):
+ wheel_path = self.options.wheel
+ assert wheel_path
+
+ # TODO: actually use these flag later, to double check the wheel we
+ # installed match our intend (in `_checkhglib`)
+ if self.options.pure:
+ assert False, b"--pure"
+ elif self.options.rust:
+ assert False, b"--rust"
+ elif self.options.no_rust:
+ assert False, b"--no-rust"
+
+ script = _sys2bytes(os.path.realpath(sys.argv[0]))
+ exe = _sys2bytes(sysexecutable)
+ hgroot = os.path.dirname(os.path.dirname(script))
+ self._hgroot = hgroot
+ os.chdir(hgroot)
+ cmd = [
+ exe,
+ b"-m",
+ b"pip",
+ b"install",
+ wheel_path,
+ b"--force",
+ b"--ignore-installed",
+ b"--user",
+ b"--break-system-packages",
+ ]
+ if not WINDOWS:
+ # The --home="" trick works only on OS where os.sep == '/'
+ # because of a distutils convert_path() fast-path. Avoid it at
+ # least on Windows for now, deal with .pydistutils.cfg bugs
+ # when they happen.
+ # cmd.append(b"--global-option=--home=")
+ pass
+
+ return cmd
+
+ def _install_hg_cmd_setup(self):
+ # Run installer in hg root
+ setup_opts = b""
+ if self.options.pure:
+ setup_opts = b"--pure"
+ elif self.options.rust:
+ setup_opts = b"--rust"
+ elif self.options.no_rust:
+ setup_opts = b"--no-rust"
+
+ script = _sys2bytes(os.path.realpath(sys.argv[0]))
+ exe = _sys2bytes(sysexecutable)
+ hgroot = os.path.dirname(os.path.dirname(script))
+ self._hgroot = hgroot
+ os.chdir(hgroot)
+ cmd = [
+ exe,
+ b"setup.py",
+ ]
+ if setup_opts:
+ cmd.append(setup_opts)
+ cmd.extend(
+ [
+ b"clean",
+ b"--all",
+ b"build",
+ ]
+ )
+ if self.options.compiler:
+ cmd.append("--compiler")
+ cmd.append(_sys2bytes(self.options.compiler))
+ cmd.extend(
+ [
+ b"--build-base=%s" % os.path.join(self._hgtmp, b"build"),
+ b"install",
+ b"--force",
+ b"--prefix=%s" % self._installdir,
+ b"--install-lib=%s" % self._pythondir,
+ b"--install-scripts=%s" % self._bindir,
+ ]
+ )
+ if not WINDOWS:
+ # The --home="" trick works only on OS where os.sep == '/'
+ # because of a distutils convert_path() fast-path. Avoid it at
+ # least on Windows for now, deal with .pydistutils.cfg bugs
+ # when they happen.
+ cmd.append(b"--home=")
+
+ return cmd
+
def _installhg(self):
"""Install hg into the test environment.
This will also configure hg with the appropriate testing settings.
"""
vlog("# Performing temporary installation of HG")
+ install_env = original_env.copy()
+ if self.options.wheel is None:
+ cmd = self._install_hg_cmd_setup()
+ else:
+ cmd = self._install_hg_cmd_wheel()
+ install_env["PYTHONUSERBASE"] = _bytes2sys(self._installdir)
+
installerrs = os.path.join(self._hgtmp, b"install.err")
- compiler = ''
- install_env = original_env.copy()
- if self.options.compiler:
- compiler = '--compiler ' + self.options.compiler
- setup_opts = b""
if self.options.pure:
- setup_opts = b"--pure"
- install_env.pop('HGWITHRUSTEXT', None)
- elif self.options.rust:
- setup_opts = b"--rust"
- elif self.options.no_rust:
- setup_opts = b"--no-rust"
install_env.pop('HGWITHRUSTEXT', None)
-
- # Run installer in hg root
- compiler = _sys2bytes(compiler)
- script = _sys2bytes(os.path.realpath(sys.argv[0]))
- exe = _sys2bytes(sysexecutable)
- hgroot = os.path.dirname(os.path.dirname(script))
- self._hgroot = hgroot
- os.chdir(hgroot)
- nohome = b'--home=""'
- if WINDOWS:
- # The --home="" trick works only on OS where os.sep == '/'
- # because of a distutils convert_path() fast-path. Avoid it at
- # least on Windows for now, deal with .pydistutils.cfg bugs
- # when they happen.
- nohome = b''
- cmd = (
- b'"%(exe)s" setup.py %(setup_opts)s clean --all'
- b' build %(compiler)s --build-base="%(base)s"'
- b' install --force --prefix="%(prefix)s"'
- b' --install-lib="%(libdir)s"'
- b' --install-scripts="%(bindir)s" %(nohome)s >%(logfile)s 2>&1'
- % {
- b'exe': exe,
- b'setup_opts': setup_opts,
- b'compiler': compiler,
- b'base': os.path.join(self._hgtmp, b"build"),
- b'prefix': self._installdir,
- b'libdir': self._pythondir,
- b'bindir': self._bindir,
- b'nohome': nohome,
- b'logfile': installerrs,
- }
- )
+ elif self.options.no_rust:
+ install_env.pop('HGWITHRUSTEXT', None)
# setuptools requires install directories to exist.
def makedirs(p):
@@ -3846,8 +3918,15 @@
makedirs(self._pythondir)
makedirs(self._bindir)
- vlog("# Running", cmd.decode("utf-8"))
- if subprocess.call(_bytes2sys(cmd), shell=True, env=install_env) == 0:
+ vlog("# Running", cmd)
+ with open(installerrs, "wb") as logfile:
+ r = subprocess.call(
+ cmd,
+ env=install_env,
+ stdout=logfile,
+ stderr=subprocess.STDOUT,
+ )
+ if r == 0:
if not self.options.verbose:
try:
os.remove(installerrs)