Repository: iterative/dvc

Issue:
check-ignore: should ignore subrepos
Subrepos are a part of dvcignore now (e.g. https://github.com/iterative/dvc/blob/7fa90e425d1c3f2b1771b541ccca4ac788d1abf9/dvc/ignore.py#L296 ) so this test https://github.com/iterative/dvc/blob/7fa90e425d1c3f2b1771b541ccca4ac788d1abf9/tests/func/test_check_ignore.py#L91 should be backwards.

Discussion:

Patch:
diff --git a/dvc/cache/__init__.py b/dvc/cache/__init__.py
index 1cb0fc994..c4a742a5a 100644
--- a/dvc/cache/__init__.py
+++ b/dvc/cache/__init__.py
@@ -63,7 +63,12 @@ class Cache:
         if local:
             settings = {"name": local}
         else:
-            settings = {**config, "url": config["dir"]}
+            from ..config import LOCAL_COMMON
+
+            settings = {"url": config["dir"]}
+            for opt in LOCAL_COMMON.keys():
+                if opt in config:
+                    settings[str(opt)] = config.get(opt)
 
         tree = get_cloud_tree(repo, **settings)
         self.local = LocalCache(tree)
diff --git a/dvc/command/version.py b/dvc/command/version.py
index aa37106c0..3396e3443 100644
--- a/dvc/command/version.py
+++ b/dvc/command/version.py
@@ -1,153 +1,18 @@
 import argparse
-import itertools
 import logging
-import os
-import pathlib
-import platform
-import uuid
 
 from dvc.command.base import CmdBaseNoRepo, append_doc_link
-from dvc.exceptions import DvcException, NotDvcRepoError
-from dvc.scm.base import SCMError
-from dvc.system import System
-from dvc.utils import error_link
-from dvc.utils.pkg import PKG
-from dvc.version import __version__
-
-try:
-    import psutil
-except ImportError:
-    psutil = None
-
+from dvc.info import get_dvc_info
 
 logger = logging.getLogger(__name__)
 
 
 class CmdVersion(CmdBaseNoRepo):
     def run(self):
-        from dvc.repo import Repo
-
-        package = PKG
-        if PKG is None:
-            package = ""
-        else:
-            package = f"({PKG})"
-
-        info = [
-            f"DVC version: {__version__} {package}",
-            "---------------------------------",
-            f"Platform: Python {platform.python_version()} on "
-            f"{platform.platform()}",
-            f"Supports: {self.get_supported_remotes()}",
-        ]
-
-        try:
-            repo = Repo()
-            root_directory = repo.root_dir
-
-            # cache_dir might not exist yet (e.g. after `dvc init`), and we
-            # can't auto-create it, as it might cause issues if the user
-            # later decides to enable shared cache mode with
-            # `dvc config cache.shared group`.
-            if os.path.exists(repo.cache.local.cache_dir):
-                info.append(
-                    "Cache types: {}".format(
-                        self.get_linktype_support_info(repo)
-                    )
-                )
-                if psutil:
-                    fs_type = self.get_fs_type(repo.cache.local.cache_dir)
-                    info.append(f"Cache directory: {fs_type}")
-            else:
-                info.append("Cache types: " + error_link("no-dvc-cache"))
-
-        except NotDvcRepoError:
-            root_directory = os.getcwd()
-        except SCMError:
-            root_directory = os.getcwd()
-            info.append("Repo: dvc, git (broken)")
-        else:
-            if psutil:
-                fs_root = self.get_fs_type(os.path.abspath(root_directory))
-                info.append(f"Workspace directory: {fs_root}")
-
-            info.append("Repo: {}".format(_get_dvc_repo_info(repo)))
-
-        logger.info("\n".join(info))
+        dvc_info = get_dvc_info()
+        logger.info(dvc_info)
         return 0
 
-    @staticmethod
-    def get_fs_type(path):
-        partition = {
-            pathlib.Path(part.mountpoint): (part.fstype + " on " + part.device)
-            for part in psutil.disk_partitions(all=True)
-        }
-
-        path = pathlib.Path(path)
-
-        for parent in itertools.chain([path], path.parents):
-            if parent in partition:
-                return partition[parent]
-        return ("unknown", "none")
-
-    @staticmethod
-    def get_linktype_support_info(repo):
-        links = {
-            "reflink": (System.reflink, None),
-            "hardlink": (System.hardlink, System.is_hardlink),
-            "symlink": (System.symlink, System.is_symlink),
-        }
-
-        fname = "." + str(uuid.uuid4())
-        src = os.path.join(repo.cache.local.cache_dir, fname)
-        open(src, "w").close()
-        dst = os.path.join(repo.root_dir, fname)
-
-        cache = []
-
-        for name, (link, is_link) in links.items():
-            try:
-                link(src, dst)
-                status = "supported"
-                if is_link and not is_link(dst):
-                    status = "broken"
-                os.unlink(dst)
-            except DvcException:
-                status = "not supported"
-
-            if status == "supported":
-                cache.append(name)
-        os.remove(src)
-
-        return ", ".join(cache)
-
-    @staticmethod
-    def get_supported_remotes():
-        from dvc.tree import TREES
-
-        supported_remotes = []
-        for tree_cls in TREES:
-            if not tree_cls.get_missing_deps():
-                supported_remotes.append(tree_cls.scheme)
-
-        if len(supported_remotes) == len(TREES):
-            return "All remotes"
-
-        if len(supported_remotes) == 1:
-            return supported_remotes
-
-        return ", ".join(supported_remotes)
-
-
-def _get_dvc_repo_info(repo):
-    if repo.config.get("core", {}).get("no_scm", False):
-        return "dvc (no_scm)"
-
-    if repo.root_dir != repo.scm.root_dir:
-        return "dvc (subdir), git"
-
-    return "dvc, git"
-
 
 def add_parser(subparsers, parent_parser):
     VERSION_HELP = (
diff --git a/dvc/ignore.py b/dvc/ignore.py
index ff3259ff4..301e66691 100644
--- a/dvc/ignore.py
+++ b/dvc/ignore.py
@@ -233,7 +233,10 @@ class DvcIgnoreFilter:
                 self._ignored_subrepos[root] = self._ignored_subrepos.get(
                     root, set()
                 ) | {d}
-                new_pattern = DvcIgnorePatterns([f"/{d}/"], root)
+                pattern_info = PatternInfo(
+                    f"/{d}/", "in sub_repo:{}".format(d)
+                )
+                new_pattern = DvcIgnorePatterns([pattern_info], root)
                 old_pattern = self.ignores_trie_tree.longest_prefix(root).value
                 if old_pattern:
                     self.ignores_trie_tree[root] = DvcIgnorePatterns(
diff --git a/dvc/info.py b/dvc/info.py
new file mode 100644
index 000000000..188d42250
--- /dev/null
+++ b/dvc/info.py
@@ -0,0 +1,136 @@
+import itertools
+import os
+import pathlib
+import platform
+import uuid
+
+from dvc.exceptions import DvcException, NotDvcRepoError
+from dvc.repo import Repo
+from dvc.scm.base import SCMError
+from dvc.system import System
+from dvc.tree import TREES
+from dvc.utils import error_link
+from dvc.utils.pkg import PKG
+from dvc.version import __version__
+
+try:
+    import psutil
+except ImportError:
+    psutil = None
+
+if PKG is None:
+    package = ""
+else:
+    package = f"({PKG})"
+
+
+def get_dvc_info():
+    info = [
+        f"DVC version: {__version__} {package}",
+        "---------------------------------",
+        f"Platform: Python {platform.python_version()} on "
+        f"{platform.platform()}",
+        f"Supports: {_get_supported_remotes()}",
+    ]
+
+    try:
+        repo = Repo()
+
+        # cache_dir might not exist yet (e.g. after `dvc init`), and we
+        # can't auto-create it, as it might cause issues if the user
+        # later decides to enable shared cache mode with
+        # `dvc config cache.shared group`.
+        if os.path.exists(repo.cache.local.cache_dir):
+            info.append(
+                "Cache types: {}".format(_get_linktype_support_info(repo))
+            )
+            if psutil:
+                fs_type = get_fs_type(repo.cache.local.cache_dir)
+                info.append(f"Cache directory: {fs_type}")
+        else:
+            info.append("Cache types: " + error_link("no-dvc-cache"))
+
+    except NotDvcRepoError:
+        pass
+    except SCMError:
+        info.append("Repo: dvc, git (broken)")
+    else:
+        root_directory = repo.root_dir
+        if psutil:
+            fs_root = get_fs_type(os.path.abspath(root_directory))
+            info.append(f"Workspace directory: {fs_root}")
+        info.append("Repo: {}".format(_get_dvc_repo_info(repo)))
+    return "\n".join(info)
+
+
+def _get_linktype_support_info(repo):
+
+    links = {
+        "reflink": (System.reflink, None),
+        "hardlink": (System.hardlink, System.is_hardlink),
+        "symlink": (System.symlink, System.is_symlink),
+    }
+
+    fname = "." + str(uuid.uuid4())
+    src = os.path.join(repo.cache.local.cache_dir, fname)
+    open(src, "w").close()
+    dst = os.path.join(repo.root_dir, fname)
+
+    cache = []
+
+    for name, (link, is_link) in links.items():
+        try:
+            link(src, dst)
+            status = "supported"
+            if is_link and not is_link(dst):
+                status = "broken"
+            os.unlink(dst)
+        except DvcException:
+            status = "not supported"
+
+        if status == "supported":
+            cache.append(name)
+    os.remove(src)
+
+    return ", ".join(cache)
+
+
+def _get_supported_remotes():
+
+    supported_remotes = []
+    for tree_cls in TREES:
+        if not tree_cls.get_missing_deps():
+            supported_remotes.append(tree_cls.scheme)
+
+    if len(supported_remotes) == len(TREES):
+        return "All remotes"
+
+    if len(supported_remotes) == 1:
+        return supported_remotes
+
+    return ", ".join(supported_remotes)
+
+
+def get_fs_type(path):
+
+    partition = {
+        pathlib.Path(part.mountpoint): (part.fstype + " on " + part.device)
+        for part in psutil.disk_partitions(all=True)
+    }
+
+    path = pathlib.Path(path)
+
+    for parent in itertools.chain([path], path.parents):
+        if parent in partition:
+            return partition[parent]
+    return ("unknown", "none")
+
+
+def _get_dvc_repo_info(self):
+    if self.config.get("core", {}).get("no_scm", False):
+        return "dvc (no_scm)"
+
+    if self.root_dir != self.scm.root_dir:
+        return "dvc (subdir), git"
+
+    return "dvc, git"
diff --git a/dvc/main.py b/dvc/main.py
index b74488afb..4bf803005 100644
--- a/dvc/main.py
+++ b/dvc/main.py
@@ -98,8 +98,12 @@ def main(argv=None):  # noqa: C901
                 extra={"tb_only": True},
             )
         else:
+            from dvc.info import get_dvc_info
+
             logger.exception("unexpected error")
             logger.info(FOOTER)
+            dvc_info = get_dvc_info()
+            logger.info(dvc_info)
         ret = 255
 
     try:
diff --git a/dvc/tree/__init__.py b/dvc/tree/__init__.py
index b9a38325c..cbd1595a6 100644
--- a/dvc/tree/__init__.py
+++ b/dvc/tree/__init__.py
@@ -43,10 +43,10 @@ def _get_conf(repo, **kwargs):
         remote_conf = repo.config["remote"][name.lower()]
     else:
         remote_conf = kwargs
-    return _resolve_remote_refs(repo.config, remote_conf)
+    return _resolve_remote_refs(repo, remote_conf)
 
 
-def _resolve_remote_refs(config, remote_conf):
+def _resolve_remote_refs(repo, remote_conf):
     # Support for cross referenced remotes.
     # This will merge the settings, shadowing base ref with remote_conf.
     # For example, having:
@@ -72,11 +72,17 @@ def _resolve_remote_refs(config, remote_conf):
     if parsed.scheme != "remote":
         return remote_conf
 
-    base = config["remote"][parsed.netloc]
+    base = _get_conf(repo, name=parsed.netloc)
     url = posixpath.join(base["url"], parsed.path.lstrip("/"))
     return {**base, **remote_conf, "url": url}
 
 
 def get_cloud_tree(repo, **kwargs):
+    from dvc.config import SCHEMA, ConfigError, Invalid
+
     remote_conf = _get_conf(repo, **kwargs)
+    try:
+        remote_conf = SCHEMA["remote"][str](remote_conf)
+    except Invalid as exc:
+        raise ConfigError(str(exc)) from None
     return _get_tree(remote_conf)(repo, remote_conf)
diff --git a/dvc/tree/base.py b/dvc/tree/base.py
index ef4ad89fd..466bb0ecf 100644
--- a/dvc/tree/base.py
+++ b/dvc/tree/base.py
@@ -75,8 +75,8 @@ class BaseTree:
     @cached_property
     def hash_jobs(self):
         return (
-            self.config.get("hash_jobs")
-            or (self.repo and self.repo.config["core"].get("hash_jobs"))
+            self.config.get("checksum_jobs")
+            or (self.repo and self.repo.config["core"].get("checksum_jobs"))
             or self.HASH_JOBS
         )
 
diff --git a/dvc/version.py b/dvc/version.py
index 982c10e9e..7f5549a77 100644
--- a/dvc/version.py
+++ b/dvc/version.py
@@ -6,7 +6,7 @@
 import os
 import subprocess
 
-_BASE_VERSION = "1.6.6"
+_BASE_VERSION = "1.7.1"
 
 
 def _generate_version(base_version):


Test patch:
diff --git a/tests/func/test_check_ignore.py b/tests/func/test_check_ignore.py
index e9750f436..dd974fc4f 100644
--- a/tests/func/test_check_ignore.py
+++ b/tests/func/test_check_ignore.py
@@ -83,12 +83,16 @@ def test_check_ignore_out_side_repo(tmp_dir, dvc):
     assert main(["check-ignore", "-q", "../file"]) == 1
 
 
-def test_check_ignore_sub_repo(tmp_dir, dvc):
+def test_check_ignore_sub_repo(tmp_dir, dvc, caplog):
     tmp_dir.gen(
         {DvcIgnore.DVCIGNORE_FILE: "other", "dir": {".dvc": {}, "foo": "bar"}}
     )
 
-    assert main(["check-ignore", "-q", os.path.join("dir", "foo")]) == 1
+    assert main(["check-ignore", "-d", os.path.join("dir", "foo")]) == 0
+    assert (
+        "in sub_repo:{}\t{}".format("dir", os.path.join("dir", "foo"),)
+        in caplog.text
+    )
 
 
 def test_check_sub_dir_ignore_file(tmp_dir, dvc, caplog):
diff --git a/tests/func/test_version.py b/tests/func/test_version.py
index 4c2ad5caa..ebeeaafc5 100644
--- a/tests/func/test_version.py
+++ b/tests/func/test_version.py
@@ -1,72 +1,13 @@
-import os
 import re
-import shutil
 
-import pytest
-
-from dvc.command.version import psutil
 from dvc.main import main
 
 
-@pytest.mark.parametrize("scm_init", [True, False])
-def test_info_in_repo(scm_init, tmp_dir, caplog):
-    tmp_dir.init(scm=scm_init, dvc=True)
-    # Create `.dvc/cache`, that is needed to check supported link types.
-    os.mkdir(tmp_dir.dvc.cache.local.cache_dir)
-
+def test_(tmp_dir, dvc, scm, caplog):
     assert main(["version"]) == 0
 
     assert re.search(r"DVC version: \d+\.\d+\.\d+.*", caplog.text)
     assert re.search(r"Platform: Python \d\.\d+\.\d+ on .*", caplog.text)
     assert re.search(r"Supports: .*", caplog.text)
     assert re.search(r"Cache types: .*", caplog.text)
-
-    if scm_init:
-        assert "Repo: dvc, git" in caplog.text
-    else:
-        assert "Repo: dvc (no_scm)" in caplog.text
-
-
-def test_info_in_subdir(tmp_dir, scm, caplog):
-    dvc_subdir = tmp_dir / "subdir"
-    dvc_subdir.mkdir()
-
-    with dvc_subdir.chdir():
-        dvc_subdir.init(scm=False, dvc=True)
-        with dvc_subdir.dvc.config.edit() as conf:
-            del conf["core"]["no_scm"]
-
-        assert main(["version"]) == 0
-
-    assert "Repo: dvc (subdir), git" in caplog.text
-
-
-def test_info_in_broken_git_repo(tmp_dir, dvc, scm, caplog):
-    shutil.rmtree(dvc.scm.dir)
-    assert main(["version"]) == 0
-
-    assert "Repo: dvc, git (broken)" in caplog.text
-
-
-@pytest.mark.skipif(psutil is None, reason="No psutil.")
-def test_fs_info_in_repo(tmp_dir, dvc, caplog):
-    os.mkdir(dvc.cache.local.cache_dir)
-    assert main(["version"]) == 0
-
-    assert re.search(r"Cache directory: .* on .*", caplog.text)
-    assert re.search(r"Workspace directory: .* on .*", caplog.text)
-
-
-def test_info_outside_of_repo(tmp_dir, caplog):
-    assert main(["version"]) == 0
-
-    assert re.search(r"DVC version: \d+\.\d+\.\d+.*", caplog.text)
-    assert re.search(r"Platform: Python \d\.\d+\.\d+ on .*", caplog.text)
-    assert re.search(r"Supports: .*", caplog.text)
-    assert not re.search(r"Cache types: .*", caplog.text)
-    assert "Repo:" not in caplog.text
-
-
-@pytest.mark.skipif(psutil is None, reason="No psutil.")
-def test_fs_info_outside_of_repo(tmp_dir, caplog):
-    assert main(["version"]) == 0
+    assert "Repo: dvc, git" in caplog.text
diff --git a/tests/unit/remote/ssh/test_connection.py b/tests/unit/remote/ssh/test_connection.py
index 10499a231..a84a22924 100644
--- a/tests/unit/remote/ssh/test_connection.py
+++ b/tests/unit/remote/ssh/test_connection.py
@@ -6,7 +6,7 @@ import tempfile
 
 import pytest
 
-from dvc.command.version import CmdVersion
+from dvc.info import get_fs_type
 from dvc.system import System
 
 here = os.path.abspath(os.path.dirname(__file__))
@@ -85,8 +85,7 @@ def test_walk(tmp_path, ssh_connection):
 
 
 @pytest.mark.skipif(
-    CmdVersion.get_fs_type(tempfile.gettempdir())[0]
-    not in ["xfs", "apfs", "btrfs"],
+    get_fs_type(tempfile.gettempdir())[0] not in ["xfs", "apfs", "btrfs"],
     reason="Reflinks only work in specified file systems",
 )
 def test_reflink(tmp_dir, ssh_connection):
diff --git a/tests/unit/remote/test_remote.py b/tests/unit/remote/test_remote.py
index f7ea0c3ce..3769fb2c3 100644
--- a/tests/unit/remote/test_remote.py
+++ b/tests/unit/remote/test_remote.py
@@ -8,9 +8,9 @@ from dvc.tree.s3 import S3Tree
 def test_remote_with_hash_jobs(dvc):
     dvc.config["remote"]["with_hash_jobs"] = {
         "url": "s3://bucket/name",
-        "hash_jobs": 100,
+        "checksum_jobs": 100,
     }
-    dvc.config["core"]["hash_jobs"] = 200
+    dvc.config["core"]["checksum_jobs"] = 200
 
     tree = get_cloud_tree(dvc, name="with_hash_jobs")
     assert tree.hash_jobs == 100
@@ -18,7 +18,7 @@ def test_remote_with_hash_jobs(dvc):
 
 def test_remote_without_hash_jobs(dvc):
     dvc.config["remote"]["without_hash_jobs"] = {"url": "s3://bucket/name"}
-    dvc.config["core"]["hash_jobs"] = 200
+    dvc.config["core"]["checksum_jobs"] = 200
 
     tree = get_cloud_tree(dvc, name="without_hash_jobs")
     assert tree.hash_jobs == 200
diff --git a/tests/unit/test_info.py b/tests/unit/test_info.py
new file mode 100644
index 000000000..fe5dc2fb0
--- /dev/null
+++ b/tests/unit/test_info.py
@@ -0,0 +1,74 @@
+import os
+import re
+import shutil
+
+import pytest
+
+from dvc.info import get_dvc_info, psutil
+
+
+@pytest.mark.parametrize("scm_init", [True, False])
+def test_info_in_repo(scm_init, tmp_dir):
+    tmp_dir.init(scm=scm_init, dvc=True)
+    # Create `.dvc/cache`, that is needed to check supported link types.
+    os.mkdir(tmp_dir.dvc.cache.local.cache_dir)
+
+    dvc_info = get_dvc_info()
+
+    assert re.search(r"DVC version: \d+\.\d+\.\d+.*", dvc_info)
+    assert re.search(r"Platform: Python \d\.\d+\.\d+ on .*", dvc_info)
+    assert re.search(r"Supports: .*", dvc_info)
+    assert re.search(r"Cache types: .*", dvc_info)
+
+    if scm_init:
+        assert "Repo: dvc, git" in dvc_info
+    else:
+        assert "Repo: dvc (no_scm)" in dvc_info
+
+
+def test_info_in_subdir(tmp_dir, scm, caplog):
+    dvc_subdir = tmp_dir / "subdir"
+    dvc_subdir.mkdir()
+
+    with dvc_subdir.chdir():
+        dvc_subdir.init(scm=False, dvc=True)
+        with dvc_subdir.dvc.config.edit() as conf:
+            del conf["core"]["no_scm"]
+
+        dvc_info = get_dvc_info()
+
+    assert "Repo: dvc (subdir), git" in dvc_info
+
+
+def test_info_in_broken_git_repo(tmp_dir, dvc, scm, caplog):
+    shutil.rmtree(dvc.scm.dir)
+    dvc_info = get_dvc_info()
+
+    assert "Repo: dvc, git (broken)" in dvc_info
+
+
+@pytest.mark.skipif(psutil is None, reason="No psutil.")
+def test_fs_info_in_repo(tmp_dir, dvc, caplog):
+    os.mkdir(dvc.cache.local.cache_dir)
+    dvc_info = get_dvc_info()
+
+    assert re.search(r"Cache directory: .* on .*", dvc_info)
+    assert re.search(r"Workspace directory: .* on .*", dvc_info)
+
+
+def test_info_outside_of_repo(tmp_dir, caplog):
+    dvc_info = get_dvc_info()
+
+    assert re.search(r"DVC version: \d+\.\d+\.\d+.*", dvc_info)
+    assert re.search(r"Platform: Python \d\.\d+\.\d+ on .*", dvc_info)
+    assert re.search(r"Supports: .*", dvc_info)
+    assert not re.search(r"Cache types: .*", dvc_info)
+    assert "Repo:" not in dvc_info
+
+
+@pytest.mark.skipif(psutil is None, reason="No psutil.")
+def test_fs_info_outside_of_repo(tmp_dir, caplog):
+    dvc_info = get_dvc_info()
+    assert re.search(r"DVC version: \d+\.\d+\.\d+.*", dvc_info)
+    assert re.search(r"Platform: Python \d\.\d+\.\d+ on .*", dvc_info)
+    assert re.search(r"Supports: .*", dvc_info)
diff --git a/tests/unit/tree/test_tree.py b/tests/unit/tree/test_tree.py
new file mode 100644
index 000000000..2c4fc3af7
--- /dev/null
+++ b/tests/unit/tree/test_tree.py
@@ -0,0 +1,48 @@
+import pytest
+
+from dvc.config import ConfigError
+from dvc.path_info import CloudURLInfo
+from dvc.tree import get_cloud_tree
+
+
+def test_get_cloud_tree(tmp_dir, dvc):
+    tmp_dir.add_remote(name="base", url="s3://bucket/path", default=False)
+    tmp_dir.add_remote(name="first", url="remote://base/first", default=False)
+    tmp_dir.add_remote(
+        name="second", url="remote://first/second", default=False
+    )
+
+    base = CloudURLInfo("s3://bucket/path")
+    first = base / "first"
+    second = first / "second"
+
+    assert get_cloud_tree(dvc, name="base").path_info == base
+    assert get_cloud_tree(dvc, name="first").path_info == first
+    assert get_cloud_tree(dvc, name="second").path_info == second
+
+
+def test_get_cloud_tree_validate(tmp_dir, dvc):
+    tmp_dir.add_remote(
+        name="base", url="ssh://example.com/path", default=False
+    )
+    tmp_dir.add_remote(
+        name="first",
+        config={"url": "remote://base/first", "type": "symlink"},
+        default=False,
+    )
+    tmp_dir.add_remote(
+        name="second",
+        config={"url": "remote://first/second", "oss_key_id": "mykey"},
+        default=False,
+    )
+
+    assert get_cloud_tree(dvc, name="base").config == {
+        "url": "ssh://example.com/path"
+    }
+    assert get_cloud_tree(dvc, name="first").config == {
+        "url": "ssh://example.com/path/first",
+        "type": ["symlink"],
+    }
+
+    with pytest.raises(ConfigError):
+        get_cloud_tree(dvc, name="second")