From e520b900bf6a7eae4ef5a3ca91c7f0e106182fa7 Mon Sep 17 00:00:00 2001 From: paugier Date: Fri, 4 Sep 2020 15:14:04 +0200 Subject: [PATCH 01/13] Add a Mercurial contentprovider MyBinder could support Mercurial repositories See https://github.com/jupyterhub/binderhub/issues/1148 --- Pipfile | 2 + dev-requirements.txt | 2 + repo2docker/contentproviders/__init__.py | 1 + repo2docker/contentproviders/mercurial.py | 79 ++++++++++++++++++ tests/unit/contentproviders/test_mercurial.py | 82 +++++++++++++++++++ 5 files changed, 166 insertions(+) create mode 100644 repo2docker/contentproviders/mercurial.py create mode 100644 tests/unit/contentproviders/test_mercurial.py diff --git a/Pipfile b/Pipfile index b4d56fdf2..3aa175da6 100644 --- a/Pipfile +++ b/Pipfile @@ -12,6 +12,8 @@ alabaster = "*" Sphinx = ">=1.4,!=1.5.4" alabaster_jupyterhub = "*" sphinxcontrib-autoprogram = "*" +mercurial = "*" +hg-evolve = "*" [packages] repo2docker = {path=".", editable=true} diff --git a/dev-requirements.txt b/dev-requirements.txt index bcecb7ba7..288c0e5d2 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -6,3 +6,5 @@ wheel pytest-cov pre-commit requests +mercurial +hg-evolve diff --git a/repo2docker/contentproviders/__init__.py b/repo2docker/contentproviders/__init__.py index c53290d86..ae0b8c27c 100755 --- a/repo2docker/contentproviders/__init__.py +++ b/repo2docker/contentproviders/__init__.py @@ -4,3 +4,4 @@ from .figshare import Figshare from .dataverse import Dataverse from .hydroshare import Hydroshare +from .mercurial import Mercurial diff --git a/repo2docker/contentproviders/mercurial.py b/repo2docker/contentproviders/mercurial.py new file mode 100644 index 000000000..c8c8c1370 --- /dev/null +++ b/repo2docker/contentproviders/mercurial.py @@ -0,0 +1,79 @@ +import subprocess + +from .base import ContentProvider, ContentProviderException +from ..utils import execute_cmd + + +hg_config = [ + "--config", + "extensions.hggit=!", + "--config", + "extensions.evolve=", + "--config", + "extensions.topic=", +] + + +class Mercurial(ContentProvider): + """Provide contents of a remote Mercurial repository.""" + + def detect(self, source, ref=None, extra_args=None): + if "github.com/" in source or source.endswith(".git"): + return None + try: + subprocess.check_output( + ["hg", "identify", source] + hg_config, stderr=subprocess.DEVNULL, + ) + except subprocess.CalledProcessError: + return None + + return {"repo": source, "ref": ref} + + def fetch(self, spec, output_dir, yield_output=False): + repo = spec["repo"] + ref = spec.get("ref", None) + + # make a clone of the remote repository + try: + cmd = ["hg", "clone", repo, output_dir] + cmd.extend(hg_config) + if ref is not None: + # don't update so the clone will include an empty working + # directory, the given ref will be updated out later + cmd.extend(["--noupdate"]) + for line in execute_cmd(cmd, capture=yield_output): + yield line + + except subprocess.CalledProcessError as error: + msg = "Failed to clone repository from {repo}".format(repo=repo) + if ref is not None: + msg += " (ref {ref})".format(ref=ref) + msg += "." + raise ContentProviderException(msg) from error + + # check out the specific ref given by the user + if ref is not None: + try: + for line in execute_cmd( + ["hg", "update", "--clean", ref] + hg_config, + cwd=output_dir, + capture=yield_output, + ): + yield line + except subprocess.CalledProcessError: + self.log.error( + "Failed to update to ref %s", ref, extra=dict(phase="failed") + ) + raise ValueError("Failed to update to ref {}".format(ref)) + + cmd = ["hg", "identify"] + cmd.extend(hg_config) + sha1 = subprocess.Popen(cmd, stdout=subprocess.PIPE, cwd=output_dir) + self._sha1 = sha1.stdout.read().decode().strip() + + @property + def content_id(self): + """A unique ID to represent the version of the content. + Uses the first seven characters of the git commit ID of the repository. + """ + return self._sha1[:7] diff --git a/tests/unit/contentproviders/test_mercurial.py b/tests/unit/contentproviders/test_mercurial.py new file mode 100644 index 000000000..5cfcd4820 --- /dev/null +++ b/tests/unit/contentproviders/test_mercurial.py @@ -0,0 +1,82 @@ +from pathlib import Path +import subprocess +from tempfile import TemporaryDirectory + +import pytest + +from repo2docker.contentproviders import Mercurial + + +def _add_content_to_hg(repo_dir): + """Add content to file 'test' in hg repository and commit.""" + # use append mode so this can be called multiple times + with open(Path(repo_dir) / "test", "a") as f: + f.write("Hello") + + subprocess.check_call(["hg", "add", "test"], cwd=repo_dir) + subprocess.check_call(["hg", "commit", "-m", "Test commit"], cwd=repo_dir) + + +def _get_sha1(repo_dir): + """Get repository's current commit SHA1.""" + sha1 = subprocess.Popen(["hg", "identify"], stdout=subprocess.PIPE, cwd=repo_dir) + return sha1.stdout.read().decode().strip() + + +@pytest.fixture() +def hg_repo(): + """ + Make a dummy git repo in which user can perform git operations + + Should be used as a contextmanager, it will delete directory when done + """ + with TemporaryDirectory() as gitdir: + subprocess.check_call(["hg", "init"], cwd=gitdir) + yield gitdir + + +@pytest.fixture() +def hg_repo_with_content(hg_repo): + """Create a hg repository with content""" + _add_content_to_hg(hg_repo) + sha1 = _get_sha1(hg_repo) + + yield hg_repo, sha1 + + +def test_detect_mercurial(hg_repo_with_content, repo_with_content): + mercurial = Mercurial() + assert mercurial.detect("this-is-not-a-directory") is None + assert mercurial.detect("https://github.com/jupyterhub/repo2docker") is None + + git_repo = repo_with_content[0] + assert mercurial.detect(git_repo) is None + + hg_repo = hg_repo_with_content[0] + assert mercurial.detect(hg_repo) == {"repo": hg_repo, "ref": None} + + +def test_clone(hg_repo_with_content): + """Test simple hg clone to a target dir""" + upstream, sha1 = hg_repo_with_content + + with TemporaryDirectory() as clone_dir: + spec = {"repo": upstream} + mercurial = Mercurial() + for _ in mercurial.fetch(spec, clone_dir): + pass + assert (Path(clone_dir) / "test").exists() + + assert mercurial.content_id == sha1[:7] + + +def test_bad_ref(hg_repo_with_content): + """ + Test trying to checkout a ref that doesn't exist + """ + upstream, sha1 = hg_repo_with_content + with TemporaryDirectory() as clone_dir: + spec = {"repo": upstream, "ref": "does-not-exist"} + with pytest.raises(ValueError): + for _ in Mercurial().fetch(spec, clone_dir): + pass From 2d2e9bf19ad0dd11c5c545a62eb090e704362e69 Mon Sep 17 00:00:00 2001 From: paugier Date: Mon, 7 Sep 2020 09:38:07 +0200 Subject: [PATCH 02/13] Skip Mercurial for Python 3.5 --- Pipfile | 4 ++-- dev-requirements.txt | 4 ++-- tests/unit/contentproviders/test_mercurial.py | 13 ++++++++++++- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/Pipfile b/Pipfile index 3aa175da6..afc8bcd2a 100644 --- a/Pipfile +++ b/Pipfile @@ -12,8 +12,8 @@ alabaster = "*" Sphinx = ">=1.4,!=1.5.4" alabaster_jupyterhub = "*" sphinxcontrib-autoprogram = "*" -mercurial = "*" -hg-evolve = "*" +mercurial = {version = ">=5.2", markers="python_version > '3.5'"} +hg-evolve = {version = ">=10.0", markers="python_version > '3.5'"} [packages] repo2docker = {path=".", editable=true} diff --git a/dev-requirements.txt b/dev-requirements.txt index 288c0e5d2..1105d9aa6 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -6,5 +6,5 @@ wheel pytest-cov pre-commit requests -mercurial -hg-evolve +mercurial>=5.2; python_version > '3.5' +hg-evolve>=10.0; python_version > '3.5' diff --git a/tests/unit/contentproviders/test_mercurial.py b/tests/unit/contentproviders/test_mercurial.py index 5cfcd4820..dee5b5103 100644 --- a/tests/unit/contentproviders/test_mercurial.py +++ b/tests/unit/contentproviders/test_mercurial.py @@ -1,12 +1,18 @@ from pathlib import Path import subprocess from tempfile import TemporaryDirectory +import sys import pytest from repo2docker.contentproviders import Mercurial +skipif_py35 = pytest.mark.skipif( + sys.version_info < (3, 6), reason="requires python3.6" +) + + def _add_content_to_hg(repo_dir): """Add content to file 'test' in hg repository and commit.""" # use append mode so this can be called multiple times @@ -19,7 +25,9 @@ def _add_content_to_hg(repo_dir): def _get_sha1(repo_dir): """Get repository's current commit SHA1.""" - sha1 = subprocess.Popen(["hg", "identify"], stdout=subprocess.PIPE, cwd=repo_dir) + sha1 = subprocess.Popen( + ["hg", "identify"], stdout=subprocess.PIPE, cwd=repo_dir + ) return sha1.stdout.read().decode().strip() @@ -44,6 +52,7 @@ def hg_repo_with_content(hg_repo): yield hg_repo, sha1 +@skipif_py35 def test_detect_mercurial(hg_repo_with_content, repo_with_content): mercurial = Mercurial() assert mercurial.detect("this-is-not-a-directory") is None @@ -56,6 +65,7 @@ def test_detect_mercurial(hg_repo_with_content, repo_with_content): assert mercurial.detect(hg_repo) == {"repo": hg_repo, "ref": None} +@skipif_py35 def test_clone(hg_repo_with_content): """Test simple hg clone to a target dir""" upstream, sha1 = hg_repo_with_content @@ -70,6 +80,7 @@ def test_clone(hg_repo_with_content): assert mercurial.content_id == sha1[:7] +@skipif_py35 def test_bad_ref(hg_repo_with_content): """ Test trying to checkout a ref that doesn't exist From d26b3dd0dfb79325e6d0402ba767ec88d13329aa Mon Sep 17 00:00:00 2001 From: paugier Date: Mon, 7 Sep 2020 09:43:22 +0200 Subject: [PATCH 03/13] Mercurial: use the full node id (12 characters) for the content_id --- repo2docker/contentproviders/mercurial.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/repo2docker/contentproviders/mercurial.py b/repo2docker/contentproviders/mercurial.py index c8c8c1370..4d02c1fba 100644 --- a/repo2docker/contentproviders/mercurial.py +++ b/repo2docker/contentproviders/mercurial.py @@ -66,14 +66,12 @@ def fetch(self, spec, output_dir, yield_output=False): ) raise ValueError("Failed to update to ref {}".format(ref)) - cmd = ["hg", "identify"] + cmd = ["hg", "identify", "-i"] cmd.extend(hg_config) sha1 = subprocess.Popen(cmd, stdout=subprocess.PIPE, cwd=output_dir) - self._sha1 = sha1.stdout.read().decode().strip() + self._node_id = sha1.stdout.read().decode().strip() @property def content_id(self): - """A unique ID to represent the version of the content. - Uses the first seven characters of the git commit ID of the repository. - """ - return self._sha1[:7] + """A unique ID to represent the version of the content.""" + return self._node_id From fc3cef16a10b751433f3335a886b62496feea27e Mon Sep 17 00:00:00 2001 From: paugier Date: Mon, 7 Sep 2020 09:51:30 +0200 Subject: [PATCH 04/13] Fix test_mercurial.py (black, node_id and git->hg) --- tests/unit/contentproviders/test_mercurial.py | 32 +++++++++---------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/tests/unit/contentproviders/test_mercurial.py b/tests/unit/contentproviders/test_mercurial.py index dee5b5103..4018b2d22 100644 --- a/tests/unit/contentproviders/test_mercurial.py +++ b/tests/unit/contentproviders/test_mercurial.py @@ -8,9 +8,7 @@ from repo2docker.contentproviders import Mercurial -skipif_py35 = pytest.mark.skipif( - sys.version_info < (3, 6), reason="requires python3.6" -) +skipif_py35 = pytest.mark.skipif(sys.version_info < (3, 6), reason="requires python3.6") def _add_content_to_hg(repo_dir): @@ -23,33 +21,33 @@ def _add_content_to_hg(repo_dir): subprocess.check_call(["hg", "commit", "-m", "Test commit"], cwd=repo_dir) -def _get_sha1(repo_dir): - """Get repository's current commit SHA1.""" - sha1 = subprocess.Popen( - ["hg", "identify"], stdout=subprocess.PIPE, cwd=repo_dir +def _get_node_id(repo_dir): + """Get repository's current commit node ID (currently SHA1).""" + node_id = subprocess.Popen( + ["hg", "identify", "-i"], stdout=subprocess.PIPE, cwd=repo_dir ) - return sha1.stdout.read().decode().strip() + return node_id.stdout.read().decode().strip() @pytest.fixture() def hg_repo(): """ - Make a dummy git repo in which user can perform git operations + Make a dummy hg repo in which user can perform hg operations Should be used as a contextmanager, it will delete directory when done """ - with TemporaryDirectory() as gitdir: - subprocess.check_call(["hg", "init"], cwd=gitdir) - yield gitdir + with TemporaryDirectory() as hgdir: + subprocess.check_call(["hg", "init"], cwd=hgdir) + yield hgdir @pytest.fixture() def hg_repo_with_content(hg_repo): """Create a hg repository with content""" _add_content_to_hg(hg_repo) - sha1 = _get_sha1(hg_repo) + node_id = _get_node_id(hg_repo) - yield hg_repo, sha1 + yield hg_repo, node_id @skipif_py35 @@ -68,7 +66,7 @@ def test_detect_mercurial(hg_repo_with_content, repo_with_content): @skipif_py35 def test_clone(hg_repo_with_content): """Test simple hg clone to a target dir""" - upstream, sha1 = hg_repo_with_content + upstream, node_id = hg_repo_with_content with TemporaryDirectory() as clone_dir: spec = {"repo": upstream} @@ -77,7 +75,7 @@ def test_clone(hg_repo_with_content): pass assert (Path(clone_dir) / "test").exists() - assert mercurial.content_id == sha1[:7] + assert mercurial.content_id == node_id @skipif_py35 @@ -85,7 +83,7 @@ def test_bad_ref(hg_repo_with_content): """ Test trying to checkout a ref that doesn't exist """ - upstream, sha1 = hg_repo_with_content + upstream, node_id = hg_repo_with_content with TemporaryDirectory() as clone_dir: spec = {"repo": upstream, "ref": "does-not-exist"} with pytest.raises(ValueError): From 979c4abe004ae7ebd29537d5afd2890128dda71a Mon Sep 17 00:00:00 2001 From: paugier Date: Mon, 7 Sep 2020 10:06:58 +0200 Subject: [PATCH 05/13] Add Mercurial in content_providers in repo2docker/app.py --- repo2docker/app.py | 1 + 1 file changed, 1 insertion(+) diff --git a/repo2docker/app.py b/repo2docker/app.py index 660a87d64..937e74793 100755 --- a/repo2docker/app.py +++ b/repo2docker/app.py @@ -148,6 +148,7 @@ def _default_log_level(self): contentproviders.Figshare, contentproviders.Dataverse, contentproviders.Hydroshare, + contentproviders.Mercurial, contentproviders.Git, ], config=True, From 319e22ab1d1b7a5fbddcc7357c39306c2e4ff9dc Mon Sep 17 00:00:00 2001 From: paugier Date: Mon, 7 Sep 2020 12:17:16 +0200 Subject: [PATCH 06/13] Add Mercurial+evolve in install_requires --- setup.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/setup.py b/setup.py index 5084b486c..2f5bf3def 100644 --- a/setup.py +++ b/setup.py @@ -55,6 +55,8 @@ def get_identifier(json): "ruamel.yaml>=0.15", "toml", "semver", + "mercurial>=5.2; python_version > '3.5'", + "hg-evolve>=10.0; python_version > '3.5'", ], python_requires=">=3.6", author="Project Jupyter Contributors", From c91ed4eec5846f2c1a865ab8f7f43555ef586e6b Mon Sep 17 00:00:00 2001 From: paugier Date: Tue, 8 Sep 2020 10:09:13 +0200 Subject: [PATCH 07/13] Mercurial: remove conditions for py3.5 + requirements only in setup.py --- Pipfile | 2 -- dev-requirements.txt | 2 -- setup.py | 4 ++-- tests/unit/contentproviders/test_mercurial.py | 7 ------- 4 files changed, 2 insertions(+), 13 deletions(-) diff --git a/Pipfile b/Pipfile index afc8bcd2a..b4d56fdf2 100644 --- a/Pipfile +++ b/Pipfile @@ -12,8 +12,6 @@ alabaster = "*" Sphinx = ">=1.4,!=1.5.4" alabaster_jupyterhub = "*" sphinxcontrib-autoprogram = "*" -mercurial = {version = ">=5.2", markers="python_version > '3.5'"} -hg-evolve = {version = ">=10.0", markers="python_version > '3.5'"} [packages] repo2docker = {path=".", editable=true} diff --git a/dev-requirements.txt b/dev-requirements.txt index 1105d9aa6..bcecb7ba7 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -6,5 +6,3 @@ wheel pytest-cov pre-commit requests -mercurial>=5.2; python_version > '3.5' -hg-evolve>=10.0; python_version > '3.5' diff --git a/setup.py b/setup.py index 2f5bf3def..f41cea0ea 100644 --- a/setup.py +++ b/setup.py @@ -55,8 +55,8 @@ def get_identifier(json): "ruamel.yaml>=0.15", "toml", "semver", - "mercurial>=5.2; python_version > '3.5'", - "hg-evolve>=10.0; python_version > '3.5'", + "mercurial>=5.2", + "hg-evolve>=10.0", ], python_requires=">=3.6", author="Project Jupyter Contributors", diff --git a/tests/unit/contentproviders/test_mercurial.py b/tests/unit/contentproviders/test_mercurial.py index 4018b2d22..6b4f91006 100644 --- a/tests/unit/contentproviders/test_mercurial.py +++ b/tests/unit/contentproviders/test_mercurial.py @@ -1,16 +1,12 @@ from pathlib import Path import subprocess from tempfile import TemporaryDirectory -import sys import pytest from repo2docker.contentproviders import Mercurial -skipif_py35 = pytest.mark.skipif(sys.version_info < (3, 6), reason="requires python3.6") - - def _add_content_to_hg(repo_dir): """Add content to file 'test' in hg repository and commit.""" # use append mode so this can be called multiple times @@ -50,7 +46,6 @@ def hg_repo_with_content(hg_repo): yield hg_repo, node_id -@skipif_py35 def test_detect_mercurial(hg_repo_with_content, repo_with_content): mercurial = Mercurial() assert mercurial.detect("this-is-not-a-directory") is None @@ -63,7 +58,6 @@ def test_detect_mercurial(hg_repo_with_content, repo_with_content): assert mercurial.detect(hg_repo) == {"repo": hg_repo, "ref": None} -@skipif_py35 def test_clone(hg_repo_with_content): """Test simple hg clone to a target dir""" upstream, node_id = hg_repo_with_content @@ -78,7 +72,6 @@ def test_clone(hg_repo_with_content): assert mercurial.content_id == node_id -@skipif_py35 def test_bad_ref(hg_repo_with_content): """ Test trying to checkout a ref that doesn't exist From 96914545e1dfaca19e542dc4944b40fb2325b49a Mon Sep 17 00:00:00 2001 From: paugier Date: Wed, 9 Sep 2020 18:10:19 +0200 Subject: [PATCH 08/13] Update Dockerfile (ALPINE_VERSION=3.12.0 & install mercurial) + remove mercurial from install_requires --- Dockerfile | 12 ++++++++---- repo2docker/contentproviders/mercurial.py | 17 +++-------------- setup.py | 2 -- 3 files changed, 11 insertions(+), 20 deletions(-) diff --git a/Dockerfile b/Dockerfile index 84762c240..023d148b9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,7 @@ -ARG ALPINE_VERSION=3.9.4 +ARG ALPINE_VERSION=3.12.0 FROM alpine:${ALPINE_VERSION} -RUN apk add --no-cache git python3 python3-dev +RUN apk add --no-cache git python3 python3-dev py-pip # build wheels in first image ADD . /tmp/src @@ -15,8 +15,12 @@ RUN mkdir /tmp/wheelhouse \ FROM alpine:${ALPINE_VERSION} -# install python, git, bash -RUN apk add --no-cache git git-lfs python3 bash docker +# install python, git, bash, mercurial +RUN apk add --no-cache git git-lfs python3 py-pip bash docker mercurial + +# install and activate the evolve and topic Mercurial extensions +RUN pip3 install hg-evolve --user --no-cache-dir +RUN mkdir -p /etc/mercurial/hgrc.d && echo -e "[extensions]\nevolve =\ntopic =\n" > /etc/mercurial/hgrc.d/evolve.rc # install repo2docker COPY --from=0 /tmp/wheelhouse /tmp/wheelhouse diff --git a/repo2docker/contentproviders/mercurial.py b/repo2docker/contentproviders/mercurial.py index 4d02c1fba..2b33d23f0 100644 --- a/repo2docker/contentproviders/mercurial.py +++ b/repo2docker/contentproviders/mercurial.py @@ -4,16 +4,6 @@ from ..utils import execute_cmd -hg_config = [ - "--config", - "extensions.hggit=!", - "--config", - "extensions.evolve=", - "--config", - "extensions.topic=", -] - - class Mercurial(ContentProvider): """Provide contents of a remote Mercurial repository.""" @@ -22,7 +12,8 @@ def detect(self, source, ref=None, extra_args=None): return None try: subprocess.check_output( - ["hg", "identify", source] + hg_config, stderr=subprocess.DEVNULL, + ["hg", "identify", source, "--config", "extensions.hggit=!"], + stderr=subprocess.DEVNULL, ) except subprocess.CalledProcessError: return None @@ -36,7 +27,6 @@ def fetch(self, spec, output_dir, yield_output=False): # make a clone of the remote repository try: cmd = ["hg", "clone", repo, output_dir] - cmd.extend(hg_config) if ref is not None: # don't update so the clone will include an empty working # directory, the given ref will be updated out later @@ -55,7 +45,7 @@ def fetch(self, spec, output_dir, yield_output=False): if ref is not None: try: for line in execute_cmd( - ["hg", "update", "--clean", ref] + hg_config, + ["hg", "update", "--clean", ref], cwd=output_dir, capture=yield_output, ): @@ -67,7 +57,6 @@ def fetch(self, spec, output_dir, yield_output=False): raise ValueError("Failed to update to ref {}".format(ref)) cmd = ["hg", "identify", "-i"] - cmd.extend(hg_config) sha1 = subprocess.Popen(cmd, stdout=subprocess.PIPE, cwd=output_dir) self._node_id = sha1.stdout.read().decode().strip() diff --git a/setup.py b/setup.py index f41cea0ea..5084b486c 100644 --- a/setup.py +++ b/setup.py @@ -55,8 +55,6 @@ def get_identifier(json): "ruamel.yaml>=0.15", "toml", "semver", - "mercurial>=5.2", - "hg-evolve>=10.0", ], python_requires=">=3.6", author="Project Jupyter Contributors", From 5bb586931b40cea181be8302f931a0d74a2b1d03 Mon Sep 17 00:00:00 2001 From: paugier Date: Thu, 10 Sep 2020 07:58:21 +0200 Subject: [PATCH 09/13] Mercurial optional --- repo2docker/contentproviders/mercurial.py | 46 +++++++++++++- tests/unit/contentproviders/test_mercurial.py | 63 ++++++++++++++++++- 2 files changed, 105 insertions(+), 4 deletions(-) diff --git a/repo2docker/contentproviders/mercurial.py b/repo2docker/contentproviders/mercurial.py index 2b33d23f0..3164b22e0 100644 --- a/repo2docker/contentproviders/mercurial.py +++ b/repo2docker/contentproviders/mercurial.py @@ -1,8 +1,39 @@ import subprocess +import os +from distutils.util import strtobool from .base import ContentProvider, ContentProviderException from ..utils import execute_cmd +HG_EVOLVE_REQUIRED = strtobool( + os.environ.get("REPO2DOCKER_HG_EVOLVE_REQUIRED", "False") +) + +if HG_EVOLVE_REQUIRED: + if "REPO2DOCKER_HG_REQUIRED" in os.environ: + HG_REQUIRED = strtobool(os.environ["REPO2DOCKER_HG_REQUIRED"]) + if not HG_REQUIRED: + raise ValueError( + "Incompatible values for environment variables " + "REPO2DOCKER_HG_EVOLVE_REQUIRED=1 and REPO2DOCKER_HG_REQUIRED=0" + ) + else: + HG_REQUIRED = True +else: + HG_REQUIRED = strtobool(os.environ.get("REPO2DOCKER_HG_REQUIRED", "False")) + + +def is_mercurial_available(): + try: + subprocess.check_output(["hg", "version"]) + except subprocess.CalledProcessError: + return False + return True + + +if HG_REQUIRED and not is_mercurial_available(): + raise RuntimeError("REPO2DOCKER_HG_REQUIRED but the command `hg` is not available") + class Mercurial(ContentProvider): """Provide contents of a remote Mercurial repository.""" @@ -16,6 +47,8 @@ def detect(self, source, ref=None, extra_args=None): stderr=subprocess.DEVNULL, ) except subprocess.CalledProcessError: + # warning: if hg is not installed and `not HG_REQUIRED`, + # we return None even for a hg repo return None return {"repo": source, "ref": ref} @@ -26,7 +59,14 @@ def fetch(self, spec, output_dir, yield_output=False): # make a clone of the remote repository try: - cmd = ["hg", "clone", repo, output_dir] + cmd = [ + "hg", + "clone", + repo, + output_dir, + "--config", + "phases.publish=False", + ] if ref is not None: # don't update so the clone will include an empty working # directory, the given ref will be updated out later @@ -35,9 +75,9 @@ def fetch(self, spec, output_dir, yield_output=False): yield line except subprocess.CalledProcessError as error: - msg = "Failed to clone repository from {repo}".format(repo=repo) + msg = f"Failed to clone repository from {repo}" if ref is not None: - msg += " (ref {ref})".format(ref=ref) + msg += f" (ref {ref})" msg += "." raise ContentProviderException(msg) from error diff --git a/tests/unit/contentproviders/test_mercurial.py b/tests/unit/contentproviders/test_mercurial.py index 6b4f91006..ee82455f0 100644 --- a/tests/unit/contentproviders/test_mercurial.py +++ b/tests/unit/contentproviders/test_mercurial.py @@ -5,6 +5,29 @@ import pytest from repo2docker.contentproviders import Mercurial +from repo2docker.contentproviders.mercurial import ( + HG_REQUIRED, + HG_EVOLVE_REQUIRED, + is_mercurial_available, +) + +skip_if_no_hg = pytest.mark.skipif( + not HG_REQUIRED and not is_mercurial_available(), + reason="not HG_REQUIRED and Mercurial not available", +) + + +def is_evolve_available(): + if not is_mercurial_available(): + return False + output = subprocess.getoutput("hg version -v") + return " evolve " in output + + +EVOLVE_AVAILABLE = is_evolve_available() + +if HG_EVOLVE_REQUIRED and not EVOLVE_AVAILABLE: + raise RuntimeError("HG_EVOLVE_REQUIRED and not EVOLVE_AVAILABLE") def _add_content_to_hg(repo_dir): @@ -16,6 +39,14 @@ def _add_content_to_hg(repo_dir): subprocess.check_call(["hg", "add", "test"], cwd=repo_dir) subprocess.check_call(["hg", "commit", "-m", "Test commit"], cwd=repo_dir) + if EVOLVE_AVAILABLE: + subprocess.check_call(["hg", "topic", "test-topic"], cwd=repo_dir) + subprocess.check_call( + ["hg", "commit", "-m", "Test commit in topic test-topic"], + cwd=repo_dir, + ) + subprocess.check_call(["hg", "up", "default"], cwd=repo_dir) + def _get_node_id(repo_dir): """Get repository's current commit node ID (currently SHA1).""" @@ -46,6 +77,7 @@ def hg_repo_with_content(hg_repo): yield hg_repo, node_id +@skip_if_no_hg def test_detect_mercurial(hg_repo_with_content, repo_with_content): mercurial = Mercurial() assert mercurial.detect("this-is-not-a-directory") is None @@ -58,6 +90,7 @@ def test_detect_mercurial(hg_repo_with_content, repo_with_content): assert mercurial.detect(hg_repo) == {"repo": hg_repo, "ref": None} +@skip_if_no_hg def test_clone(hg_repo_with_content): """Test simple hg clone to a target dir""" upstream, node_id = hg_repo_with_content @@ -72,9 +105,10 @@ def test_clone(hg_repo_with_content): assert mercurial.content_id == node_id +@skip_if_no_hg def test_bad_ref(hg_repo_with_content): """ - Test trying to checkout a ref that doesn't exist + Test trying to update to a ref that doesn't exist """ upstream, node_id = hg_repo_with_content with TemporaryDirectory() as clone_dir: @@ -82,3 +116,30 @@ def test_bad_ref(hg_repo_with_content): with pytest.raises(ValueError): for _ in Mercurial().fetch(spec, clone_dir): pass + + +@pytest.mark.skipif( + not HG_EVOLVE_REQUIRED and not EVOLVE_AVAILABLE, + reason="not HG_EVOLVE_REQUIRED and hg-evolve not available", +) +@skip_if_no_hg +def test_ref_topic(hg_repo_with_content): + """ + Test trying to update to a topic + """ + upstream, node_id = hg_repo_with_content + node_id = subprocess.Popen( + ["hg", "identify", "-i", "-r", "topic(test-topic)"], + stdout=subprocess.PIPE, + cwd=upstream, + ) + node_id = node_id.stdout.read().decode().strip() + + with TemporaryDirectory() as clone_dir: + spec = {"repo": upstream, "ref": "test-topic"} + mercurial = Mercurial() + for _ in mercurial.fetch(spec, clone_dir): + pass + assert (Path(clone_dir) / "test").exists() + + assert mercurial.content_id == node_id From 3cdde89328aadddc859b64130ea4c1f4cac337cb Mon Sep 17 00:00:00 2001 From: paugier Date: Thu, 10 Sep 2020 21:48:46 +0200 Subject: [PATCH 10/13] By default run Mercurial tests + enable the topic extension from code (no need for config file) --- .github/workflows/test.yml | 1 + Dockerfile | 3 +- repo2docker/contentproviders/mercurial.py | 42 ++--------- tests/unit/contentproviders/test_mercurial.py | 70 +++++++++++-------- 4 files changed, 47 insertions(+), 69 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ba1a80003..973225236 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -106,6 +106,7 @@ jobs: python setup.py bdist_wheel pip install dist/*.whl pip freeze + pip install mercurial hg-evolve - name: "Run tests" run: | diff --git a/Dockerfile b/Dockerfile index 023d148b9..54f5a24e3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -18,9 +18,8 @@ FROM alpine:${ALPINE_VERSION} # install python, git, bash, mercurial RUN apk add --no-cache git git-lfs python3 py-pip bash docker mercurial -# install and activate the evolve and topic Mercurial extensions +# install hg-evolve (Mercurial extensions) RUN pip3 install hg-evolve --user --no-cache-dir -RUN mkdir -p /etc/mercurial/hgrc.d && echo -e "[extensions]\nevolve =\ntopic =\n" > /etc/mercurial/hgrc.d/evolve.rc # install repo2docker COPY --from=0 /tmp/wheelhouse /tmp/wheelhouse diff --git a/repo2docker/contentproviders/mercurial.py b/repo2docker/contentproviders/mercurial.py index 3164b22e0..168682190 100644 --- a/repo2docker/contentproviders/mercurial.py +++ b/repo2docker/contentproviders/mercurial.py @@ -1,38 +1,9 @@ import subprocess -import os -from distutils.util import strtobool from .base import ContentProvider, ContentProviderException from ..utils import execute_cmd -HG_EVOLVE_REQUIRED = strtobool( - os.environ.get("REPO2DOCKER_HG_EVOLVE_REQUIRED", "False") -) - -if HG_EVOLVE_REQUIRED: - if "REPO2DOCKER_HG_REQUIRED" in os.environ: - HG_REQUIRED = strtobool(os.environ["REPO2DOCKER_HG_REQUIRED"]) - if not HG_REQUIRED: - raise ValueError( - "Incompatible values for environment variables " - "REPO2DOCKER_HG_EVOLVE_REQUIRED=1 and REPO2DOCKER_HG_REQUIRED=0" - ) - else: - HG_REQUIRED = True -else: - HG_REQUIRED = strtobool(os.environ.get("REPO2DOCKER_HG_REQUIRED", "False")) - - -def is_mercurial_available(): - try: - subprocess.check_output(["hg", "version"]) - except subprocess.CalledProcessError: - return False - return True - - -if HG_REQUIRED and not is_mercurial_available(): - raise RuntimeError("REPO2DOCKER_HG_REQUIRED but the command `hg` is not available") +args_enabling_topic = ["--config", "extensions.topic="] class Mercurial(ContentProvider): @@ -43,12 +14,11 @@ def detect(self, source, ref=None, extra_args=None): return None try: subprocess.check_output( - ["hg", "identify", source, "--config", "extensions.hggit=!"], + ["hg", "identify", source, "--config", "extensions.hggit=!"] + + args_enabling_topic, stderr=subprocess.DEVNULL, ) except subprocess.CalledProcessError: - # warning: if hg is not installed and `not HG_REQUIRED`, - # we return None even for a hg repo return None return {"repo": source, "ref": ref} @@ -66,7 +36,7 @@ def fetch(self, spec, output_dir, yield_output=False): output_dir, "--config", "phases.publish=False", - ] + ] + args_enabling_topic if ref is not None: # don't update so the clone will include an empty working # directory, the given ref will be updated out later @@ -85,7 +55,7 @@ def fetch(self, spec, output_dir, yield_output=False): if ref is not None: try: for line in execute_cmd( - ["hg", "update", "--clean", ref], + ["hg", "update", "--clean", ref] + args_enabling_topic, cwd=output_dir, capture=yield_output, ): @@ -96,7 +66,7 @@ def fetch(self, spec, output_dir, yield_output=False): ) raise ValueError("Failed to update to ref {}".format(ref)) - cmd = ["hg", "identify", "-i"] + cmd = ["hg", "identify", "-i"] + args_enabling_topic sha1 = subprocess.Popen(cmd, stdout=subprocess.PIPE, cwd=output_dir) self._node_id = sha1.stdout.read().decode().strip() diff --git a/tests/unit/contentproviders/test_mercurial.py b/tests/unit/contentproviders/test_mercurial.py index ee82455f0..2b1b48f33 100644 --- a/tests/unit/contentproviders/test_mercurial.py +++ b/tests/unit/contentproviders/test_mercurial.py @@ -1,33 +1,42 @@ from pathlib import Path import subprocess from tempfile import TemporaryDirectory +import os +from distutils.util import strtobool import pytest from repo2docker.contentproviders import Mercurial -from repo2docker.contentproviders.mercurial import ( - HG_REQUIRED, - HG_EVOLVE_REQUIRED, - is_mercurial_available, +from repo2docker.contentproviders.mercurial import args_enabling_topic + +SKIP_HG = strtobool(os.environ.get("REPO2DOCKER_SKIP_HG_TESTS", "False")) +SKIP_HG_EVOLVE = SKIP_HG or strtobool( + os.environ.get("REPO2DOCKER_SKIP_HG_EVOLVE_TESTS", "False") ) -skip_if_no_hg = pytest.mark.skipif( - not HG_REQUIRED and not is_mercurial_available(), - reason="not HG_REQUIRED and Mercurial not available", +skip_if_no_hg_tests = pytest.mark.skipif( + SKIP_HG, + reason="REPO2DOCKER_SKIP_HG_TESTS", +) +skip_if_no_evolve_tests = pytest.mark.skipif( + SKIP_HG_EVOLVE, + reason="REPO2DOCKER_SKIP_HG_EVOLVE_TESTS", ) +if SKIP_HG_EVOLVE: + args_enabling_topic = [] -def is_evolve_available(): - if not is_mercurial_available(): - return False - output = subprocess.getoutput("hg version -v") - return " evolve " in output +@skip_if_no_hg_tests +def test_if_mercurial_is_available(): + subprocess.check_output(["hg", "version"]) -EVOLVE_AVAILABLE = is_evolve_available() -if HG_EVOLVE_REQUIRED and not EVOLVE_AVAILABLE: - raise RuntimeError("HG_EVOLVE_REQUIRED and not EVOLVE_AVAILABLE") +@skip_if_no_evolve_tests +def test_if_topic_is_available(): + """Check that the topic extension can be enabled""" + output = subprocess.getoutput("hg version -v --config extensions.topic=") + assert "failed to import extension topic" not in output def _add_content_to_hg(repo_dir): @@ -39,19 +48,22 @@ def _add_content_to_hg(repo_dir): subprocess.check_call(["hg", "add", "test"], cwd=repo_dir) subprocess.check_call(["hg", "commit", "-m", "Test commit"], cwd=repo_dir) - if EVOLVE_AVAILABLE: - subprocess.check_call(["hg", "topic", "test-topic"], cwd=repo_dir) - subprocess.check_call( - ["hg", "commit", "-m", "Test commit in topic test-topic"], - cwd=repo_dir, - ) - subprocess.check_call(["hg", "up", "default"], cwd=repo_dir) + if not SKIP_HG_EVOLVE: + + def check_call(command): + subprocess.check_call(command + args_enabling_topic, cwd=repo_dir) + + check_call(["hg", "topic", "test-topic"]) + check_call(["hg", "commit", "-m", "Test commit in topic test-topic"]) + check_call(["hg", "up", "default"]) def _get_node_id(repo_dir): """Get repository's current commit node ID (currently SHA1).""" node_id = subprocess.Popen( - ["hg", "identify", "-i"], stdout=subprocess.PIPE, cwd=repo_dir + ["hg", "identify", "-i"] + args_enabling_topic, + stdout=subprocess.PIPE, + cwd=repo_dir, ) return node_id.stdout.read().decode().strip() @@ -77,7 +89,7 @@ def hg_repo_with_content(hg_repo): yield hg_repo, node_id -@skip_if_no_hg +@skip_if_no_hg_tests def test_detect_mercurial(hg_repo_with_content, repo_with_content): mercurial = Mercurial() assert mercurial.detect("this-is-not-a-directory") is None @@ -90,7 +102,7 @@ def test_detect_mercurial(hg_repo_with_content, repo_with_content): assert mercurial.detect(hg_repo) == {"repo": hg_repo, "ref": None} -@skip_if_no_hg +@skip_if_no_hg_tests def test_clone(hg_repo_with_content): """Test simple hg clone to a target dir""" upstream, node_id = hg_repo_with_content @@ -105,7 +117,7 @@ def test_clone(hg_repo_with_content): assert mercurial.content_id == node_id -@skip_if_no_hg +@skip_if_no_hg_tests def test_bad_ref(hg_repo_with_content): """ Test trying to update to a ref that doesn't exist @@ -118,11 +130,7 @@ def test_bad_ref(hg_repo_with_content): pass -@pytest.mark.skipif( - not HG_EVOLVE_REQUIRED and not EVOLVE_AVAILABLE, - reason="not HG_EVOLVE_REQUIRED and hg-evolve not available", -) -@skip_if_no_hg +@skip_if_no_evolve_tests def test_ref_topic(hg_repo_with_content): """ Test trying to update to a topic From 64633bbcbca93ad5aef8e38ea999a17f53e35df3 Mon Sep 17 00:00:00 2001 From: paugier Date: Fri, 11 Sep 2020 00:10:55 +0200 Subject: [PATCH 11/13] Documentation about Mercurial support --- docs/source/contributing/tasks.md | 10 +++++++--- docs/source/install.rst | 11 +++++++++++ tests/unit/contentproviders/test_mercurial.py | 9 +++++++++ 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/docs/source/contributing/tasks.md b/docs/source/contributing/tasks.md index 3f6375e0a..0e7f304b3 100644 --- a/docs/source/contributing/tasks.md +++ b/docs/source/contributing/tasks.md @@ -23,11 +23,15 @@ If you want to run a specific test, you can do so with: py.test -s tests/ ``` +To skip the tests related to Mercurial repositories (to avoid to install +Mercurial or hg-evolve), one can use the environment variables +``REPO2DOCKER_SKIP_HG_TESTS`` or ``REPO2DOCKER_SKIP_HG_EVOLVE_TESTS``. + ### Troubleshooting Tests Some of the tests have non-python requirements for your development machine. They are: -- `git-lfs` must be installed ([instructions](https://github.com/git-lfs/git-lfs)). It need not be activated -- there is no need to run the `git lfs install` command. It just needs to be available to the test suite. +- `git-lfs` must be installed ([instructions](https://github.com/git-lfs/git-lfs)). It need not be activated -- there is no need to run the `git lfs install` command. It just needs to be available to the test suite. - If your test failure messages include "`git-lfs filter-process: git-lfs: command not found`", this step should address the problem. - Minimum Docker Image size of 128GB is required. If you are not running docker on a linux OS, you may need to expand the runtime image size for your installation. See Docker's instructions for [macOS](https://docs.docker.com/docker-for-mac/space/) or [Windows 10](https://docs.docker.com/docker-for-windows/#resources) for more information. @@ -218,7 +222,7 @@ files accordingly. ## Compare generated Dockerfiles between repo2docker versions For larger refactorings it can be useful to check that the generated Dockerfiles match -between an older version of r2d and the current version. The following shell script +between an older version of r2d and the current version. The following shell script automates this test. ```bash @@ -231,7 +235,7 @@ basename="dockerfilediff" diff_r2d_dockerfiles_with_version () { docker run --rm -t -v "$(pwd)":"$(pwd)" --user 1000 jupyterhub/repo2docker:"$1" jupyter-repo2docker --no-build --debug "$(pwd)" &> "$basename"."$1" jupyter-repo2docker --no-build --debug "$(pwd)" &> "$basename"."$current_version" - + # remove first line logging the path sed -i '/^\[Repo2Docker\]/d' "$basename"."$1" sed -i '/^\[Repo2Docker\]/d' "$basename"."$current_version" diff --git a/docs/source/install.rst b/docs/source/install.rst index 48b31a50c..615a7ce7a 100644 --- a/docs/source/install.rst +++ b/docs/source/install.rst @@ -22,6 +22,17 @@ The `BinderHub `_ helm chart uses version `helm chart `_ for more details. +Optional: Mercurial +------------------- + +For `Mercurial `_ repositories, `Mercurial needs +to be installed `_. For support of +`Mercurial topics +`_, +also install `hg-evolve `_ which +provides the topic extension (however, no need to explicitly enable it in a +Mercurial configuration file). + Installing with ``pip`` ----------------------- diff --git a/tests/unit/contentproviders/test_mercurial.py b/tests/unit/contentproviders/test_mercurial.py index 2b1b48f33..6cbc1dc8d 100644 --- a/tests/unit/contentproviders/test_mercurial.py +++ b/tests/unit/contentproviders/test_mercurial.py @@ -29,6 +29,11 @@ @skip_if_no_hg_tests def test_if_mercurial_is_available(): + """ + To skip the tests related to Mercurial repositories (to avoid to install + Mercurial), one can use the environment variable + REPO2DOCKER_SKIP_HG_TESTS. + """ subprocess.check_output(["hg", "version"]) @@ -134,6 +139,10 @@ def test_bad_ref(hg_repo_with_content): def test_ref_topic(hg_repo_with_content): """ Test trying to update to a topic + + To skip this test (to avoid to install hg-evolve), one can use the + environment variable REPO2DOCKER_SKIP_HG_EVOLVE_TESTS. + """ upstream, node_id = hg_repo_with_content node_id = subprocess.Popen( From 39081b70c39dd9b4c91fb28cd3c8cd642551d27e Mon Sep 17 00:00:00 2001 From: paugier Date: Fri, 11 Sep 2020 00:36:28 +0200 Subject: [PATCH 12/13] Fix bug hg id topic --- tests/unit/contentproviders/test_mercurial.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/contentproviders/test_mercurial.py b/tests/unit/contentproviders/test_mercurial.py index 6cbc1dc8d..af3b7fd46 100644 --- a/tests/unit/contentproviders/test_mercurial.py +++ b/tests/unit/contentproviders/test_mercurial.py @@ -146,7 +146,7 @@ def test_ref_topic(hg_repo_with_content): """ upstream, node_id = hg_repo_with_content node_id = subprocess.Popen( - ["hg", "identify", "-i", "-r", "topic(test-topic)"], + ["hg", "identify", "-i", "-r", "topic(test-topic)"] + args_enabling_topic, stdout=subprocess.PIPE, cwd=upstream, ) From 05002a4177371ec4662eef9f1d39b29f9d047b26 Mon Sep 17 00:00:00 2001 From: paugier Date: Mon, 14 Sep 2020 14:05:52 +0200 Subject: [PATCH 13/13] hg-evolve required for Mercurial support (simpler) --- .github/workflows/test.yml | 4 +- docs/source/contributing/tasks.md | 4 +- docs/source/install.rst | 20 ++++++---- tests/unit/contentproviders/test_mercurial.py | 37 ++++++------------- 4 files changed, 30 insertions(+), 35 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 973225236..385d82d0f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -106,7 +106,9 @@ jobs: python setup.py bdist_wheel pip install dist/*.whl pip freeze - pip install mercurial hg-evolve + # hg-evolve pinned to 9.2 because hg-evolve dropped support for + # hg 4.5, installed with apt in Ubuntu 18.04 + $(hg debuginstall --template "{pythonexe}") -m pip install hg-evolve==9.2 --user - name: "Run tests" run: | diff --git a/docs/source/contributing/tasks.md b/docs/source/contributing/tasks.md index 0e7f304b3..a1f6a34d0 100644 --- a/docs/source/contributing/tasks.md +++ b/docs/source/contributing/tasks.md @@ -24,8 +24,8 @@ py.test -s tests/ ``` To skip the tests related to Mercurial repositories (to avoid to install -Mercurial or hg-evolve), one can use the environment variables -``REPO2DOCKER_SKIP_HG_TESTS`` or ``REPO2DOCKER_SKIP_HG_EVOLVE_TESTS``. +Mercurial and hg-evolve), one can use the environment variable +``REPO2DOCKER_SKIP_HG_TESTS``. ### Troubleshooting Tests diff --git a/docs/source/install.rst b/docs/source/install.rst index 615a7ce7a..09aff8f21 100644 --- a/docs/source/install.rst +++ b/docs/source/install.rst @@ -25,13 +25,19 @@ for more details. Optional: Mercurial ------------------- -For `Mercurial `_ repositories, `Mercurial needs -to be installed `_. For support of -`Mercurial topics -`_, -also install `hg-evolve `_ which -provides the topic extension (however, no need to explicitly enable it in a -Mercurial configuration file). +For `Mercurial `_ repositories, Mercurial and +`hg-evolve `_ need to be +installed. For example, on Debian based distributions, one can do:: + + sudo apt install mercurial + $(hg debuginstall --template "{pythonexe}") -m pip install hg-evolve --user + +To install Mercurial on other systems, see `here +`_. + +Note that for old Mercurial versions, you may need to specify a version for +hg-evolve. For example, ``hg-evolve==9.2`` for hg 4.5 (which is installed with +`apt` on Ubuntu 18.4). Installing with ``pip`` ----------------------- diff --git a/tests/unit/contentproviders/test_mercurial.py b/tests/unit/contentproviders/test_mercurial.py index af3b7fd46..25257bf39 100644 --- a/tests/unit/contentproviders/test_mercurial.py +++ b/tests/unit/contentproviders/test_mercurial.py @@ -10,34 +10,24 @@ from repo2docker.contentproviders.mercurial import args_enabling_topic SKIP_HG = strtobool(os.environ.get("REPO2DOCKER_SKIP_HG_TESTS", "False")) -SKIP_HG_EVOLVE = SKIP_HG or strtobool( - os.environ.get("REPO2DOCKER_SKIP_HG_EVOLVE_TESTS", "False") -) skip_if_no_hg_tests = pytest.mark.skipif( SKIP_HG, reason="REPO2DOCKER_SKIP_HG_TESTS", ) -skip_if_no_evolve_tests = pytest.mark.skipif( - SKIP_HG_EVOLVE, - reason="REPO2DOCKER_SKIP_HG_EVOLVE_TESTS", -) - -if SKIP_HG_EVOLVE: - args_enabling_topic = [] @skip_if_no_hg_tests def test_if_mercurial_is_available(): """ To skip the tests related to Mercurial repositories (to avoid to install - Mercurial), one can use the environment variable + Mercurial and hg-evolve), one can use the environment variable REPO2DOCKER_SKIP_HG_TESTS. """ subprocess.check_output(["hg", "version"]) -@skip_if_no_evolve_tests +@skip_if_no_hg_tests def test_if_topic_is_available(): """Check that the topic extension can be enabled""" output = subprocess.getoutput("hg version -v --config extensions.topic=") @@ -50,17 +40,14 @@ def _add_content_to_hg(repo_dir): with open(Path(repo_dir) / "test", "a") as f: f.write("Hello") - subprocess.check_call(["hg", "add", "test"], cwd=repo_dir) - subprocess.check_call(["hg", "commit", "-m", "Test commit"], cwd=repo_dir) + def check_call(command): + subprocess.check_call(command + args_enabling_topic, cwd=repo_dir) - if not SKIP_HG_EVOLVE: - - def check_call(command): - subprocess.check_call(command + args_enabling_topic, cwd=repo_dir) - - check_call(["hg", "topic", "test-topic"]) - check_call(["hg", "commit", "-m", "Test commit in topic test-topic"]) - check_call(["hg", "up", "default"]) + check_call(["hg", "add", "test"]) + check_call(["hg", "commit", "-m", "Test commit"]) + check_call(["hg", "topic", "test-topic"]) + check_call(["hg", "commit", "-m", "Test commit in topic test-topic"]) + check_call(["hg", "up", "default"]) def _get_node_id(repo_dir): @@ -135,13 +122,13 @@ def test_bad_ref(hg_repo_with_content): pass -@skip_if_no_evolve_tests +@skip_if_no_hg_tests def test_ref_topic(hg_repo_with_content): """ Test trying to update to a topic - To skip this test (to avoid to install hg-evolve), one can use the - environment variable REPO2DOCKER_SKIP_HG_EVOLVE_TESTS. + To skip this test (to avoid to install Mercurial and hg-evolve), one can + use the environment variable REPO2DOCKER_SKIP_HG_TESTS. """ upstream, node_id = hg_repo_with_content