From 435f67deaa41802bd2b86667781c8fa278b852ae Mon Sep 17 00:00:00 2001 From: karajan1001 Date: Fri, 15 Apr 2022 13:02:54 +0800 Subject: [PATCH 1/4] Update on push_refspec and fetch_refspec (#58) fix: #58 1. Unify the API of `push_refspec` and `fetch_refspec`. 2. Can push multi `refspec` for one time. 3. No repository Error handle for `fetch_refspec` 4. Now the `push_refspec` and `fetch_refspec` will return the status for each refspec. Co-authored-by: --- scmrepo/git/backend/dulwich/__init__.py | 130 +++++++++++++----------- tests/test_git.py | 89 +++++++++++----- 2 files changed, 138 insertions(+), 81 deletions(-) diff --git a/scmrepo/git/backend/dulwich/__init__.py b/scmrepo/git/backend/dulwich/__init__.py index d09237c3..b3a308a6 100644 --- a/scmrepo/git/backend/dulwich/__init__.py +++ b/scmrepo/git/backend/dulwich/__init__.py @@ -3,6 +3,7 @@ import logging import os import stat +from enum import Enum from functools import partial from io import BytesIO, StringIO from typing import ( @@ -37,6 +38,13 @@ logger = logging.getLogger(__name__) +class SyncStatus(Enum): + SUCCESS = 0 + DUPLICATED = 1 + DIVERGED = 2 + FAILED = 3 + + class DulwichObject(GitObject): def __init__(self, repo, name, mode, sha): self.repo = repo @@ -491,23 +499,20 @@ def get_refs_containing(self, rev: str, pattern: Optional[str] = None): def push_refspec( self, url: str, - src: Optional[str], - dest: str, + refspecs: Union[str, Iterable[str]], force: bool = False, - on_diverged: Optional[Callable[[str, str], bool]] = None, progress: Callable[["GitProgressEvent"], None] = None, **kwargs, - ): + ) -> Mapping[str, int]: from dulwich.client import HTTPUnauthorized, get_transport_and_path from dulwich.errors import NotGitRepository, SendPackError + from dulwich.objectspec import parse_reftuples from dulwich.porcelain import ( DivergedBranches, check_diverged, get_remote_repo, ) - dest_refs, values = self._push_dest_refs(src, dest) - try: _remote, location = get_remote_repo(self.repo, url) client, path = get_transport_and_path(location, **kwargs) @@ -516,26 +521,40 @@ def push_refspec( f"'{url}' is not a valid Git remote or URL" ) from exc + change_result = {} + selected_refs = [] + def update_refs(refs): from dulwich.objects import ZERO_SHA + selected_refs.extend( + parse_reftuples(self.repo.refs, refs, refspecs, force=force) + ) new_refs = {} - for ref, value in zip(dest_refs, values): - if ref in refs and value != ZERO_SHA: - local_sha = self.repo.refs[ref] - remote_sha = refs[ref] + for (lh, rh, _) in selected_refs: + refname = os.fsdecode(rh) + if rh in refs and lh is not None: + if refs[rh] == self.repo.refs[lh]: + change_result[refname] = SyncStatus.DUPLICATED + continue try: - check_diverged(self.repo, remote_sha, local_sha) + check_diverged(self.repo, refs[rh], self.repo.refs[lh]) except DivergedBranches: if not force: - overwrite = False - if on_diverged: - overwrite = on_diverged( - os.fsdecode(ref), os.fsdecode(remote_sha) - ) - if not overwrite: - continue - new_refs[ref] = value + change_result[refname] = SyncStatus.DIVERGED + continue + except Exception: + change_result[refname] = SyncStatus.FAILED + continue + + if lh is None: + value = ZERO_SHA + else: + value = self.repo.refs[lh] + + new_refs[rh] = value + change_result[refname] = SyncStatus.SUCCESS + return new_refs try: @@ -548,38 +567,21 @@ def update_refs(refs): ), ) except (NotGitRepository, SendPackError) as exc: - raise SCMError("Git failed to push '{src}' to '{url}'") from exc + raise SCMError(f"Git failed to push ref to '{url}'") from exc except HTTPUnauthorized: raise AuthError(url) - - def _push_dest_refs( - self, src: Optional[str], dest: str - ) -> Tuple[Iterable[bytes], Iterable[bytes]]: - from dulwich.objects import ZERO_SHA - - if src is not None and src.endswith("/"): - src_b = os.fsencode(src) - keys = self.repo.refs.subkeys(src_b) - values = [self.repo.refs[b"".join([src_b, key])] for key in keys] - dest_refs = [b"".join([os.fsencode(dest), key]) for key in keys] - else: - if src is None: - values = [ZERO_SHA] - else: - values = [self.repo.refs[os.fsencode(src)]] - dest_refs = [os.fsencode(dest)] - return dest_refs, values + return change_result def fetch_refspecs( self, url: str, - refspecs: Iterable[str], + refspecs: Union[str, Iterable[str]], force: Optional[bool] = False, - on_diverged: Optional[Callable[[str, str], bool]] = None, progress: Callable[["GitProgressEvent"], None] = None, **kwargs, - ): + ) -> Mapping[str, int]: from dulwich.client import get_transport_and_path + from dulwich.errors import NotGitRepository from dulwich.objectspec import parse_reftuples from dulwich.porcelain import ( DivergedBranches, @@ -594,7 +596,7 @@ def determine_wants(remote_refs): parse_reftuples( remote_refs, self.repo.refs, - [os.fsencode(refspec) for refspec in refspecs], + refspecs, force=force, ) ) @@ -612,28 +614,40 @@ def determine_wants(remote_refs): f"'{url}' is not a valid Git remote or URL" ) from exc - fetch_result = client.fetch( - path, - self.repo, - progress=DulwichProgressReporter(progress) if progress else None, - determine_wants=determine_wants, - ) + try: + fetch_result = client.fetch( + path, + self.repo, + progress=DulwichProgressReporter(progress) + if progress + else None, + determine_wants=determine_wants, + ) + except NotGitRepository as exc: + raise SCMError(f"Git failed to fetch ref from '{url}'") from exc + + result = {} + for (lh, rh, _) in fetch_refs: - try: - if rh in self.repo.refs: + refname = os.fsdecode(rh) + if rh in self.repo.refs: + if self.repo.refs[rh] == fetch_result.refs[lh]: + result[refname] = SyncStatus.DUPLICATED + continue + try: check_diverged( self.repo, self.repo.refs[rh], fetch_result.refs[lh] ) - except DivergedBranches: - if not force: - overwrite = False - if on_diverged: - overwrite = on_diverged( - os.fsdecode(rh), os.fsdecode(fetch_result.refs[lh]) - ) - if not overwrite: + except DivergedBranches: + if not force: + result[refname] = SyncStatus.DIVERGED continue + except Exception: + result[refname] = SyncStatus.FAILED + continue self.repo.refs[rh] = fetch_result.refs[lh] + result[refname] = SyncStatus.SUCCESS + return result def _stash_iter(self, ref: str): stash = self._get_stash(ref) diff --git a/tests/test_git.py b/tests/test_git.py index bf51bb03..ecf57ab6 100644 --- a/tests/test_git.py +++ b/tests/test_git.py @@ -334,13 +334,20 @@ def test_push_refspec( remote_git_dir: TmpDir, use_url: str, ): + from scmrepo.git.backend.dulwich import SyncStatus + tmp_dir.gen({"file": "0"}) scm.add_commit("file", message="init") init_rev = scm.get_rev() + scm.add_commit("file", message="bar") + bar_rev = scm.get_rev() + scm.checkout(init_rev) + scm.add_commit("file", message="baz") + baz_rev = scm.get_rev() tmp_dir.gen( { - os.path.join(".git", "refs", "foo", "bar"): init_rev, - os.path.join(".git", "refs", "foo", "baz"): init_rev, + os.path.join(".git", "refs", "foo", "bar"): bar_rev, + os.path.join(".git", "refs", "foo", "baz"): baz_rev, } ) @@ -349,53 +356,89 @@ def test_push_refspec( scm.gitpython.repo.create_remote("origin", url) with pytest.raises(SCMError): - git.push_refspec("bad-remote", "refs/foo/bar", "refs/foo/bar") + git.push_refspec("bad-remote", "refs/foo/bar:refs/foo/bar") remote = url if use_url else "origin" - git.push_refspec(remote, "refs/foo/bar", "refs/foo/bar") - assert init_rev == remote_scm.get_ref("refs/foo/bar") + assert git.push_refspec(remote, "refs/foo/bar:refs/foo/bar") == { + "refs/foo/bar": SyncStatus.SUCCESS + } + assert bar_rev == remote_scm.get_ref("refs/foo/bar") remote_scm.checkout("refs/foo/bar") - assert init_rev == remote_scm.get_rev() + assert bar_rev == remote_scm.get_rev() assert (remote_git_dir / "file").read_text() == "0" - git.push_refspec(remote, "refs/foo/", "refs/foo/") - assert init_rev == remote_scm.get_ref("refs/foo/baz") - - git.push_refspec(remote, None, "refs/foo/baz") + assert git.push_refspec( + remote, ["refs/foo/bar:refs/foo/bar", "refs/foo/baz:refs/foo/baz"] + ) == { + "refs/foo/bar": SyncStatus.DUPLICATED, + "refs/foo/baz": SyncStatus.SUCCESS, + } + assert baz_rev == remote_scm.get_ref("refs/foo/baz") + + assert git.push_refspec(remote, ["refs/foo/bar:refs/foo/baz"]) == { + "refs/foo/baz": SyncStatus.DIVERGED + } + assert baz_rev == remote_scm.get_ref("refs/foo/baz") + + assert git.push_refspec(remote, ":refs/foo/baz") == { + "refs/foo/baz": SyncStatus.SUCCESS + } assert remote_scm.get_ref("refs/foo/baz") is None @pytest.mark.skip_git_backend("pygit2", "gitpython") +@pytest.mark.parametrize("use_url", [True, False]) def test_fetch_refspecs( + tmp_dir: TmpDir, scm: Git, git: Git, remote_git_dir: TmpDir, + use_url: bool, ): - url = f"file://{remote_git_dir.resolve().as_posix()}" + from scmrepo.git.backend.dulwich import SyncStatus + + url = f"file://{remote_git_dir.resolve().as_posix()}" + scm.gitpython.repo.create_remote("origin", url) remote_scm = Git(remote_git_dir) remote_git_dir.gen("file", "0") - remote_scm.add_commit("file", message="init") + remote_scm.add_commit("file", message="init") init_rev = remote_scm.get_rev() - + remote_scm.add_commit("file", message="bar") + bar_rev = remote_scm.get_rev() + remote_scm.checkout(init_rev) + remote_scm.add_commit("file", message="baz") + baz_rev = remote_scm.get_rev() remote_git_dir.gen( { - os.path.join(".git", "refs", "foo", "bar"): init_rev, - os.path.join(".git", "refs", "foo", "baz"): init_rev, + os.path.join(".git", "refs", "foo", "bar"): bar_rev, + os.path.join(".git", "refs", "foo", "baz"): baz_rev, } ) - git.fetch_refspecs( - url, ["refs/foo/bar:refs/foo/bar", "refs/foo/baz:refs/foo/baz"] - ) - assert init_rev == scm.get_ref("refs/foo/bar") - assert init_rev == scm.get_ref("refs/foo/baz") + with pytest.raises(SCMError): + git.fetch_refspecs("bad-remote", "refs/foo/bar:refs/foo/bar") - remote_scm.checkout("refs/foo/bar") - assert init_rev == remote_scm.get_rev() - assert (remote_git_dir / "file").read_text() == "0" + remote = url if use_url else "origin" + assert git.fetch_refspecs(remote, "refs/foo/bar:refs/foo/bar") == { + "refs/foo/bar": SyncStatus.SUCCESS + } + assert bar_rev == scm.get_ref("refs/foo/bar") + + assert git.fetch_refspecs( + remote, ["refs/foo/bar:refs/foo/bar", "refs/foo/baz:refs/foo/baz"] + ) == { + "refs/foo/bar": SyncStatus.DUPLICATED, + "refs/foo/baz": SyncStatus.SUCCESS, + } + assert baz_rev == scm.get_ref("refs/foo/baz") + + assert git.fetch_refspecs(remote, ["refs/foo/bar:refs/foo/baz"]) == { + "refs/foo/baz": SyncStatus.DIVERGED + } + assert baz_rev == scm.get_ref("refs/foo/baz") @pytest.mark.skip_git_backend("dulwich", "pygit2") From ecd00f1793275b37622aa9d76ebd6755224b7bbe Mon Sep 17 00:00:00 2001 From: karajan1001 Date: Fri, 15 Apr 2022 18:38:28 +0800 Subject: [PATCH 2/4] Some review changes on push and fetch refspec 1. rename `push_refspec` to `push_refspecs` as it can receive a list of refspecs 2. Move SyncEnum to base.py 3. Modify abstract methods args of `push_refspecs` and `fetch_refspecs` to match the new api. --- scmrepo/git/__init__.py | 2 +- scmrepo/git/backend/base.py | 27 +++++++------ scmrepo/git/backend/dulwich/__init__.py | 53 ++++++++++++++----------- scmrepo/git/backend/gitpython.py | 15 ++++--- scmrepo/git/backend/pygit2.py | 15 ++++--- tests/test_git.py | 17 ++++---- 6 files changed, 68 insertions(+), 61 deletions(-) diff --git a/scmrepo/git/__init__.py b/scmrepo/git/__init__.py index 260ab74f..ec9baccc 100644 --- a/scmrepo/git/__init__.py +++ b/scmrepo/git/__init__.py @@ -348,7 +348,7 @@ def add_commit( iter_refs = partialmethod(_backend_func, "iter_refs") iter_remote_refs = partialmethod(_backend_func, "iter_remote_refs") get_refs_containing = partialmethod(_backend_func, "get_refs_containing") - push_refspec = partialmethod(_backend_func, "push_refspec") + push_refspecs = partialmethod(_backend_func, "push_refspecs") fetch_refspecs = partialmethod(_backend_func, "fetch_refspecs") _stash_iter = partialmethod(_backend_func, "_stash_iter") _stash_push = partialmethod(_backend_func, "_stash_push") diff --git a/scmrepo/git/backend/base.py b/scmrepo/git/backend/base.py index d5e23acc..0feef3ef 100644 --- a/scmrepo/git/backend/base.py +++ b/scmrepo/git/backend/base.py @@ -1,5 +1,6 @@ import os from abc import ABC, abstractmethod +from enum import Enum from typing import ( TYPE_CHECKING, Callable, @@ -25,6 +26,12 @@ def __init__(self, func): super().__init__(f"No valid Git backend for '{func}'") +class SyncStatus(Enum): + SUCCESS = 0 + DUPLICATED = 1 + DIVERGED = 2 + + class BaseGitBackend(ABC): """Base Git backend class.""" @@ -206,25 +213,21 @@ def get_refs_containing(self, rev: str, pattern: Optional[str] = None): """Iterate over all git refs containing the specified revision.""" @abstractmethod - def push_refspec( + def push_refspecs( self, url: str, - src: Optional[str], - dest: str, + refspecs: Union[str, Iterable[str]], force: bool = False, on_diverged: Optional[Callable[[str, str], bool]] = None, progress: Callable[["GitProgressEvent"], None] = None, **kwargs, - ): + ) -> Mapping[str, SyncStatus]: """Push refspec to a remote Git repo. Args: url: Git remote name or absolute Git URL. - src: Local refspec. If src ends with "/" it will be treated as a - prefix, and all refs inside src will be pushed using dest - as destination refspec prefix. If src is None, dest will be - deleted from the remote. - dest: Remote refspec. + refspecs: Iterable containing refspecs to fetch. + Note that this will not match subkeys. force: If True, remote refs will be overwritten. on_diverged: Callback function which will be called if local ref and remote have diverged and force is False. If the callback @@ -237,12 +240,12 @@ def push_refspec( def fetch_refspecs( self, url: str, - refspecs: Iterable[str], - force: Optional[bool] = False, + refspecs: Union[str, Iterable[str]], + force: bool = False, on_diverged: Optional[Callable[[str, str], bool]] = None, progress: Callable[["GitProgressEvent"], None] = None, **kwargs, - ): + ) -> Mapping[str, SyncStatus]: """Fetch refspecs from a remote Git repo. Args: diff --git a/scmrepo/git/backend/dulwich/__init__.py b/scmrepo/git/backend/dulwich/__init__.py index b3a308a6..eff02942 100644 --- a/scmrepo/git/backend/dulwich/__init__.py +++ b/scmrepo/git/backend/dulwich/__init__.py @@ -3,7 +3,6 @@ import logging import os import stat -from enum import Enum from functools import partial from io import BytesIO, StringIO from typing import ( @@ -25,7 +24,7 @@ from scmrepo.utils import relpath from ...objects import GitObject -from ..base import BaseGitBackend +from ..base import BaseGitBackend, SyncStatus if TYPE_CHECKING: from dulwich.repo import Repo @@ -38,13 +37,6 @@ logger = logging.getLogger(__name__) -class SyncStatus(Enum): - SUCCESS = 0 - DUPLICATED = 1 - DIVERGED = 2 - FAILED = 3 - - class DulwichObject(GitObject): def __init__(self, repo, name, mode, sha): self.repo = repo @@ -496,14 +488,15 @@ def iter_remote_refs(self, url: str, base: Optional[str] = None, **kwargs): def get_refs_containing(self, rev: str, pattern: Optional[str] = None): raise NotImplementedError - def push_refspec( + def push_refspecs( self, url: str, refspecs: Union[str, Iterable[str]], force: bool = False, + on_diverged: Optional[Callable[[str, str], bool]] = None, progress: Callable[["GitProgressEvent"], None] = None, **kwargs, - ) -> Mapping[str, int]: + ) -> Mapping[str, SyncStatus]: from dulwich.client import HTTPUnauthorized, get_transport_and_path from dulwich.errors import NotGitRepository, SendPackError from dulwich.objectspec import parse_reftuples @@ -541,11 +534,16 @@ def update_refs(refs): check_diverged(self.repo, refs[rh], self.repo.refs[lh]) except DivergedBranches: if not force: - change_result[refname] = SyncStatus.DIVERGED - continue - except Exception: - change_result[refname] = SyncStatus.FAILED - continue + overwrite = ( + on_diverged( + os.fsdecode(lh), os.fsdecode(refs[rh]) + ) + if on_diverged + else False + ) + if not overwrite: + change_result[refname] = SyncStatus.DIVERGED + continue if lh is None: value = ZERO_SHA @@ -567,7 +565,8 @@ def update_refs(refs): ), ) except (NotGitRepository, SendPackError) as exc: - raise SCMError(f"Git failed to push ref to '{url}'") from exc + src = [lh for (lh, _, _) in selected_refs] + raise SCMError(f"Git failed to push '{src}' to '{url}'") from exc except HTTPUnauthorized: raise AuthError(url) return change_result @@ -577,9 +576,10 @@ def fetch_refspecs( url: str, refspecs: Union[str, Iterable[str]], force: Optional[bool] = False, + on_diverged: Optional[Callable[[str, str], bool]] = None, progress: Callable[["GitProgressEvent"], None] = None, **kwargs, - ) -> Mapping[str, int]: + ) -> Mapping[str, SyncStatus]: from dulwich.client import get_transport_and_path from dulwich.errors import NotGitRepository from dulwich.objectspec import parse_reftuples @@ -640,11 +640,18 @@ def determine_wants(remote_refs): ) except DivergedBranches: if not force: - result[refname] = SyncStatus.DIVERGED - continue - except Exception: - result[refname] = SyncStatus.FAILED - continue + overwrite = ( + on_diverged( + os.fsdecode(rh), + os.fsdecode(fetch_result.refs[lh]), + ) + if on_diverged + else False + ) + if not overwrite: + result[refname] = SyncStatus.DIVERGED + continue + self.repo.refs[rh] = fetch_result.refs[lh] result[refname] = SyncStatus.SUCCESS return result diff --git a/scmrepo/git/backend/gitpython.py b/scmrepo/git/backend/gitpython.py index 0a994134..5d4adb6a 100644 --- a/scmrepo/git/backend/gitpython.py +++ b/scmrepo/git/backend/gitpython.py @@ -28,7 +28,7 @@ from scmrepo.utils import relpath from ..objects import GitCommit, GitObject -from .base import BaseGitBackend +from .base import BaseGitBackend, SyncStatus if TYPE_CHECKING: from scmrepo.progress import GitProgressEvent @@ -474,27 +474,26 @@ def get_refs_containing(self, rev: str, pattern: Optional[str] = None): except GitCommandError: pass - def push_refspec( + def push_refspecs( self, url: str, - src: Optional[str], - dest: str, + refspecs: Union[str, Iterable[str]], force: bool = False, on_diverged: Optional[Callable[[str, str], bool]] = None, progress: Callable[["GitProgressEvent"], None] = None, **kwargs, - ): + ) -> Mapping[str, SyncStatus]: raise NotImplementedError def fetch_refspecs( self, url: str, - refspecs: Iterable[str], - force: Optional[bool] = False, + refspecs: Union[str, Iterable[str]], + force: bool = False, on_diverged: Optional[Callable[[str, str], bool]] = None, progress: Callable[["GitProgressEvent"], None] = None, **kwargs, - ): + ) -> Mapping[str, SyncStatus]: raise NotImplementedError def _stash_iter(self, ref: str): diff --git a/scmrepo/git/backend/pygit2.py b/scmrepo/git/backend/pygit2.py index e07b11ce..58e6e3b0 100644 --- a/scmrepo/git/backend/pygit2.py +++ b/scmrepo/git/backend/pygit2.py @@ -26,7 +26,7 @@ from scmrepo.utils import relpath from ..objects import GitCommit, GitObject -from .base import BaseGitBackend +from .base import BaseGitBackend, SyncStatus logger = logging.getLogger(__name__) @@ -414,27 +414,26 @@ def _contains(repo, ref, search_commit): ) and _contains(self.repo, ref, search_commit): yield ref - def push_refspec( + def push_refspecs( self, url: str, - src: Optional[str], - dest: str, + refspecs: Union[str, Iterable[str]], force: bool = False, on_diverged: Optional[Callable[[str, str], bool]] = None, progress: Callable[["GitProgressEvent"], None] = None, **kwargs, - ): + ) -> Mapping[str, SyncStatus]: raise NotImplementedError def fetch_refspecs( self, url: str, - refspecs: Iterable[str], - force: Optional[bool] = False, + refspecs: Union[str, Iterable[str]], + force: bool = False, on_diverged: Optional[Callable[[str, str], bool]] = None, progress: Callable[["GitProgressEvent"], None] = None, **kwargs, - ): + ) -> Mapping[str, SyncStatus]: raise NotImplementedError def _stash_iter(self, ref: str): diff --git a/tests/test_git.py b/tests/test_git.py index ecf57ab6..9017f21a 100644 --- a/tests/test_git.py +++ b/tests/test_git.py @@ -327,7 +327,7 @@ def test_refs_containing(tmp_dir: TmpDir, scm: Git, git: Git): @pytest.mark.skip_git_backend("pygit2", "gitpython") @pytest.mark.parametrize("use_url", [True, False]) -def test_push_refspec( +def test_push_refspecs( tmp_dir: TmpDir, scm: Git, git: Git, @@ -356,10 +356,10 @@ def test_push_refspec( scm.gitpython.repo.create_remote("origin", url) with pytest.raises(SCMError): - git.push_refspec("bad-remote", "refs/foo/bar:refs/foo/bar") + git.push_refspecs("bad-remote", "refs/foo/bar:refs/foo/bar") remote = url if use_url else "origin" - assert git.push_refspec(remote, "refs/foo/bar:refs/foo/bar") == { + assert git.push_refspecs(remote, "refs/foo/bar:refs/foo/bar") == { "refs/foo/bar": SyncStatus.SUCCESS } assert bar_rev == remote_scm.get_ref("refs/foo/bar") @@ -368,7 +368,7 @@ def test_push_refspec( assert bar_rev == remote_scm.get_rev() assert (remote_git_dir / "file").read_text() == "0" - assert git.push_refspec( + assert git.push_refspecs( remote, ["refs/foo/bar:refs/foo/bar", "refs/foo/baz:refs/foo/baz"] ) == { "refs/foo/bar": SyncStatus.DUPLICATED, @@ -376,12 +376,12 @@ def test_push_refspec( } assert baz_rev == remote_scm.get_ref("refs/foo/baz") - assert git.push_refspec(remote, ["refs/foo/bar:refs/foo/baz"]) == { + assert git.push_refspecs(remote, ["refs/foo/bar:refs/foo/baz"]) == { "refs/foo/baz": SyncStatus.DIVERGED } assert baz_rev == remote_scm.get_ref("refs/foo/baz") - assert git.push_refspec(remote, ":refs/foo/baz") == { + assert git.push_refspecs(remote, ":refs/foo/baz") == { "refs/foo/baz": SyncStatus.SUCCESS } assert remote_scm.get_ref("refs/foo/baz") is None @@ -905,10 +905,9 @@ async def test_git_ssh( scm.add_commit("foo", message="init") rev = scm.get_rev() - git.push_refspec( + git.push_refspecs( url, - "refs/heads/master", - "refs/heads/master", + "refs/heads/master:refs/heads/master", force=True, key_filename=key_filename, ) From cc3bf3ae6adb73b66dbc0bd878695c23a158d3f2 Mon Sep 17 00:00:00 2001 From: Gao Date: Mon, 25 Apr 2022 16:11:47 +0800 Subject: [PATCH 3/4] Update scmrepo/git/backend/base.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Peter Rowlands (변기호) --- scmrepo/git/backend/base.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scmrepo/git/backend/base.py b/scmrepo/git/backend/base.py index 0feef3ef..5c64362f 100644 --- a/scmrepo/git/backend/base.py +++ b/scmrepo/git/backend/base.py @@ -28,7 +28,7 @@ def __init__(self, func): class SyncStatus(Enum): SUCCESS = 0 - DUPLICATED = 1 + UP_TO_DATE = 1 DIVERGED = 2 @@ -226,7 +226,7 @@ def push_refspecs( Args: url: Git remote name or absolute Git URL. - refspecs: Iterable containing refspecs to fetch. + refspecs: Iterable containing refspecs to push. Note that this will not match subkeys. force: If True, remote refs will be overwritten. on_diverged: Callback function which will be called if local ref From 6ada49fd4753b52a99782a178904612e1568fd2b Mon Sep 17 00:00:00 2001 From: karajan1001 Date: Mon, 25 Apr 2022 16:16:20 +0800 Subject: [PATCH 4/4] Rename DUPLICETE to UP_TO_DATE --- scmrepo/git/backend/dulwich/__init__.py | 4 ++-- tests/test_git.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/scmrepo/git/backend/dulwich/__init__.py b/scmrepo/git/backend/dulwich/__init__.py index eff02942..bdec149d 100644 --- a/scmrepo/git/backend/dulwich/__init__.py +++ b/scmrepo/git/backend/dulwich/__init__.py @@ -528,7 +528,7 @@ def update_refs(refs): refname = os.fsdecode(rh) if rh in refs and lh is not None: if refs[rh] == self.repo.refs[lh]: - change_result[refname] = SyncStatus.DUPLICATED + change_result[refname] = SyncStatus.UP_TO_DATE continue try: check_diverged(self.repo, refs[rh], self.repo.refs[lh]) @@ -632,7 +632,7 @@ def determine_wants(remote_refs): refname = os.fsdecode(rh) if rh in self.repo.refs: if self.repo.refs[rh] == fetch_result.refs[lh]: - result[refname] = SyncStatus.DUPLICATED + result[refname] = SyncStatus.UP_TO_DATE continue try: check_diverged( diff --git a/tests/test_git.py b/tests/test_git.py index 9017f21a..f5bc93e2 100644 --- a/tests/test_git.py +++ b/tests/test_git.py @@ -371,7 +371,7 @@ def test_push_refspecs( assert git.push_refspecs( remote, ["refs/foo/bar:refs/foo/bar", "refs/foo/baz:refs/foo/baz"] ) == { - "refs/foo/bar": SyncStatus.DUPLICATED, + "refs/foo/bar": SyncStatus.UP_TO_DATE, "refs/foo/baz": SyncStatus.SUCCESS, } assert baz_rev == remote_scm.get_ref("refs/foo/baz") @@ -430,7 +430,7 @@ def test_fetch_refspecs( assert git.fetch_refspecs( remote, ["refs/foo/bar:refs/foo/bar", "refs/foo/baz:refs/foo/baz"] ) == { - "refs/foo/bar": SyncStatus.DUPLICATED, + "refs/foo/bar": SyncStatus.UP_TO_DATE, "refs/foo/baz": SyncStatus.SUCCESS, } assert baz_rev == scm.get_ref("refs/foo/baz")