commit b57a69160a0ffde51cd6fc80eb98fdaed9a5567f
Author: Mathieu Parent <math.parent@gmail.com>
Date:   Thu Jun 4 23:17:38 2020 +0200

    git_pillar: Avoid checkout to improve performance and fix inconsistency
    
    Fixes: #39420
    
    This also add several features from gitfs:
    - git_pillar_saltenv_whitelist / git_pillar_saltenv_blacklist
    - git_pillar_ref_types
    - git_pillar_disable_saltenv_mapping

commit 34b1154997181c19cf2ffc08b3748012c90fb085
Author: Sergey Efimov <sefimov@efolder.net>
Date:   Fri Oct 9 15:13:51 2020 +0500

    Fix 'import_yaml' issue

commit dddfd49c8e0da44182b955c7e1955c6b29ed9d2c
Author: Vaarlion <59558433+Vaarlion@users.noreply.github.com>
Date:   Wed Mar 24 10:26:36 2021 +0100

    fix error when file isn't provided by salt (local one for exemple)

Index: salt-3003+ds+efs/salt/config/__init__.py
===================================================================
--- salt-3003+ds+efs.orig/salt/config/__init__.py
+++ salt-3003+ds+efs/salt/config/__init__.py
@@ -534,6 +534,8 @@ VALID_OPTS = immutabletypes.freeze(
         # could conceivably be loaded as non-string types, which is OK because
         # git_pillar will normalize them to strings. But rather than include all the
         # possible types they could be, we'll just skip type-checking.
+        "git_pillar_saltenv_whitelist": list,
+        "git_pillar_saltenv_blacklist": list,
         "git_pillar_ssl_verify": bool,
         "git_pillar_global_lock": bool,
         "git_pillar_user": str,
@@ -542,7 +544,9 @@ VALID_OPTS = immutabletypes.freeze(
         "git_pillar_privkey": str,
         "git_pillar_pubkey": str,
         "git_pillar_passphrase": str,
+        "git_pillar_ref_types": list,
         "git_pillar_refspecs": list,
+        "git_pillar_disable_saltenv_mapping": bool,
         "git_pillar_includes": bool,
         "git_pillar_verify_config": bool,
         # NOTE: gitfs_base, gitfs_fallback, gitfs_mountpoint, and gitfs_root omitted
@@ -1067,6 +1071,8 @@ DEFAULT_MINION_OPTS = immutabletypes.fre
         "git_pillar_env": "",
         "git_pillar_fallback": "",
         "git_pillar_root": "",
+        "git_pillar_saltenv_whitelist": [],
+        "git_pillar_saltenv_blacklist": [],
         "git_pillar_ssl_verify": True,
         "git_pillar_global_lock": True,
         "git_pillar_user": "",
@@ -1075,7 +1081,9 @@ DEFAULT_MINION_OPTS = immutabletypes.fre
         "git_pillar_privkey": "",
         "git_pillar_pubkey": "",
         "git_pillar_passphrase": "",
+        "git_pillar_ref_types": ["branch", "tag", "sha"],
         "git_pillar_refspecs": _DFLT_REFSPECS,
+        "git_pillar_disable_saltenv_mapping": False,
         "git_pillar_includes": True,
         "gitfs_remotes": [],
         "gitfs_mountpoint": "",
@@ -1316,6 +1324,8 @@ DEFAULT_MASTER_OPTS = immutabletypes.fre
         "git_pillar_env": "",
         "git_pillar_fallback": "",
         "git_pillar_root": "",
+        "git_pillar_saltenv_whitelist": [],
+        "git_pillar_saltenv_blacklist": [],
         "git_pillar_ssl_verify": True,
         "git_pillar_global_lock": True,
         "git_pillar_user": "",
@@ -1324,7 +1334,9 @@ DEFAULT_MASTER_OPTS = immutabletypes.fre
         "git_pillar_privkey": "",
         "git_pillar_pubkey": "",
         "git_pillar_passphrase": "",
+        "git_pillar_ref_types": ["branch", "tag", "sha"],
         "git_pillar_refspecs": _DFLT_REFSPECS,
+        "git_pillar_disable_saltenv_mapping": False,
         "git_pillar_includes": True,
         "git_pillar_verify_config": True,
         "gitfs_remotes": [],
Index: salt-3003+ds+efs/salt/pillar/__init__.py
===================================================================
--- salt-3003+ds+efs.orig/salt/pillar/__init__.py
+++ salt-3003+ds+efs/salt/pillar/__init__.py
@@ -501,6 +501,7 @@ class Pillar:
         pillar_override=None,
         pillarenv=None,
         extra_minion_data=None,
+        client=None,
     ):
         self.minion_id = minion_id
         self.ext = ext
@@ -510,7 +511,10 @@ class Pillar:
         # use the local file client
         self.opts = self.__gen_opts(opts, grains, saltenv=saltenv, pillarenv=pillarenv)
         self.saltenv = saltenv
-        self.client = salt.fileclient.get_file_client(self.opts, True)
+        if client is None:
+            self.client = salt.fileclient.get_file_client(self.opts, True)
+        else:
+            self.client = client
         self.avail = self.__gather_avail()
 
         if opts.get("file_client", "") == "local" and not opts.get(
@@ -639,8 +643,9 @@ class Pillar:
         Pull the file server environments out of the master options
         """
         envs = {"base"}
-        if "pillar_roots" in self.opts:
-            envs.update(list(self.opts["pillar_roots"]))
+        envs.update(self.client.envs())
+        if self.opts.get("__git_pillar", False) and self.opts["pillarenv"]:
+            envs.update([self.opts["pillarenv"]])
         return envs
 
     def get_tops(self):
@@ -657,12 +662,12 @@ class Pillar:
             if self.opts["pillarenv"]:
                 # If the specified pillarenv is not present in the available
                 # pillar environments, do not cache the pillar top file.
-                if self.opts["pillarenv"] not in self.opts["pillar_roots"]:
+                if self.opts["pillarenv"] not in self._get_envs():
                     log.debug(
                         "pillarenv '%s' not found in the configured pillar "
                         "environments (%s)",
                         self.opts["pillarenv"],
-                        ", ".join(self.opts["pillar_roots"]),
+                        ", ".join(self._get_envs()),
                     )
                 else:
                     saltenvs.add(self.opts["pillarenv"])
@@ -860,7 +865,7 @@ class Pillar:
                     "Specified SLS '{}' in environment '{}' was not "
                     "found. ".format(sls, saltenv)
                 )
-                if self.opts.get("__git_pillar", False) is True:
+                if self.opts.get("__git_pillar", False):
                     msg += (
                         "This is likely caused by a git_pillar top file "
                         "containing an environment other than the one for the "
@@ -875,11 +880,13 @@ class Pillar:
                         "could also be due to environment '{1}' not being "
                         "defined in 'pillar_roots'.".format(sls, saltenv)
                     )
-                log.debug(msg)
+                log.error(msg)
+                errors.append(msg)
                 # return state, mods, errors
                 return None, mods, errors
         state = None
         try:
+            defaults["file_client"] = self.client
             state = compile_template(
                 fn_,
                 self.rend,
Index: salt-3003+ds+efs/salt/pillar/git_pillar.py
===================================================================
--- salt-3003+ds+efs.orig/salt/pillar/git_pillar.py
+++ salt-3003+ds+efs/salt/pillar/git_pillar.py
@@ -398,9 +398,21 @@ import salt.utils.versions
 from salt.exceptions import FileserverConfigError
 from salt.pillar import Pillar
 
-PER_REMOTE_OVERRIDES = ("base", "env", "root", "ssl_verify", "refspecs", "fallback")
-PER_REMOTE_ONLY = ("name", "mountpoint", "all_saltenvs")
-GLOBAL_ONLY = ("branch",)
+PER_REMOTE_OVERRIDES = (
+    "base",
+    "fallback",
+    "root",
+    "ssl_verify",
+    "saltenv_whitelist",
+    "saltenv_blacklist",
+    "refspecs",
+    "disable_saltenv_mapping",
+    "ref_types",
+    # "update_interval",
+    "env",  # != gitfs
+)
+PER_REMOTE_ONLY = ("name", "mountpoint", "all_saltenvs")  # "saltenv"
+GLOBAL_ONLY = ("branch",)  # != gitfs
 
 # Set up logging
 log = logging.getLogger(__name__)
@@ -435,7 +447,7 @@ def ext_pillar(minion_id, pillar, *repos
     opts = copy.deepcopy(__opts__)
     opts["pillar_roots"] = {}
     opts["__git_pillar"] = True
-    git_pillar = salt.utils.gitfs.GitPillar(
+    git_pillar_client = salt.utils.gitfs.GitPillarClient(
         opts,
         repos,
         per_remote_overrides=PER_REMOTE_OVERRIDES,
@@ -445,68 +457,47 @@ def ext_pillar(minion_id, pillar, *repos
     if __opts__.get("__role") == "minion":
         # If masterless, fetch the remotes. We'll need to remove this once
         # we make the minion daemon able to run standalone.
-        git_pillar.fetch_remotes()
-    git_pillar.checkout()
+        git_pillar_client.fetch_remotes()
     ret = {}
     merge_strategy = __opts__.get("pillar_source_merging_strategy", "smart")
     merge_lists = __opts__.get("pillar_merge_lists", False)
-    for pillar_dir, env in git_pillar.pillar_dirs.items():
-        # Map env if env == '__env__' before checking the env value
-        if env == "__env__":
-            env = (
-                opts.get("pillarenv")
-                or opts.get("saltenv")
-                or opts.get("git_pillar_base")
-            )
-            log.debug("__env__ maps to %s", env)
-
-        # If pillarenv is set, only grab pillars with that match pillarenv
-        if opts["pillarenv"] and env != opts["pillarenv"]:
-            log.debug(
-                "env '%s' for pillar dir '%s' does not match "
-                "pillarenv '%s', skipping",
-                env,
-                pillar_dir,
-                opts["pillarenv"],
-            )
-            continue
-        if pillar_dir in git_pillar.pillar_linked_dirs:
-            log.debug(
-                "git_pillar is skipping processing on %s as it is a " "mounted repo",
-                pillar_dir,
-            )
-            continue
-        else:
-            log.debug(
-                "git_pillar is processing pillar SLS from %s for pillar " "env '%s'",
-                pillar_dir,
-                env,
-            )
-
-        pillar_roots = [pillar_dir]
 
+    def remote_env(remote):
+        if remote.branch == "__env__" and hasattr(remote, "all_saltenvs"):
+            return opts.get("pillarenv") or opts.get("saltenv") or "base"
+        elif remote.env:
+            return remote.env
+        else:
+            if remote.branch == remote.base:
+                return "base"
+            else:
+                tgt = remote.get_checkout_target()
+                return "base" if tgt == remote.base else tgt
+
+    for remote_idx, remote in enumerate(git_pillar_client.remotes):
+        env = remote_env(remote)
+        remotes = [repos[remote_idx]]
         if __opts__["git_pillar_includes"]:
-            # Add the rest of the pillar_dirs in this environment to the
-            # list, excluding the current pillar_dir being processed. This
-            # is because it was already specified above as the first in the
-            # list, so that its top file is sourced from the correct
-            # location and not from another git_pillar remote.
-            pillar_roots.extend(
-                [
-                    d
-                    for (d, e) in git_pillar.pillar_dirs.items()
-                    if env == e and d != pillar_dir
-                ]
-            )
-
-        opts["pillar_roots"] = {env: pillar_roots}
-
-        local_pillar = Pillar(opts, __grains__, minion_id, env)
+            for remote_idx2, remote2 in enumerate(git_pillar_client.remotes):
+                if remote_idx2 == remote_idx:
+                    continue
+                env2 = remote_env(remote2)
+                if env2 == env:
+                    remotes.append(repos[remote_idx2])
+
+        repo_git_pillar_client = salt.utils.gitfs.GitPillarClient(
+            opts,
+            remotes,
+            per_remote_overrides=PER_REMOTE_OVERRIDES,
+            per_remote_only=PER_REMOTE_ONLY,
+            global_only=GLOBAL_ONLY,
+        )
+        local_pillar = Pillar(
+            opts, __grains__, minion_id, env, client=repo_git_pillar_client
+        )
+        compiled = local_pillar.compile_pillar(ext=False)
         ret = salt.utils.dictupdate.merge(
-            ret,
-            local_pillar.compile_pillar(ext=False),
-            strategy=merge_strategy,
-            merge_lists=merge_lists,
+            ret, compiled, strategy=merge_strategy, merge_lists=merge_lists,
         )
     return ret
 
Index: salt-3003+ds+efs/salt/utils/gitfs.py
===================================================================
--- salt-3003+ds+efs.orig/salt/utils/gitfs.py
+++ salt-3003+ds+efs/salt/utils/gitfs.py
@@ -20,6 +20,7 @@ import weakref
 from datetime import datetime
 
 import salt.ext.tornado.ioloop
+import salt.fileclient
 import salt.fileserver
 import salt.utils.configparser
 import salt.utils.data
@@ -525,8 +526,6 @@ class GitProvider:
             strip_sep = (
                 lambda x: x.rstrip(os.sep) if name in ("root", "mountpoint") else x
             )
-            if self.role != "gitfs":
-                return strip_sep(getattr(self, "_" + name))
             # Get saltenv-specific configuration
             saltenv_conf = self.saltenv.get(tgt_env, {})
             if name == "ref":
@@ -542,6 +541,43 @@ class GitProvider:
                     else:
                         return None
 
+                def _get_git_pillar_env():
+                    if self.branch == "__env__":
+                        if hasattr(self, "all_saltenvs"):
+                            pillarenv = (
+                                self.opts.get("pillarenv")
+                                or self.opts.get("saltenv")
+                                or "base"
+                            )
+                            if tgt_env == pillarenv:
+                                return self.all_saltenvs
+                            else:
+                                return None
+                        else:
+                            if tgt_env == "base":
+                                return self.base
+                            else:
+                                return tgt_env
+                    elif self.env:
+                        if tgt_env == self.env:
+                            return self.branch
+                        else:
+                            return None
+                    else:
+                        if tgt_env == "base":
+                            if self.branch == self.base:
+                                return self.branch
+                            else:
+                                return None
+                        else:
+                            if tgt_env == self.branch:
+                                return self.branch
+                            else:
+                                return None
+
+                if self.opts.get("__git_pillar", False):
+                    return _get_git_pillar_env()
+
                 # Return the all_saltenvs branch/tag if it is configured
                 per_saltenv_ref = _get_per_saltenv(tgt_env)
                 try:
@@ -1011,6 +1047,17 @@ class GitProvider:
         Check if an environment is exposed by comparing it against a whitelist
         and blacklist.
         """
+        if self.opts.get("__git_pillar", False):
+            if self.branch != "__env__":
+                if self.env:
+                    if tgt_env != self.env:
+                        return False
+                elif tgt_env == "base":
+                    if self.base != self.branch:
+                        return False
+                else:
+                    if tgt_env != self.branch:
+                        return False
         return salt.utils.stringutils.check_whitelist_blacklist(
             tgt_env, whitelist=self.saltenv_whitelist, blacklist=self.saltenv_blacklist,
         )
@@ -2843,6 +2890,7 @@ class GitFS(GitBase):
         remotes=None,
         per_remote_overrides=(),
         per_remote_only=PER_REMOTE_ONLY,
+        global_only=GLOBAL_ONLY,
         git_providers=None,
         cache_root=None,
         init_remotes=True,
@@ -2867,6 +2915,7 @@ class GitFS(GitBase):
                 remotes if remotes is not None else [],
                 per_remote_overrides=per_remote_overrides,
                 per_remote_only=per_remote_only,
+                global_only=global_only,
                 git_providers=git_providers
                 if git_providers is not None
                 else GIT_PROVIDERS,
@@ -2890,6 +2939,7 @@ class GitFS(GitBase):
         remotes,
         per_remote_overrides=(),
         per_remote_only=PER_REMOTE_ONLY,
+        global_only=GLOBAL_ONLY,
         git_providers=None,
         cache_root=None,
         init_remotes=True,
@@ -2930,14 +2980,29 @@ class GitFS(GitBase):
         if os.path.isabs(path):
             return fnd
 
-        dest = salt.utils.path.join(self.cache_root, "refs", tgt_env, path)
-        hashes_glob = salt.utils.path.join(
-            self.hash_cachedir, tgt_env, "{}.hash.*".format(path)
-        )
-        blobshadest = salt.utils.path.join(
-            self.hash_cachedir, tgt_env, "{}.hash.blob_sha1".format(path)
-        )
-        lk_fn = salt.utils.path.join(self.hash_cachedir, tgt_env, "{}.lk".format(path))
+        if self.opts.get("__git_pillar", False):
+            name = getattr(self.remotes[0], "name", self.remotes[0].hash)
+            dest = salt.utils.path.join(self.cache_root, "refs", name, tgt_env, path)
+            hashes_glob = salt.utils.path.join(
+                self.hash_cachedir, name, tgt_env, "{}.hash.*".format(path)
+            )
+            blobshadest = salt.utils.path.join(
+                self.hash_cachedir, name, tgt_env, "{}.hash.blob_sha1".format(path)
+            )
+            lk_fn = salt.utils.path.join(
+                self.hash_cachedir, name, tgt_env, "{}.lk".format(path)
+            )
+        else:
+            dest = salt.utils.path.join(self.cache_root, "refs", tgt_env, path)
+            hashes_glob = salt.utils.path.join(
+                self.hash_cachedir, tgt_env, "{}.hash.*".format(path)
+            )
+            blobshadest = salt.utils.path.join(
+                self.hash_cachedir, tgt_env, "{}.hash.blob_sha1".format(path)
+            )
+            lk_fn = salt.utils.path.join(
+                self.hash_cachedir, tgt_env, "{}.lk".format(path)
+            )
         destdir = os.path.dirname(dest)
         hashdir = os.path.dirname(blobshadest)
         if not os.path.isdir(destdir):
@@ -3350,6 +3415,81 @@ class GitPillar(GitBase):
         return True
 
 
+class GitPillarClient(GitBase, salt.fileclient.Client):
+    """
+    Functionality specific to the git external pillar implementing the salt.fileclient.Client interface
+    """
+
+    role = "git_pillar"
+
+    def __init__(
+        self,
+        opts,
+        remotes,
+        per_remote_overrides=(),
+        per_remote_only=PER_REMOTE_ONLY,
+        global_only=GLOBAL_ONLY,
+        git_providers=None,
+        cache_root=None,
+        init_remotes=True,
+    ):
+        self._envs = None
+        GitBase.__init__(
+            self,
+            opts,
+            remotes,
+            per_remote_overrides=per_remote_overrides,
+            per_remote_only=per_remote_only,
+            global_only=global_only,
+            git_providers=git_providers,
+            cache_root=cache_root,
+            init_remotes=init_remotes,
+        )
+        salt.fileclient.Client.__init__(self, opts)
+
+    def get_file(
+        self, path, dest="", makedirs=False, saltenv="base", gzip=None, cachedir=None
+    ):
+        """
+        Get a single file from the salt-master
+        path must be a salt server location, aka, salt://path/to/file, if
+        dest is omitted, then the downloaded file will be placed in the minion
+        cache
+        """
+        path = self._check_proto(path)
+        ret = GitFS.find_file(self, path, tgt_env=saltenv)
+        return ret["path"]
+
+    def file_list(self, saltenv="base", prefix=""):
+        """
+        List the files on the master
+        """
+        load = {"saltenv": saltenv, "prefix": prefix, "cmd": "_file_list"}
+        return GitFS._file_lists(self, load, "files")
+
+    def file_list_emptydirs(self, saltenv="base", prefix=""):
+        """
+        List the empty dirs on the master
+        """
+        # Cannot have empty dirs in git
+        return []
+
+    def dir_list(self, saltenv="base", prefix=""):
+        """
+        List the dirs on the master
+        """
+        load = {"saltenv": saltenv, "prefix": prefix, "cmd": "_dir_list"}
+        return GitFS._file_lists(self, load, "dirs")
+
+    def envs(self):
+        """
+        Return a list of available environments
+        """
+        if self._envs is None:
+            self._envs = GitFS.envs(self)
+        return self._envs
+
+
 class WinRepo(GitBase):
     """
     Functionality specific to the winrepo runner
Index: salt-3003+ds+efs/salt/utils/jinja.py
===================================================================
--- salt-3003+ds+efs.orig/salt/utils/jinja.py
+++ salt-3003+ds+efs/salt/utils/jinja.py
@@ -87,7 +87,9 @@ class SaltCacheLoader(BaseLoader):
         self.cached = []
         self._file_client = _file_client
         # Instantiate the fileclient
-        self.file_client()
+        if _file_client is None:
+            log.debug("SaltCacheLoader::__init__ - file_client is None. Instantiate")
+            self.file_client()
 
     def file_client(self):
         """
@@ -112,7 +114,19 @@ class SaltCacheLoader(BaseLoader):
         Cache a file from the salt master
         """
         saltpath = salt.utils.url.create(template)
-        self.file_client().get_file(saltpath, "", True, self.saltenv)
+        ret_path = self.file_client().get_file(saltpath, "", True, self.saltenv)
+        # Only continue if the file is from salt
+        if ret_path is not False:
+            # remove 'template' string in returned full path and add cache directory into searchpath
+            m = ret_path.find(template, 0, len(ret_path))
+            if m >= 0:
+                _rpath = ret_path[:m]
+                if _rpath not in self.searchpath:
+                    self.searchpath.append(_rpath)
+                log.debug(
+                    "SaltCacheLoader::cache_file Added directory %s into searchpath",
+                    _rpath,
+                )
 
     def check_cache(self, template):
         """
@@ -173,7 +187,6 @@ class SaltCacheLoader(BaseLoader):
                 "tpldot": tpldir.replace("/", "."),
             }
             environment.globals.update(tpldata)
-
         # pylint: disable=cell-var-from-loop
         for spath in self.searchpath:
             filepath = os.path.join(spath, _template)
Index: salt-3003+ds+efs/salt/utils/templates.py
===================================================================
--- salt-3003+ds+efs.orig/salt/utils/templates.py
+++ salt-3003+ds+efs/salt/utils/templates.py
@@ -384,6 +384,9 @@ def render_jinja_tmpl(tmplstr, context,
     newline = False
     file_client = context.get("fileclient", None)
 
+    file_client = None
+    if "file_client" in context:
+        file_client = context["file_client"]
     if tmplstr and not isinstance(tmplstr, str):
         # https://jinja.palletsprojects.com/en/2.11.x/api/#unicode
         tmplstr = tmplstr.decode(SLS_ENCODING)
Index: salt-3003+ds+efs/tests/integration/pillar/test_git_pillar.py
===================================================================
--- salt-3003+ds+efs.orig/tests/integration/pillar/test_git_pillar.py
+++ salt-3003+ds+efs/tests/integration/pillar/test_git_pillar.py
@@ -403,8 +403,11 @@ class GitPythonMixin:
                     "nested_dict": {"master": True},
                 },
                 "_errors": [
-                    "Specified SLS 'bar' in environment 'base' is not "
-                    "available on the salt master"
+                    "Specified SLS 'bar' in environment 'base' was not found. "
+                    "This is likely caused by a git_pillar top file "
+                    "containing an environment other than the one for the "
+                    "branch in which it resides. Each git_pillar "
+                    "branch/tag must have its own top file."
                 ],
             },
         )
