diff --git a/README.md b/README.md index ce25cfce9..261549a6a 100644 --- a/README.md +++ b/README.md @@ -114,7 +114,7 @@ Once installed, extension behavior can be modified via the following settings wh - `JupyterLabGit.credential_helper`: Git credential helper to set to cache the credentials. The default value is `cache --timeout=3600` to cache the credentials for an hour. If you want to cache them for 10 hours, set `cache --timeout=36000`. - `JupyterLabGit.excluded_paths`: Set path patterns to exclude from this extension. You can use wildcard and interrogation mark for respectively everything or any single character in the pattern. - +- `JupyterLabGit.git_command_timeout_s`: Set the timeout for git operations. Defaults to 20 seconds.
How to set server settings? diff --git a/jupyterlab_git/__init__.py b/jupyterlab_git/__init__.py index dbe342505..ca597009f 100644 --- a/jupyterlab_git/__init__.py +++ b/jupyterlab_git/__init__.py @@ -1,6 +1,6 @@ """Initialize the backend server extension """ -from traitlets import List, Dict, Unicode, default +from traitlets import CFloat, List, Dict, Unicode, default from traitlets.config import Configurable try: @@ -46,10 +46,19 @@ class JupyterLabGit(Configurable): config=True, ) + git_command_timeout = CFloat( + help="The timeout for executing git operations. By default it is set to 20 seconds.", + config=True, + ) + @default("credential_helper") def _credential_helper_default(self): return "cache --timeout=3600" + @default("git_command_timeout") + def _git_command_timeout_default(self): + return 20.0 + def _jupyter_server_extension_points(): return [{"module": "jupyterlab_git"}] diff --git a/jupyterlab_git/git.py b/jupyterlab_git/git.py index cd8990731..3e30f8067 100644 --- a/jupyterlab_git/git.py +++ b/jupyterlab_git/git.py @@ -28,8 +28,6 @@ DEFAULT_REMOTE_NAME = "origin" # Maximum number of character of command output to print in debug log MAX_LOG_OUTPUT = 500 # type: int -# How long to wait to be executed or finished your execution before timing out -MAX_WAIT_FOR_EXECUTE_S = 20 # Ensure on NFS or similar, that we give the .git/index.lock time to be removed MAX_WAIT_FOR_LOCK_S = 5 # How often should we check for the lock above to be free? This comes up more on things like NFS @@ -49,6 +47,7 @@ async def execute( cmdline: "List[str]", cwd: "str", + timeout: "float" = 20, env: "Optional[Dict[str, str]]" = None, username: "Optional[str]" = None, password: "Optional[str]" = None, @@ -128,9 +127,7 @@ def call_subprocess( return (process.returncode, output.decode("utf-8"), error.decode("utf-8")) try: - await execution_lock.acquire( - timeout=datetime.timedelta(seconds=MAX_WAIT_FOR_EXECUTE_S) - ) + await execution_lock.acquire(timeout=datetime.timedelta(seconds=timeout)) except tornado.util.TimeoutError: return (1, "", "Unable to get the lock on the directory") @@ -192,11 +189,33 @@ class Git: def __init__(self, config=None): self._config = config + self._execute_timeout = ( + 20.0 if self._config is None else self._config.git_command_timeout + ) def __del__(self): if self._GIT_CREDENTIAL_CACHE_DAEMON_PROCESS: self._GIT_CREDENTIAL_CACHE_DAEMON_PROCESS.terminate() + async def __execute( + self, + cmdline: "List[str]", + cwd: "str", + env: "Optional[Dict[str, str]]" = None, + username: "Optional[str]" = None, + password: "Optional[str]" = None, + is_binary=False, + ) -> "Tuple[int, str, str]": + return await execute( + cmdline, + cwd=cwd, + timeout=self._execute_timeout, + env=env, + username=username, + password=password, + is_binary=is_binary, + ) + async def config(self, path, **kwargs): """Get or set Git options. @@ -208,7 +227,7 @@ async def config(self, path, **kwargs): output = [] for k, v in kwargs.items(): cmd = ["git", "config", "--add", k, v] - code, out, err = await execute(cmd, cwd=path) + code, out, err = await self.__execute(cmd, cwd=path) output.append(out.strip()) response["code"] = code if code != 0: @@ -219,7 +238,7 @@ async def config(self, path, **kwargs): response["message"] = "\n".join(output).strip() else: cmd = ["git", "config", "--list"] - code, output, error = await execute(cmd, cwd=path) + code, output, error = await self.__execute(cmd, cwd=path) response = {"code": code} if code != 0: @@ -267,7 +286,7 @@ async def changed_files(self, path, base=None, remote=None, single_commit=None): response = {} try: - code, output, error = await execute(cmd, cwd=path) + code, output, error = await self.__execute(cmd, cwd=path) except subprocess.CalledProcessError as e: response["code"] = e.returncode response["message"] = e.output.decode("utf-8") @@ -307,7 +326,7 @@ async def clone(self, path, repo_url, auth=None, versioning=True, submodules=Fal await self.ensure_credential_helper(path) env["GIT_TERMINAL_PROMPT"] = "1" cmd.append("-q") - code, output, error = await execute( + code, output, error = await self.__execute( cmd, username=auth["username"], password=auth["password"], @@ -316,7 +335,7 @@ async def clone(self, path, repo_url, auth=None, versioning=True, submodules=Fal ) else: env["GIT_TERMINAL_PROMPT"] = "0" - code, output, error = await execute( + code, output, error = await self.__execute( cmd, cwd=path, env=env, @@ -351,7 +370,7 @@ async def fetch(self, path, auth=None): if auth.get("cache_credentials"): await self.ensure_credential_helper(path) env["GIT_TERMINAL_PROMPT"] = "1" - code, _, fetch_error = await execute( + code, _, fetch_error = await self.__execute( cmd, cwd=cwd, username=auth["username"], @@ -360,7 +379,7 @@ async def fetch(self, path, auth=None): ) else: env["GIT_TERMINAL_PROMPT"] = "0" - code, _, fetch_error = await execute(cmd, cwd=cwd, env=env) + code, _, fetch_error = await self.__execute(cmd, cwd=cwd, env=env) result = { "code": code, @@ -438,7 +457,7 @@ async def status(self, path): Execute git status command & return the result. """ cmd = ["git", "status", "--porcelain", "-b", "-u", "-z"] - code, status, my_error = await execute(cmd, cwd=path) + code, status, my_error = await self.__execute(cmd, cwd=path) if code != 0: return { @@ -456,7 +475,7 @@ async def status(self, path): "--cached", "4b825dc642cb6eb9a060e54bf8d69288fbee4904", ] - text_code, text_output, _ = await execute(command, cwd=path) + text_code, text_output, _ = await self.__execute(command, cwd=path) are_binary = dict() if text_code == 0: @@ -530,7 +549,7 @@ async def log(self, path, history_count=10, follow_path=None): "--", follow_path, ] - code, my_output, my_error = await execute( + code, my_output, my_error = await self.__execute( cmd, cwd=path, ) @@ -593,7 +612,7 @@ async def detailed_log(self, selected_hash, path): selected_hash, ] - code, my_output, my_error = await execute( + code, my_output, my_error = await self.__execute( cmd, cwd=path, ) @@ -669,7 +688,7 @@ async def diff(self, path, previous=None, current=None): if current: cmd.append(current) - code, my_output, my_error = await execute(cmd, cwd=path) + code, my_output, my_error = await self.__execute(cmd, cwd=path) if code != 0: return {"code": code, "command": " ".join(cmd), "message": my_error} @@ -711,7 +730,7 @@ async def branch(self, path): async def branch_delete(self, path, branch): """Execute 'git branch -D '""" cmd = ["git", "branch", "-D", branch] - code, _, error = await execute(cmd, cwd=path) + code, _, error = await self.__execute(cmd, cwd=path) if code != 0: return {"code": code, "command": " ".join(cmd), "message": error} else: @@ -730,7 +749,7 @@ async def branch_heads(self, path): "refs/heads/", ] - code, output, error = await execute(cmd, cwd=path) + code, output, error = await self.__execute(cmd, cwd=path) if code != 0: return {"code": code, "command": " ".join(cmd), "message": error} @@ -796,7 +815,7 @@ async def branch_remotes(self, path): "refs/remotes/", ] - code, output, error = await execute(cmd, cwd=path) + code, output, error = await self.__execute(cmd, cwd=path) if code != 0: return {"code": code, "command": " ".join(cmd), "message": error} @@ -826,7 +845,7 @@ async def show_top_level(self, path): Execute git --show-toplevel command & return the result. """ cmd = ["git", "rev-parse", "--show-toplevel"] - code, my_output, my_error = await execute( + code, my_output, my_error = await self.__execute( cmd, cwd=path, ) @@ -849,7 +868,7 @@ async def show_prefix(self, path): Execute git --show-prefix command & return the result. """ cmd = ["git", "rev-parse", "--show-prefix"] - code, my_output, my_error = await execute( + code, my_output, my_error = await self.__execute( cmd, cwd=path, ) @@ -877,7 +896,7 @@ async def add(self, filename, path): cmd = ["git", "add"] + list(filename) else: cmd = ["git", "add", filename] - code, _, error = await execute(cmd, cwd=path) + code, _, error = await self.__execute(cmd, cwd=path) if code != 0: return {"code": code, "command": " ".join(cmd), "message": error} @@ -888,7 +907,7 @@ async def add_all(self, path): Execute git add all command & return the result. """ cmd = ["git", "add", "-A"] - code, _, error = await execute(cmd, cwd=path) + code, _, error = await self.__execute(cmd, cwd=path) if code != 0: return {"code": code, "command": " ".join(cmd), "message": error} @@ -899,7 +918,7 @@ async def add_all_unstaged(self, path): Execute git add all unstaged command & return the result. """ cmd = ["git", "add", "-u"] - code, _, error = await execute(cmd, cwd=path) + code, _, error = await self.__execute(cmd, cwd=path) if code != 0: return {"code": code, "command": " ".join(cmd), "message": error} @@ -925,7 +944,7 @@ async def reset(self, filename, path): Execute git reset command & return the result. """ cmd = ["git", "reset", "--", filename] - code, _, error = await execute(cmd, cwd=path) + code, _, error = await self.__execute(cmd, cwd=path) if code != 0: return {"code": code, "command": " ".join(cmd), "message": error} @@ -936,7 +955,7 @@ async def reset_all(self, path): Execute git reset command & return the result. """ cmd = ["git", "reset"] - code, _, error = await execute(cmd, cwd=path) + code, _, error = await self.__execute(cmd, cwd=path) if code != 0: return {"code": code, "command": " ".join(cmd), "message": error} @@ -947,7 +966,7 @@ async def delete_commit(self, commit_id, path): Delete a specified commit from the repository. """ cmd = ["git", "revert", "-m", "1", "--no-commit", commit_id] - code, _, error = await execute(cmd, cwd=path) + code, _, error = await self.__execute(cmd, cwd=path) if code != 0: return {"code": code, "command": " ".join(cmd), "message": error} @@ -960,7 +979,7 @@ async def reset_to_commit(self, commit_id, path): cmd = ["git", "reset", "--hard"] if commit_id: cmd.append(commit_id) - code, _, error = await execute(cmd, cwd=path) + code, _, error = await self.__execute(cmd, cwd=path) if code != 0: return {"code": code, "command": " ".join(cmd), "message": error} @@ -971,7 +990,7 @@ async def checkout_new_branch(self, branchname, startpoint, path): Execute git checkout command & return the result. """ cmd = ["git", "checkout", "-b", branchname, startpoint] - code, my_output, my_error = await execute( + code, my_output, my_error = await self.__execute( cmd, cwd=path, ) @@ -988,7 +1007,7 @@ async def _get_branch_reference(self, branchname, path): """ Execute git rev-parse --symbolic-full-name and return the result (or None). """ - code, my_output, _ = await execute( + code, my_output, _ = await self.__execute( ["git", "rev-parse", "--symbolic-full-name", branchname], cwd=path, ) @@ -1014,7 +1033,7 @@ async def checkout_branch(self, branchname, path): else: cmd = ["git", "checkout", branchname] - code, my_output, my_error = await execute(cmd, cwd=path) + code, my_output, my_error = await self.__execute(cmd, cwd=path) if code == 0: return {"code": 0, "message": my_output} @@ -1026,7 +1045,7 @@ async def checkout(self, filename, path): Execute git checkout command for the filename & return the result. """ cmd = ["git", "checkout", "--", filename] - code, _, error = await execute(cmd, cwd=path) + code, _, error = await self.__execute(cmd, cwd=path) if code != 0: return {"code": code, "command": " ".join(cmd), "message": error} @@ -1037,7 +1056,7 @@ async def checkout_all(self, path): Execute git checkout command & return the result. """ cmd = ["git", "checkout", "--", "."] - code, _, error = await execute(cmd, cwd=path) + code, _, error = await self.__execute(cmd, cwd=path) if code != 0: return {"code": code, "command": " ".join(cmd), "message": error} @@ -1048,7 +1067,7 @@ async def merge(self, branch, path): Execute git merge command & return the result. """ cmd = ["git", "merge", branch] - code, output, error = await execute(cmd, cwd=path) + code, output, error = await self.__execute(cmd, cwd=path) if code != 0: return {"code": code, "command": " ".join(cmd), "message": error} @@ -1066,7 +1085,7 @@ async def commit(self, commit_msg, amend, path): else: cmd.extend(["--m", commit_msg]) - code, _, error = await execute(cmd, cwd=path) + code, _, error = await self.__execute(cmd, cwd=path) if code != 0: return {"code": code, "command": " ".join(cmd), "message": error} @@ -1082,7 +1101,7 @@ async def pull(self, path, auth=None, cancel_on_conflict=False): if auth.get("cache_credentials"): await self.ensure_credential_helper(path) env["GIT_TERMINAL_PROMPT"] = "1" - code, output, error = await execute( + code, output, error = await self.__execute( ["git", "pull", "--no-commit"], username=auth["username"], password=auth["password"], @@ -1091,7 +1110,7 @@ async def pull(self, path, auth=None, cancel_on_conflict=False): ) else: env["GIT_TERMINAL_PROMPT"] = "0" - code, output, error = await execute( + code, output, error = await self.__execute( ["git", "pull", "--no-commit"], env=env, cwd=path, @@ -1106,7 +1125,7 @@ async def pull(self, path, auth=None, cancel_on_conflict=False): in output.lower() ) if cancel_on_conflict and has_conflict: - code, _, error = await execute( + code, _, error = await self.__execute( ["git", "merge", "--abort"], cwd=path, ) @@ -1147,7 +1166,7 @@ async def push( if auth.get("cache_credentials"): await self.ensure_credential_helper(path) env["GIT_TERMINAL_PROMPT"] = "1" - code, output, error = await execute( + code, output, error = await self.__execute( command, username=auth["username"], password=auth["password"], @@ -1156,7 +1175,7 @@ async def push( ) else: env["GIT_TERMINAL_PROMPT"] = "0" - code, output, error = await execute( + code, output, error = await self.__execute( command, env=env, cwd=path, @@ -1175,7 +1194,7 @@ async def init(self, path): """ cmd = ["git", "init"] cwd = path - code, _, error = await execute(cmd, cwd=cwd) + code, _, error = await self.__execute(cmd, cwd=cwd) actions = None if code == 0: @@ -1199,7 +1218,9 @@ async def _maybe_run_actions(self, name, cwd): for action in actions_list: try: # We trust the actions as they were passed via a config and not the UI - code, stdout, stderr = await execute(shlex.split(action), cwd=cwd) + code, stdout, stderr = await self.__execute( + shlex.split(action), cwd=cwd + ) actions.append( { "cmd": action, @@ -1237,7 +1258,7 @@ async def get_current_branch(self, path): See https://git-blame.blogspot.com/2013/06/checking-current-branch-programatically.html """ command = ["git", "symbolic-ref", "--short", "HEAD"] - code, output, error = await execute(command, cwd=path) + code, output, error = await self.__execute(command, cwd=path) if code == 0: return output.strip() elif "not a symbolic ref" in error.lower(): @@ -1253,7 +1274,7 @@ async def get_current_branch(self, path): async def _get_current_branch_detached(self, path): """Execute 'git branch -a' to get current branch details in case of detached HEAD""" command = ["git", "branch", "-a"] - code, output, error = await execute(command, cwd=path) + code, output, error = await self.__execute(command, cwd=path) if code == 0: for branch in output.splitlines(): branch = branch.strip() @@ -1277,13 +1298,13 @@ async def get_upstream_branch(self, path, branch_name): "--abbrev-ref", "{}@{{upstream}}".format(branch_name), ] - code, output, error = await execute(command, cwd=path) + code, output, error = await self.__execute(command, cwd=path) if code != 0: return {"code": code, "command": " ".join(command), "message": error} rev_parse_output = output.strip() command = ["git", "config", "--local", "branch.{}.remote".format(branch_name)] - code, output, error = await execute(command, cwd=path) + code, output, error = await self.__execute(command, cwd=path) if code != 0: return {"code": code, "command": " ".join(command), "message": error} @@ -1301,7 +1322,7 @@ async def _get_tag(self, path, commit_sha): Reference : https://git-scm.com/docs/git-describe#git-describe-ltcommit-ishgt82308203 """ command = ["git", "describe", "--tags", commit_sha] - code, output, error = await execute(command, cwd=path) + code, output, error = await self.__execute(command, cwd=path) if code == 0: return output.strip() elif "fatal: no tags can describe '{}'.".format(commit_sha) in error.lower(): @@ -1325,7 +1346,7 @@ async def _get_base_ref(self, path, filename): """ command = ["git", "ls-files", "-u", "-z", filename] - code, output, error = await execute(command, cwd=path) + code, output, error = await self.__execute(command, cwd=path) if code != 0: raise subprocess.CalledProcessError( code, " ".join(command), output=output, stderr=error @@ -1351,7 +1372,9 @@ async def show(self, path, ref, filename=None, is_binary=False): else: command.append(f"{ref}:{filename}") - code, output, error = await execute(command, cwd=path, is_binary=is_binary) + code, output, error = await self.__execute( + command, cwd=path, is_binary=is_binary + ) error_messages = map( lambda n: n.lower(), @@ -1481,7 +1504,7 @@ async def _is_binary(self, filename, ref, path): "--", filename, ] # where 4b825... is a magic SHA which represents the empty tree - code, output, error = await execute(command, cwd=path) + code, output, error = await self.__execute(command, cwd=path) if code != 0: error_messages = map( @@ -1517,7 +1540,7 @@ async def remote_add(self, path, url, name=DEFAULT_REMOTE_NAME): Remote name; default "origin" """ cmd = ["git", "remote", "add", name, url] - code, _, error = await execute(cmd, cwd=path) + code, _, error = await self.__execute(cmd, cwd=path) response = {"code": code, "command": " ".join(cmd)} if code != 0: @@ -1540,7 +1563,7 @@ async def remote_show(self, path, verbose=False): else: command.append("show") - code, output, error = await execute(command, cwd=path) + code, output, error = await self.__execute(command, cwd=path) response = {"code": code, "command": " ".join(command)} if code == 0: @@ -1565,7 +1588,7 @@ async def remote_remove(self, path, name): """ command = ["git", "remote", "remove", name] - code, _, error = await execute(command, cwd=path) + code, _, error = await self.__execute(command, cwd=path) response = {"code": code, "command": " ".join(command)} if code != 0: @@ -1619,7 +1642,7 @@ async def version(self): If an error occurs, return None. """ command = ["git", "--version"] - code, output, _ = await execute(command, cwd=os.curdir) + code, output, _ = await self.__execute(command, cwd=os.curdir) if code == 0: version = GIT_VERSION_REGEX.match(output) if version is not None: @@ -1634,7 +1657,7 @@ async def tags(self, path): Git path repository """ command = ["git", "tag", "--list"] - code, output, error = await execute(command, cwd=path) + code, output, error = await self.__execute(command, cwd=path) if code != 0: return {"code": code, "command": " ".join(command), "message": error} tags = [tag for tag in output.split("\n") if len(tag) > 0] @@ -1649,7 +1672,7 @@ async def tag_checkout(self, path, tag): Tag to checkout """ command = ["git", "checkout", "tags/" + tag] - code, _, error = await execute(command, cwd=path) + code, _, error = await self.__execute(command, cwd=path) if code == 0: return {"code": code, "message": "Tag {} checked out".format(tag)} else: @@ -1798,7 +1821,7 @@ async def stash(self, path: str, stashMsg: str = "") -> dict: # if the git command is run in a non-interactive terminal, it will not prompt for user input env["GIT_TERMINAL_PROMPT"] = "0" - code, output, error = await execute(cmd, cwd=path, env=env) + code, output, error = await self.__execute(cmd, cwd=path, env=env) # code 0: no changes to stash if code != 0: @@ -1814,7 +1837,7 @@ async def stash_list(self, path: str) -> dict: env = os.environ.copy() env["GIT_TERMINAL_PROMPT"] = "0" - code, output, error = await execute(cmd, cwd=path, env=env) + code, output, error = await self.__execute(cmd, cwd=path, env=env) if code != 0: return {"code": code, "command": " ".join(cmd), "message": error} @@ -1833,7 +1856,7 @@ async def stash_show(self, path: str, index: int) -> dict: env = os.environ.copy() env["GIT_TERMINAL_PROMPT"] = "0" - code, output, error = await execute(cmd, cwd=path, env=env) + code, output, error = await self.__execute(cmd, cwd=path, env=env) if code != 0: return {"code": code, "command": " ".join(cmd), "message": error} @@ -1858,7 +1881,7 @@ async def pop_stash(self, path: str, stash_index: Optional[int] = None) -> dict: env = os.environ.copy() env["GIT_TERMINAL_PROMPT"] = "0" - code, output, error = await execute(cmd, cwd=path, env=env) + code, output, error = await self.__execute(cmd, cwd=path, env=env) if code != 0: return {"code": code, "command": " ".join(cmd), "message": error} @@ -1884,7 +1907,7 @@ async def drop_stash(self, path, stash_index: Optional[int] = None) -> dict: env = os.environ.copy() env["GIT_TERMINAL_PROMPT"] = "0" - code, output, error = await execute(cmd, cwd=path, env=env) + code, output, error = await self.__execute(cmd, cwd=path, env=env) if code != 0: return {"code": code, "command": " ".join(cmd), "message": error} @@ -1910,7 +1933,7 @@ async def apply_stash(self, path: str, stash_index: Optional[int] = None) -> dic env = os.environ.copy() env["GIT_TERMINAL_PROMPT"] = "0" - code, output, error = await execute(cmd, cwd=path, env=env) + code, output, error = await self.__execute(cmd, cwd=path, env=env) # error: if code != 0: diff --git a/jupyterlab_git/tests/test_branch.py b/jupyterlab_git/tests/test_branch.py index 7705556cf..c11e83ee1 100644 --- a/jupyterlab_git/tests/test_branch.py +++ b/jupyterlab_git/tests/test_branch.py @@ -40,6 +40,11 @@ async def test_get_current_branch_success(): mock_execute.assert_called_once_with( ["git", "symbolic-ref", "--short", "HEAD"], cwd=str(Path("/bin") / "test_curr_path"), + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, ) assert "feature-foo" == actual_response @@ -73,6 +78,11 @@ async def test_checkout_branch_noref_success(): mock_execute.assert_called_once_with( cmd, cwd=str(Path("/bin") / "test_curr_path"), + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, ) assert {"code": rc, "message": stdout_message} == actual_response @@ -108,6 +118,11 @@ async def test_checkout_branch_noref_failure(): mock_execute.assert_called_once_with( cmd, cwd=str(Path("/bin") / "test_curr_path"), + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, ) assert { @@ -149,6 +164,11 @@ async def test_checkout_branch_remoteref_success(): mock_execute.assert_called_once_with( cmd, cwd=str(Path("/bin") / "test_curr_path"), + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, ) assert {"code": rc, "message": stdout_message} == actual_response @@ -187,6 +207,11 @@ async def test_checkout_branch_headsref_failure(): mock_execute.assert_called_once_with( cmd, cwd=str(Path("/bin") / "test_curr_path"), + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, ) assert { "code": rc, @@ -223,6 +248,11 @@ async def test_checkout_branch_headsref_success(): mock_execute.assert_called_once_with( cmd, cwd=str(Path("/bin") / "test_curr_path"), + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, ) assert {"code": rc, "message": stdout_message} == actual_response @@ -258,6 +288,11 @@ async def test_checkout_branch_remoteref_failure(): mock_execute.assert_called_once_with( cmd, cwd=str(Path("/bin") / "test_curr_path"), + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, ) assert { "code": rc, @@ -285,6 +320,11 @@ async def test_get_branch_reference_success(): mock_execute.assert_called_once_with( ["git", "rev-parse", "--symbolic-full-name", branch], cwd=str(Path("/bin") / "test_curr_path"), + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, ) assert actual_response == reference @@ -315,6 +355,11 @@ async def test_get_branch_reference_failure(): mock_execute.assert_called_once_with( ["git", "rev-parse", "--symbolic-full-name", branch], cwd=str(Path("/bin") / "test_curr_path"), + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, ) assert actual_response is None @@ -339,6 +384,11 @@ async def test_get_current_branch_failure(): mock_execute.assert_called_once_with( ["git", "symbolic-ref", "--short", "HEAD"], cwd=str(Path("/bin") / "test_curr_path"), + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, ) assert ( "Error [fatal: Not a git repository (or any of the parent directories): .git] " @@ -368,6 +418,11 @@ async def test_get_current_branch_detached_success(): mock_execute.assert_called_once_with( ["git", "branch", "-a"], cwd=str(Path("/bin") / "test_curr_path"), + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, ) assert "(HEAD detached at origin/feature-foo)" == actual_response @@ -394,6 +449,11 @@ async def test_get_current_branch_detached_failure(): mock_execute.assert_called_once_with( ["git", "branch", "-a"], cwd=str(Path("/bin") / "test_curr_path"), + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, ) assert ( "Error [fatal: Not a git repository (or any of the parent directories): .git] " @@ -437,10 +497,20 @@ async def test_get_upstream_branch_success(branch, upstream, remotename): "{}@{{upstream}}".format(branch), ], cwd=str(Path("/bin") / "test_curr_path"), + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, ), call( ["git", "config", "--local", "branch.{}.remote".format(branch)], cwd=str(Path("/bin") / "test_curr_path"), + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, ), ], any_order=False, @@ -495,6 +565,11 @@ async def test_get_upstream_branch_failure(outputs, message): call( ["git", "rev-parse", "--abbrev-ref", "blah@{upstream}"], cwd=str(Path("/bin") / "test_curr_path"), + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, ) ], any_order=False, @@ -517,6 +592,11 @@ async def test_get_tag_success(): mock_execute.assert_called_once_with( ["git", "describe", "--tags", "abcdefghijklmnopqrstuvwxyz01234567890123"], cwd=str(Path("/bin") / "test_curr_path"), + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, ) assert "v0.3.0" == actual_response @@ -561,6 +641,11 @@ async def test_get_tag_failure(): call( ["git", "describe", "--tags", "blah"], cwd=str(Path("/bin") / "test_curr_path"), + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, ), call( [ @@ -570,6 +655,11 @@ async def test_get_tag_failure(): "01234567899999abcdefghijklmnopqrstuvwxyz", ], cwd=str(Path("/bin") / "test_curr_path"), + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, ), ], any_order=False, @@ -593,6 +683,11 @@ async def test_no_tags(): mock_execute.assert_called_once_with( ["git", "describe", "--tags", "768c79ad661598889f29bdf8916f4cc488f5062a"], cwd="/path/foo", + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, ) assert actual_response is None @@ -687,6 +782,11 @@ async def test_branch_success(): "refs/heads/", ], cwd=str(Path("/bin") / "test_curr_path"), + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, ), # call to get refs/remotes call( @@ -697,6 +797,11 @@ async def test_branch_success(): "refs/remotes/", ], cwd=str(Path("/bin") / "test_curr_path"), + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, ), ], any_order=False, @@ -735,6 +840,11 @@ async def test_branch_failure(): mock_execute.assert_called_once_with( expected_cmd, cwd=str(Path("/bin") / "test_curr_path"), + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, ) assert expected_response == actual_response @@ -820,16 +930,31 @@ async def test_branch_success_detached_head(): "refs/heads/", ], cwd=str(Path("/bin") / "test_curr_path"), + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, ), # call to get current branch call( ["git", "symbolic-ref", "--short", "HEAD"], cwd=str(Path("/bin") / "test_curr_path"), + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, ), # call to get current branch name given a detached head call( ["git", "branch", "-a"], cwd=str(Path("/bin") / "test_curr_path"), + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, ), # call to get refs/remotes call( @@ -840,6 +965,11 @@ async def test_branch_success_detached_head(): "refs/remotes/", ], cwd=str(Path("/bin") / "test_curr_path"), + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, ), ], any_order=False, diff --git a/jupyterlab_git/tests/test_clone.py b/jupyterlab_git/tests/test_clone.py index 562d5a3a5..dec064b95 100644 --- a/jupyterlab_git/tests/test_clone.py +++ b/jupyterlab_git/tests/test_clone.py @@ -27,7 +27,11 @@ async def test_git_clone_success(): mock_execute.assert_called_once_with( ["git", "clone", "ghjkhjkl"], cwd=str(Path("/bin") / "test_curr_path"), + timeout=20, env={"TEST": "test", "GIT_TERMINAL_PROMPT": "0"}, + username=None, + password=None, + is_binary=False, ) assert {"code": 0, "message": output} == actual_response @@ -55,7 +59,11 @@ def create_fake_git_repo(*args, **kwargs): mock_execute.assert_called_once_with( ["git", "clone", "--depth=1", "ghjkhjkl"], # to be update cwd=str(tmp_path), # to be udpated + timeout=20, env={"TEST": "test", "GIT_TERMINAL_PROMPT": "0"}, + username=None, + password=None, + is_binary=False, ) # Check the repository folder has been created @@ -83,7 +91,11 @@ async def test_git_submodules_success(tmp_path): mock_execute.assert_called_once_with( ["git", "clone", "--recurse-submodules", "ghjkhjkl"], cwd=str(Path("/bin") / "test_curr_path"), + timeout=20, env={"TEST": "test", "GIT_TERMINAL_PROMPT": "0"}, + username=None, + password=None, + is_binary=False, ) assert {"code": 0, "message": output} == actual_response @@ -111,7 +123,11 @@ async def test_git_clone_failure_from_git(): mock_execute.assert_called_once_with( ["git", "clone", "ghjkhjkl"], cwd=str(Path("/bin") / "test_curr_path"), + timeout=20, env={"TEST": "test", "GIT_TERMINAL_PROMPT": "0"}, + username=None, + password=None, + is_binary=False, ) assert { "code": 128, @@ -136,10 +152,12 @@ async def test_git_clone_with_auth_success(): # Then mock_authentication.assert_called_once_with( ["git", "clone", "ghjkhjkl", "-q"], - username="asdf", - password="qwerty", cwd=str(Path("/bin") / "test_curr_path"), + timeout=20, env={"TEST": "test", "GIT_TERMINAL_PROMPT": "1"}, + username="asdf", + password="qwerty", + is_binary=False, ) assert {"code": 0, "message": output} == actual_response @@ -167,10 +185,12 @@ async def test_git_clone_with_auth_wrong_repo_url_failure_from_git(): # Then mock_authentication.assert_called_once_with( ["git", "clone", "ghjkhjkl", "-q"], - username="asdf", - password="qwerty", cwd=str(Path("/bin") / "test_curr_path"), + timeout=20, env={"TEST": "test", "GIT_TERMINAL_PROMPT": "1"}, + username="asdf", + password="qwerty", + is_binary=False, ) assert { "code": 128, @@ -205,10 +225,12 @@ async def test_git_clone_with_auth_auth_failure_from_git(): # Then mock_authentication.assert_called_once_with( ["git", "clone", "ghjkhjkl", "-q"], - username="asdf", - password="qwerty", cwd=str(Path("/bin") / "test_curr_path"), + timeout=20, env={"TEST": "test", "GIT_TERMINAL_PROMPT": "1"}, + username="asdf", + password="qwerty", + is_binary=False, ) assert { "code": 128, @@ -249,7 +271,15 @@ async def test_git_clone_with_auth_and_cache_credentials(): assert mock_execute.call_count == 3 mock_execute.assert_has_calls( [ - call(["git", "config", "--list"], cwd=test_path), + call( + ["git", "config", "--list"], + cwd=test_path, + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, + ), call( [ "git", @@ -259,13 +289,20 @@ async def test_git_clone_with_auth_and_cache_credentials(): credential_helper, ], cwd=test_path, + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, ), call( ["git", "clone", "ghjkhjkl", "-q"], - username="asdf", - password="qwerty", cwd=test_path, + timeout=20, env={**os.environ, "GIT_TERMINAL_PROMPT": "1"}, + username="asdf", + password="qwerty", + is_binary=False, ), ] ) @@ -293,13 +330,23 @@ async def test_git_clone_with_auth_and_cache_credentials_and_existing_credential assert mock_execute.call_count == 2 mock_execute.assert_has_calls( [ - call(["git", "config", "--list"], cwd=test_path), + call( + ["git", "config", "--list"], + cwd=test_path, + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, + ), call( ["git", "clone", "ghjkhjkl", "-q"], - username="asdf", - password="qwerty", cwd=test_path, + timeout=20, env={**os.environ, "GIT_TERMINAL_PROMPT": "1"}, + username="asdf", + password="qwerty", + is_binary=False, ), ] ) diff --git a/jupyterlab_git/tests/test_config.py b/jupyterlab_git/tests/test_config.py index 4c047ed03..b159cdff7 100644 --- a/jupyterlab_git/tests/test_config.py +++ b/jupyterlab_git/tests/test_config.py @@ -21,7 +21,13 @@ async def test_git_get_config_success(mock_execute, jp_fetch, jp_root_dir): # Then mock_execute.assert_called_once_with( - ["git", "config", "--list"], cwd=str(local_path) + ["git", "config", "--list"], + cwd=str(local_path), + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, ) assert response.code == 201 @@ -60,7 +66,13 @@ async def test_git_get_config_multiline(mock_execute, jp_fetch, jp_root_dir): # Then mock_execute.assert_called_once_with( - ["git", "config", "--list"], cwd=str(local_path) + ["git", "config", "--list"], + cwd=str(local_path), + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, ) assert response.code == 201 @@ -103,7 +115,13 @@ async def test_git_get_config_accepted_multiline(mock_execute, jp_fetch, jp_root # Then mock_execute.assert_called_once_with( - ["git", "config", "--list"], cwd=str(local_path) + ["git", "config", "--list"], + cwd=str(local_path), + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, ) assert response.code == 201 @@ -145,10 +163,20 @@ async def test_git_set_config_success(mock_execute, jp_fetch, jp_root_dir): call( ["git", "config", "--add", "user.email", "john.snow@iscoming.com"], cwd=str(local_path), + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, ), call( ["git", "config", "--add", "user.name", "John Snow"], cwd=str(local_path), + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, ), ], any_order=True, diff --git a/jupyterlab_git/tests/test_detailed_log.py b/jupyterlab_git/tests/test_detailed_log.py index 3c2f655d1..d7c7d38e6 100644 --- a/jupyterlab_git/tests/test_detailed_log.py +++ b/jupyterlab_git/tests/test_detailed_log.py @@ -111,6 +111,11 @@ async def test_detailed_log(): "f29660a2472e24164906af8653babeb48e4bf2ab", ], cwd=str(Path("/bin") / "test_curr_path"), + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, ) assert expected_response == actual_response diff --git a/jupyterlab_git/tests/test_diff.py b/jupyterlab_git/tests/test_diff.py index fde6651eb..8b1e8dcad 100644 --- a/jupyterlab_git/tests/test_diff.py +++ b/jupyterlab_git/tests/test_diff.py @@ -42,6 +42,11 @@ async def test_changed_files_single_commit(): "-z", ], cwd="test-path", + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, ) assert {"code": 0, "files": ["file1.ipynb", "file2.py"]} == actual_response @@ -61,6 +66,11 @@ async def test_changed_files_working_tree(): mock_execute.assert_called_once_with( ["git", "diff", "HEAD", "--name-only", "-z"], cwd="test-path", + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, ) assert {"code": 0, "files": ["file1.ipynb", "file2.py"]} == actual_response @@ -80,6 +90,11 @@ async def test_changed_files_index(): mock_execute.assert_called_once_with( ["git", "diff", "--staged", "HEAD", "--name-only", "-z"], cwd="test-path", + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, ) assert {"code": 0, "files": ["file1.ipynb", "file2.py"]} == actual_response @@ -99,6 +114,11 @@ async def test_changed_files_two_commits(): mock_execute.assert_called_once_with( ["git", "diff", "HEAD", "origin/HEAD", "--name-only", "-z"], cwd="test-path", + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, ) assert {"code": 0, "files": ["file1.ipynb", "file2.py"]} == actual_response @@ -118,6 +138,11 @@ async def test_changed_files_git_diff_error(): mock_execute.assert_called_once_with( ["git", "diff", "HEAD", "origin/HEAD", "--name-only", "-z"], cwd="test-path", + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, ) assert {"code": 128, "message": "error message"} == actual_response @@ -229,7 +254,15 @@ async def test_is_binary_file(args, cli_result, cmd, expected): actual_response = await Git()._is_binary(*args) # Then - mock_execute.assert_called_once_with(cmd, cwd="/bin") + mock_execute.assert_called_once_with( + cmd, + cwd="/bin", + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, + ) assert actual_response == expected diff --git a/jupyterlab_git/tests/test_execute.py b/jupyterlab_git/tests/test_execute.py index 0e6d99403..30cb37a92 100644 --- a/jupyterlab_git/tests/test_execute.py +++ b/jupyterlab_git/tests/test_execute.py @@ -19,7 +19,7 @@ async def remove_lock_file(*args): assert "unlock" in repr(execution_lock) cmd = ["git", "dummy"] - kwargs = {"cwd": "{!s}".format(tmp_path)} + kwargs = {"cwd": "{!s}".format(tmp_path), "timeout": 20} await execute(cmd, **kwargs) assert "unlock" in repr(execution_lock) diff --git a/jupyterlab_git/tests/test_fetch.py b/jupyterlab_git/tests/test_fetch.py index 5265d610f..2f7454609 100644 --- a/jupyterlab_git/tests/test_fetch.py +++ b/jupyterlab_git/tests/test_fetch.py @@ -22,7 +22,11 @@ async def test_git_fetch_success(): mock_execute.assert_called_once_with( ["git", "fetch", "--all", "--prune"], cwd="test_path", + timeout=20, env={**os.environ, "GIT_TERMINAL_PROMPT": "0"}, + username=None, + password=None, + is_binary=False, ) assert {"code": 0} == actual_response @@ -40,7 +44,11 @@ async def test_git_fetch_fail(): mock_execute.assert_called_once_with( ["git", "fetch", "--all", "--prune"], cwd="test_path", + timeout=20, env={**os.environ, "GIT_TERMINAL_PROMPT": "0"}, + username=None, + password=None, + is_binary=False, ) assert { "code": 1, @@ -64,10 +72,12 @@ async def test_git_fetch_with_auth_success(): # Then mock_execute.assert_called_once_with( ["git", "fetch", "--all", "--prune"], - username="test_user", - password="test_pass", cwd="test_path", + timeout=20, env={**os.environ, "GIT_TERMINAL_PROMPT": "1"}, + username="test_user", + password="test_pass", + is_binary=False, ) assert {"code": 0} == actual_response @@ -93,10 +103,12 @@ async def test_git_fetch_with_auth_fail(): # Then mock_execute.assert_called_once_with( ["git", "fetch", "--all", "--prune"], - username="test_user", - password="test_pass", cwd="test_path", + timeout=20, env={**os.environ, "GIT_TERMINAL_PROMPT": "1"}, + username="test_user", + password="test_pass", + is_binary=False, ) assert { "code": 128, @@ -136,7 +148,15 @@ async def test_git_fetch_with_auth_and_cache_credentials(): assert mock_execute.call_count == 3 mock_execute.assert_has_calls( [ - call(["git", "config", "--list"], cwd=test_path), + call( + ["git", "config", "--list"], + cwd=test_path, + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, + ), call( [ "git", @@ -146,13 +166,20 @@ async def test_git_fetch_with_auth_and_cache_credentials(): credential_helper, ], cwd=test_path, + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, ), call( ["git", "fetch", "--all", "--prune"], - username="test_user", - password="test_pass", cwd=test_path, + timeout=20, env={**os.environ, "GIT_TERMINAL_PROMPT": "1"}, + username="test_user", + password="test_pass", + is_binary=False, ), ] ) @@ -184,13 +211,23 @@ async def test_git_fetch_with_auth_and_cache_credentials_and_existing_credential assert mock_execute.call_count == 2 mock_execute.assert_has_calls( [ - call(["git", "config", "--list"], cwd=test_path), + call( + ["git", "config", "--list"], + cwd=test_path, + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, + ), call( ["git", "fetch", "--all", "--prune"], - username="test_user", - password="test_pass", cwd=test_path, + timeout=20, env={**os.environ, "GIT_TERMINAL_PROMPT": "1"}, + username="test_user", + password="test_pass", + is_binary=False, ), ] ) diff --git a/jupyterlab_git/tests/test_handlers.py b/jupyterlab_git/tests/test_handlers.py index 7aa9b0d66..212ef7894 100644 --- a/jupyterlab_git/tests/test_handlers.py +++ b/jupyterlab_git/tests/test_handlers.py @@ -102,6 +102,11 @@ async def test_git_show_prefix(mock_execute, jp_fetch, jp_root_dir): call( ["git", "rev-parse", "--show-prefix"], cwd=str(local_path / "subfolder"), + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, ), ] ) @@ -151,6 +156,11 @@ async def test_git_show_prefix_not_a_git_repo(mock_execute, jp_fetch, jp_root_di call( ["git", "rev-parse", "--show-prefix"], cwd=str(local_path / "subfolder"), + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, ), ] ) @@ -183,6 +193,11 @@ async def test_git_show_top_level(mock_execute, jp_fetch, jp_root_dir): call( ["git", "rev-parse", "--show-toplevel"], cwd=str(local_path / "subfolder"), + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, ), ] ) @@ -215,6 +230,11 @@ async def test_git_show_top_level_not_a_git_repo(mock_execute, jp_fetch, jp_root call( ["git", "rev-parse", "--show-toplevel"], cwd=str(local_path / "subfolder"), + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, ), ] ) @@ -689,10 +709,19 @@ async def test_content(mock_execute, jp_fetch, jp_root_dir): filename, ], cwd=str(local_path), + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, ), call( ["git", "show", "{}:{}".format("previous", filename)], cwd=str(local_path), + timeout=20, + env=None, + username=None, + password=None, is_binary=False, ), ] @@ -803,10 +832,19 @@ async def test_content_index(mock_execute, jp_fetch, jp_root_dir): filename, ], cwd=str(local_path), + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, ), call( ["git", "show", "{}:{}".format("", filename)], cwd=str(local_path), + timeout=20, + env=None, + username=None, + password=None, is_binary=False, ), ], @@ -852,10 +890,19 @@ async def test_content_base(mock_execute, jp_fetch, jp_root_dir): call( ["git", "ls-files", "-u", "-z", filename], cwd=str(local_path), + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, ), call( ["git", "show", "915bb14609daab65e5304e59d89c626283ae49fc"], cwd=str(local_path), + timeout=20, + env=None, + username=None, + password=None, is_binary=False, ), ] @@ -950,10 +997,19 @@ async def test_content_binary(mock_execute, jp_fetch, jp_root_dir): filename, ], cwd=str(local_path), + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, ), call( ["git", "show", "{}:{}".format("current", filename)], cwd=str(local_path), + timeout=20, + env=None, + username=None, + password=None, is_binary=True, ), ] diff --git a/jupyterlab_git/tests/test_init.py b/jupyterlab_git/tests/test_init.py index 512cb447b..6b8e5c64e 100644 --- a/jupyterlab_git/tests/test_init.py +++ b/jupyterlab_git/tests/test_init.py @@ -17,7 +17,15 @@ async def test_init(): # When actual_response = await Git().init("test_curr_path") - mock_execute.assert_called_once_with(["git", "init"], cwd="test_curr_path") + mock_execute.assert_called_once_with( + ["git", "init"], + cwd="test_curr_path", + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, + ) assert {"code": 0, "actions": None} == actual_response @@ -36,7 +44,15 @@ async def test_init_and_post_init(): JupyterLabGit(actions={"post_init": ['echo "hello"']}), ).init("test_curr_path") - mock_execute.assert_called_with(["echo", "hello"], cwd="test_curr_path") + mock_execute.assert_called_with( + ["echo", "hello"], + cwd="test_curr_path", + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, + ) assert { "code": 0, @@ -60,7 +76,15 @@ async def test_init_and_post_init_fail(): JupyterLabGit(actions={"post_init": ["not_there arg"]}), ).init("test_curr_path") - mock_execute.assert_called_with(["not_there", "arg"], cwd="test_curr_path") + mock_execute.assert_called_with( + ["not_there", "arg"], + cwd="test_curr_path", + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, + ) assert { "code": 1, @@ -91,7 +115,15 @@ async def test_init_and_post_init_fail_to_run(): JupyterLabGit(actions={"post_init": ["not_there arg"]}), ).init("test_curr_path") - mock_execute.assert_called_with(["not_there", "arg"], cwd="test_curr_path") + mock_execute.assert_called_with( + ["not_there", "arg"], + cwd="test_curr_path", + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, + ) assert { "code": 1, diff --git a/jupyterlab_git/tests/test_integrations.py b/jupyterlab_git/tests/test_integrations.py index f1bfa2f11..639b835ed 100644 --- a/jupyterlab_git/tests/test_integrations.py +++ b/jupyterlab_git/tests/test_integrations.py @@ -42,13 +42,16 @@ async def test_git_show_prefix_symlink( assert (jp_root_dir / local_repo).exists() # When - response = await jp_fetch( - "git", - local_repo, - "show_prefix", - body="{}", - method="POST", - ) + try: + response = await jp_fetch( + "git", + local_repo, + "show_prefix", + body="{}", + method="POST", + ) + except Exception as e: + print(str(e)) # Then assert response.code == 200 diff --git a/jupyterlab_git/tests/test_pushpull.py b/jupyterlab_git/tests/test_pushpull.py index a1a896b92..2ef32e546 100644 --- a/jupyterlab_git/tests/test_pushpull.py +++ b/jupyterlab_git/tests/test_pushpull.py @@ -25,7 +25,11 @@ async def test_git_pull_fail(): mock_execute.assert_called_once_with( ["git", "pull", "--no-commit"], cwd="test_curr_path", + timeout=20, env={"TEST": "test", "GIT_TERMINAL_PROMPT": "0"}, + username=None, + password=None, + is_binary=False, ) assert {"code": 1, "message": "Authentication failed"} == actual_response @@ -52,7 +56,11 @@ async def test_git_pull_with_conflict_fail(): call( ["git", "pull", "--no-commit"], cwd="test_curr_path", + timeout=20, env={"TEST": "test", "GIT_TERMINAL_PROMPT": "0"}, + username=None, + password=None, + is_binary=False, ) ] ) @@ -82,10 +90,12 @@ async def test_git_pull_with_auth_fail(): # Then mock_execute_with_authentication.assert_called_once_with( ["git", "pull", "--no-commit"], - username="asdf", - password="qwerty", cwd="test_curr_path", + timeout=20, env={"TEST": "test", "GIT_TERMINAL_PROMPT": "1"}, + username="asdf", + password="qwerty", + is_binary=False, ) assert { "code": 1, @@ -108,7 +118,11 @@ async def test_git_pull_success(): mock_execute.assert_called_once_with( ["git", "pull", "--no-commit"], cwd="test_curr_path", + timeout=20, env={"TEST": "test", "GIT_TERMINAL_PROMPT": "0"}, + username=None, + password=None, + is_binary=False, ) assert {"code": 0, "message": output} == actual_response @@ -130,10 +144,12 @@ async def test_git_pull_with_auth_success(): # Then mock_execute_with_authentication.assert_called_once_with( ["git", "pull", "--no-commit"], - username="asdf", - password="qwerty", cwd="test_curr_path", + timeout=20, env={"TEST": "test", "GIT_TERMINAL_PROMPT": "1"}, + username="asdf", + password="qwerty", + is_binary=False, ) assert {"code": 0, "message": output} == actual_response @@ -161,9 +177,11 @@ async def test_git_pull_with_auth_success_and_conflict_fail(): call( ["git", "pull", "--no-commit"], cwd="test_curr_path", + timeout=20, env={"TEST": "test", "GIT_TERMINAL_PROMPT": "1"}, username="asdf", password="qwerty", + is_binary=False, ) ] ) @@ -201,6 +219,11 @@ async def test_git_pull_with_auth_and_cache_credentials(): call( ["git", "config", "--list"], cwd=test_path, + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, ), call( [ @@ -211,13 +234,20 @@ async def test_git_pull_with_auth_and_cache_credentials(): credential_helper, ], cwd=test_path, + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, ), call( ["git", "pull", "--no-commit"], - username="user", - password="pass", cwd=test_path, + timeout=20, env={**os.environ, "GIT_TERMINAL_PROMPT": "1"}, + username="user", + password="pass", + is_binary=False, ), ] ) @@ -247,13 +277,20 @@ async def test_git_pull_with_auth_and_cache_credentials_and_existing_credential_ call( ["git", "config", "--list"], cwd=test_path, + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, ), call( ["git", "pull", "--no-commit"], - username="user", - password="pass", cwd=test_path, + timeout=20, env={**os.environ, "GIT_TERMINAL_PROMPT": "1"}, + username="user", + password="pass", + is_binary=False, ), ] ) @@ -278,7 +315,11 @@ async def test_git_push_fail(): mock_execute.assert_called_once_with( ["git", "push", "test_origin", "HEAD:test_master"], cwd="test_curr_path", + timeout=20, env={"TEST": "test", "GIT_TERMINAL_PROMPT": "0"}, + username=None, + password=None, + is_binary=False, ) assert {"code": 1, "message": "Authentication failed"} == actual_response @@ -305,10 +346,12 @@ async def test_git_push_with_auth_fail(): # Then mock_execute_with_authentication.assert_called_once_with( ["git", "push", "test_origin", "HEAD:test_master"], - username="asdf", - password="qwerty", cwd="test_curr_path", + timeout=20, env={"TEST": "test", "GIT_TERMINAL_PROMPT": "1"}, + username="asdf", + password="qwerty", + is_binary=False, ) assert { "code": 1, @@ -333,7 +376,11 @@ async def test_git_push_success(): mock_execute.assert_called_once_with( ["git", "push", ".", "HEAD:test_master"], cwd="test_curr_path", + timeout=20, env={"TEST": "test", "GIT_TERMINAL_PROMPT": "0"}, + username=None, + password=None, + is_binary=False, ) assert {"code": 0, "message": output} == actual_response @@ -357,10 +404,12 @@ async def test_git_push_with_auth_success(): # Then mock_execute_with_authentication.assert_called_once_with( ["git", "push", ".", "HEAD:test_master"], - username="asdf", - password="qwerty", cwd="test_curr_path", + timeout=20, env={"TEST": "test", "GIT_TERMINAL_PROMPT": "1"}, + username="asdf", + password="qwerty", + is_binary=False, ) assert {"code": 0, "message": output} == actual_response @@ -395,6 +444,11 @@ async def test_git_push_with_auth_and_cache_credentials(): call( ["git", "config", "--list"], cwd=test_path, + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, ), call( [ @@ -405,13 +459,20 @@ async def test_git_push_with_auth_and_cache_credentials(): credential_helper, ], cwd=test_path, + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, ), call( ["git", "push", ".", "HEAD:test_master"], - username="user", - password="pass", cwd=test_path, + timeout=20, env={**os.environ, "GIT_TERMINAL_PROMPT": "1"}, + username="user", + password="pass", + is_binary=False, ), ] ) @@ -443,13 +504,20 @@ async def test_git_push_with_auth_and_cache_credentials_and_existing_credential_ call( ["git", "config", "--list"], cwd=test_path, + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, ), call( ["git", "push", ".", "HEAD:test_master"], - username="user", - password="pass", cwd=test_path, + timeout=20, env={**os.environ, "GIT_TERMINAL_PROMPT": "1"}, + username="user", + password="pass", + is_binary=False, ), ] ) diff --git a/jupyterlab_git/tests/test_remote.py b/jupyterlab_git/tests/test_remote.py index 8e5ccc335..fe439bd09 100644 --- a/jupyterlab_git/tests/test_remote.py +++ b/jupyterlab_git/tests/test_remote.py @@ -31,7 +31,15 @@ async def test_git_add_remote_success_no_name(mock_execute, jp_fetch, jp_root_di # Then command = ["git", "remote", "add", "origin", url] - mock_execute.assert_called_once_with(command, cwd=str(local_path)) + mock_execute.assert_called_once_with( + command, + cwd=str(local_path), + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, + ) assert response.code == 201 payload = json.loads(response.body) @@ -62,7 +70,15 @@ async def test_git_add_remote_success(mock_execute, jp_fetch, jp_root_dir): # Then command = ["git", "remote", "add", name, url] - mock_execute.assert_called_once_with(command, cwd=str(local_path)) + mock_execute.assert_called_once_with( + command, + cwd=str(local_path), + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, + ) assert response.code == 201 payload = json.loads(response.body) @@ -99,7 +115,13 @@ async def test_git_add_remote_failure(mock_execute, jp_fetch, jp_root_dir): # Then mock_execute.assert_called_once_with( - ["git", "remote", "add", "origin", url], cwd=str(local_path) + ["git", "remote", "add", "origin", url], + cwd=str(local_path), + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, ) @@ -116,7 +138,15 @@ async def test_git_remote_show(mock_execute, jp_root_dir): # Then command = ["git", "remote", "show"] - mock_execute.assert_called_once_with(command, cwd=str(local_path)) + mock_execute.assert_called_once_with( + command, + cwd=str(local_path), + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, + ) assert output == { "code": 0, "command": " ".join(command), @@ -145,7 +175,15 @@ async def test_git_remote_show_verbose(mock_execute, jp_fetch, jp_root_dir): # Then command = ["git", "remote", "-v", "show"] - mock_execute.assert_called_once_with(command, cwd=str(local_path)) + mock_execute.assert_called_once_with( + command, + cwd=str(local_path), + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, + ) assert response.code == 200 payload = json.loads(response.body) @@ -176,6 +214,14 @@ async def test_git_remote_remove(mock_execute, jp_fetch, jp_root_dir): # Then command = ["git", "remote", "remove", name] - mock_execute.assert_called_once_with(command, cwd=str(local_path)) + mock_execute.assert_called_once_with( + command, + cwd=str(local_path), + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, + ) assert response.code == 204 diff --git a/jupyterlab_git/tests/test_settings.py b/jupyterlab_git/tests/test_settings.py index 94b9767b3..36707379e 100644 --- a/jupyterlab_git/tests/test_settings.py +++ b/jupyterlab_git/tests/test_settings.py @@ -24,7 +24,15 @@ async def test_git_get_settings_success(mock_execute, jp_fetch): ) # Then - mock_execute.assert_called_once_with(["git", "--version"], cwd=".") + mock_execute.assert_called_once_with( + ["git", "--version"], + cwd=".", + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, + ) assert response.code == 200 payload = json.loads(response.body) @@ -49,7 +57,15 @@ async def test_git_get_settings_no_git(mock_execute, jp_fetch): ) # Then - mock_execute.assert_called_once_with(["git", "--version"], cwd=".") + mock_execute.assert_called_once_with( + ["git", "--version"], + cwd=".", + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, + ) assert response.code == 200 payload = json.loads(response.body) @@ -72,7 +88,15 @@ async def test_git_get_settings_no_jlab(mock_execute, jp_fetch): response = await jp_fetch(NAMESPACE, "settings", method="GET") # Then - mock_execute.assert_called_once_with(["git", "--version"], cwd=".") + mock_execute.assert_called_once_with( + ["git", "--version"], + cwd=".", + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, + ) assert response.code == 200 payload = json.loads(response.body) diff --git a/jupyterlab_git/tests/test_single_file_log.py b/jupyterlab_git/tests/test_single_file_log.py index 86130ac85..adec43998 100644 --- a/jupyterlab_git/tests/test_single_file_log.py +++ b/jupyterlab_git/tests/test_single_file_log.py @@ -90,6 +90,11 @@ async def test_single_file_log(): "folder/test.txt", ], cwd=str(Path("/bin") / "test_curr_path"), + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, ) assert expected_response == actual_response diff --git a/jupyterlab_git/tests/test_stash.py b/jupyterlab_git/tests/test_stash.py index cb46c372d..60b7424b6 100644 --- a/jupyterlab_git/tests/test_stash.py +++ b/jupyterlab_git/tests/test_stash.py @@ -31,7 +31,15 @@ async def test_git_stash_without_message(mock_execute, jp_fetch, jp_root_dir): # Then command = ["git", "stash"] # Checks that the mock function was called with the correct arguments - mock_execute.assert_called_once_with(command, cwd=str(local_path), env=env) + mock_execute.assert_called_once_with( + command, + cwd=str(local_path), + timeout=20, + env=env, + username=None, + password=None, + is_binary=False, + ) assert response.code == 201 # json.loads turns a string into a dictionary @@ -63,7 +71,15 @@ async def test_git_stash_failure(mock_execute, jp_fetch, jp_root_dir): # Then command = ["git", "stash"] - mock_execute.assert_called_once_with(command, cwd=str(local_path), env=env) + mock_execute.assert_called_once_with( + command, + cwd=str(local_path), + timeout=20, + env=env, + username=None, + password=None, + is_binary=False, + ) @patch("jupyterlab_git.git.execute") @@ -88,7 +104,15 @@ async def test_git_stash_with_message(mock_execute, jp_fetch, jp_root_dir): # Then command = ["git", "stash", "save", "-m", stash_message] - mock_execute.assert_called_once_with(command, cwd=str(local_path), env=env) + mock_execute.assert_called_once_with( + command, + cwd=str(local_path), + timeout=20, + env=env, + username=None, + password=None, + is_binary=False, + ) assert response.code == 201 payload = json.loads(response.body) @@ -126,7 +150,15 @@ async def test_git_stash_show_with_index(mock_execute, jp_fetch, jp_root_dir): f"stash@{{{stash_index!s}}}", "--name-only", ] - mock_execute.assert_called_once_with(command, cwd=str(local_path), env=env) + mock_execute.assert_called_once_with( + command, + cwd=str(local_path), + timeout=20, + env=env, + username=None, + password=None, + is_binary=False, + ) assert response.code == 200 payload = json.loads(response.body) @@ -156,7 +188,15 @@ async def test_git_stash_show_without_index(mock_execute, jp_fetch, jp_root_dir) # Then command = ["git", "stash", "list"] - mock_execute.assert_called_once_with(command, cwd=str(local_path), env=env) + mock_execute.assert_called_once_with( + command, + cwd=str(local_path), + timeout=20, + env=env, + username=None, + password=None, + is_binary=False, + ) assert response.code == 200 payload = json.loads(response.body) @@ -199,7 +239,15 @@ async def test_git_stash_show_failure(mock_execute, jp_fetch, jp_root_dir): "--name-only", ] - mock_execute.assert_called_once_with(command, cwd=str(local_path), env=env) + mock_execute.assert_called_once_with( + command, + cwd=str(local_path), + timeout=20, + env=env, + username=None, + password=None, + is_binary=False, + ) # Git Stash - DELETE @@ -226,7 +274,15 @@ async def test_git_drop_stash_single_success(mock_execute, jp_fetch, jp_root_dir # Then command = ["git", "stash", "drop", str(stash_index)] - mock_execute.assert_called_once_with(command, cwd=str(local_path), env=env) + mock_execute.assert_called_once_with( + command, + cwd=str(local_path), + timeout=20, + env=env, + username=None, + password=None, + is_binary=False, + ) assert response.code == 204 @@ -257,7 +313,15 @@ async def test_git_drop_stash_single_failure(mock_execute, jp_fetch, jp_root_dir assert_http_error(e, 500) command = ["git", "stash", "drop", str(stash_index)] - mock_execute.assert_called_once_with(command, cwd=str(local_path), env=env) + mock_execute.assert_called_once_with( + command, + cwd=str(local_path), + timeout=20, + env=env, + username=None, + password=None, + is_binary=False, + ) @patch("jupyterlab_git.git.execute") @@ -280,7 +344,15 @@ async def test_git_drop_stash_all_success(mock_execute, jp_fetch, jp_root_dir): # Then command = ["git", "stash", "clear"] - mock_execute.assert_called_once_with(command, cwd=str(local_path), env=env) + mock_execute.assert_called_once_with( + command, + cwd=str(local_path), + timeout=20, + env=env, + username=None, + password=None, + is_binary=False, + ) assert response.code == 204 @@ -308,7 +380,15 @@ async def test_git_apply_stash_with_index(mock_execute, jp_fetch, jp_root_dir): # Then command = ["git", "stash", "apply", "stash@{" + str(stash_index) + "}"] - mock_execute.assert_called_once_with(command, cwd=str(local_path), env=env) + mock_execute.assert_called_once_with( + command, + cwd=str(local_path), + timeout=20, + env=env, + username=None, + password=None, + is_binary=False, + ) assert response.code == 201 @@ -330,7 +410,15 @@ async def test_git_apply_stash_without_index(mock_execute, jp_fetch, jp_root_dir # Then command = ["git", "stash", "apply"] - mock_execute.assert_called_once_with(command, cwd=str(local_path), env=env) + mock_execute.assert_called_once_with( + command, + cwd=str(local_path), + timeout=20, + env=env, + username=None, + password=None, + is_binary=False, + ) assert response.code == 201 @@ -362,7 +450,15 @@ async def test_git_apply_stash_failure(mock_execute, jp_fetch, jp_root_dir): command = ["git", "stash", "apply", "stash@{" + str(stash_index) + "}"] - mock_execute.assert_called_once_with(command, cwd=str(local_path), env=env) + mock_execute.assert_called_once_with( + command, + cwd=str(local_path), + timeout=20, + env=env, + username=None, + password=None, + is_binary=False, + ) # Git Stash Pop @@ -385,7 +481,15 @@ async def test_git_pop_stash_with_index(mock_execute, jp_fetch, jp_root_dir): ) # Then command = ["git", "stash", "pop", str(stash_index)] - mock_execute.assert_called_once_with(command, cwd=str(local_path), env=env) + mock_execute.assert_called_once_with( + command, + cwd=str(local_path), + timeout=20, + env=env, + username=None, + password=None, + is_binary=False, + ) assert response.code == 204 @@ -409,7 +513,15 @@ async def test_git_pop_stash_without_index(mock_execute, jp_fetch, jp_root_dir): ) # Then command = ["git", "stash", "pop"] - mock_execute.assert_called_once_with(command, cwd=str(local_path), env=env) + mock_execute.assert_called_once_with( + command, + cwd=str(local_path), + timeout=20, + env=env, + username=None, + password=None, + is_binary=False, + ) assert response.code == 204 @@ -441,4 +553,12 @@ async def test_git_pop_stash_failure(mock_execute, jp_fetch, jp_root_dir): command = ["git", "stash", "pop", str(stash_index)] - mock_execute.assert_called_once_with(command, cwd=str(local_path), env=env) + mock_execute.assert_called_once_with( + command, + cwd=str(local_path), + timeout=20, + env=env, + username=None, + password=None, + is_binary=False, + ) diff --git a/jupyterlab_git/tests/test_status.py b/jupyterlab_git/tests/test_status.py index e0ca02d59..146503aa8 100644 --- a/jupyterlab_git/tests/test_status.py +++ b/jupyterlab_git/tests/test_status.py @@ -183,6 +183,11 @@ async def test_status(output, diff_output, expected): call( ["git", "status", "--porcelain", "-b", "-u", "-z"], cwd=repository, + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, ), call( [ @@ -194,6 +199,11 @@ async def test_status(output, diff_output, expected): "4b825dc642cb6eb9a060e54bf8d69288fbee4904", ], cwd=repository, + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, ), ] ) diff --git a/jupyterlab_git/tests/test_tag.py b/jupyterlab_git/tests/test_tag.py index 650d3f080..7503aec03 100644 --- a/jupyterlab_git/tests/test_tag.py +++ b/jupyterlab_git/tests/test_tag.py @@ -21,6 +21,11 @@ async def test_git_tag_success(): mock_execute.assert_called_once_with( ["git", "tag", "--list"], cwd="test_curr_path", + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, ) assert {"code": 0, "tags": [tag]} == actual_response @@ -41,6 +46,11 @@ async def test_git_tag_checkout_success(): mock_execute.assert_called_once_with( ["git", "checkout", "tags/{}".format(tag)], cwd="test_curr_path", + timeout=20, + env=None, + username=None, + password=None, + is_binary=False, ) assert {