@@ -1462,8 +1465,11 @@ class TestPygit2SSH(GitPillarSSHTestBase
                 "nested_dict": {"master": True},
             },
             "_errors": [
-                "Specified SLS 'bar' in environment 'base' is not "
-                "available on the salt master"
+                "Specified SLS 'bar' in environment 'base' was not found. "
+                "This is likely caused by a git_pillar top file "
+                "containing an environment other than the one for the "
+                "branch in which it resides. Each git_pillar "
+                "branch/tag must have its own top file."
             ],
         }
 
@@ -2604,8 +2610,11 @@ class TestPygit2HTTP(GitPillarHTTPTestBa
                 "nested_dict": {"master": True},
             },
             "_errors": [
-                "Specified SLS 'bar' in environment 'base' is not "
-                "available on the salt master"
+                "Specified SLS 'bar' in environment 'base' was not found. "
+                "This is likely caused by a git_pillar top file "
+                "containing an environment other than the one for the "
+                "branch in which it resides. Each git_pillar "
+                "branch/tag must have its own top file."
             ],
         }
 
@@ -3414,8 +3423,11 @@ class TestPygit2AuthenticatedHTTP(GitPil
                 "nested_dict": {"master": True},
             },
             "_errors": [
-                "Specified SLS 'bar' in environment 'base' is not "
-                "available on the salt master"
+                "Specified SLS 'bar' in environment 'base' was not found. "
+                "This is likely caused by a git_pillar top file "
+                "containing an environment other than the one for the "
+                "branch in which it resides. Each git_pillar "
+                "branch/tag must have its own top file."
             ],
         }
 
Index: salt-3003+ds+efs/tests/support/gitfs.py
===================================================================
--- salt-3003+ds+efs.orig/tests/support/gitfs.py
+++ salt-3003+ds+efs/tests/support/gitfs.py
@@ -58,10 +58,14 @@ _OPTS = freeze(
         "git_pillar_privkey": "",
         "git_pillar_pubkey": "",
         "git_pillar_passphrase": "",
+        "git_pillar_ref_types": ["branch", "tag", "sha"],
+        "git_pillar_saltenv_whitelist": [],
+        "git_pillar_saltenv_blacklist": [],
         "git_pillar_refspecs": [
             "+refs/heads/*:refs/remotes/origin/*",
             "+refs/tags/*:refs/tags/*",
         ],
+        "git_pillar_disable_saltenv_mapping": False,
         "git_pillar_includes": True,
     }
 )
Index: salt-3003+ds+efs/tests/unit/test_pillar.py
===================================================================
--- salt-3003+ds+efs.orig/tests/unit/test_pillar.py
+++ salt-3003+ds+efs/tests/unit/test_pillar.py
@@ -45,6 +45,9 @@ class MockFileclient:
     def list_states(*args, **kwargs):
         raise NotImplementedError()
 
+    def envs(self):
+        return ["base"]
+
     # pylint: enable=unused-argument,no-method-argument,method-hidden
 
 
