# HG changeset patch # User Georges Racinet <georges.racinet@octobus.net> # Date 1592312367 -7200 # Tue Jun 16 14:59:27 2020 +0200 # Node ID 6eddb15037298509b2b8e82b7f05963fa568a717 # Parent df655a5c3c66ad4512b5bf75850e383159d4ddc3 FindCommit: 'revision' is actually a Git revspec. This is a nice example of how a guess based on the type of an argument can be wrong. First tries with actual GitLab client showed that this revision is called "id_or_ref" on the client side, and can be either - a SHA ("id") - a GitLab branch name ("ref") - HEAD, meaning the head of the default branch, not supported yet in HGitaly. Just hoping there's not more advanced syntax such as `master~3` that would force us to do a full conversion from Git revspec to Mercurial revset syntax. diff --git a/hgitaly/servicer.py b/hgitaly/servicer.py --- a/hgitaly/servicer.py +++ b/hgitaly/servicer.py @@ -4,11 +4,15 @@ error as hg_error, hg, node, + scmutil, ui as uimod, ) from mercurial.utils import stringutil as hg_stringutil from google.protobuf.timestamp_pb2 import Timestamp +# TODO move that to heptapod.gitlab +from hgext3rd.heptapod.git import parse_gitlab_branch + from .stub.shared_pb2 import ( CommitAuthor, GitCommit, @@ -72,6 +76,15 @@ ) +def gitlab_branch_to_branchmap_branch(gl_branch): + parsed = parse_gitlab_branch(gl_branch) + if parsed is None: + return None # could be a SHA, a bookmark or a tag + if parsed[1] is None: + return parsed[0] + return b':'.join(parsed) + + class Servicer(CommitServiceServicer): """CommitService implementation. @@ -105,7 +118,14 @@ repo = self.load_repo(request.repository) logger.debug("FindCommit revision=%r", request.revision) try: - ctx = repo[request.revision] + branchmap_key = gitlab_branch_to_branchmap_branch(request.revision) + if branchmap_key is None: + ctx = scmutil.revsingle(repo, request.revision) + else: + contexts = (repo[node] + for node in repo.branchmap()[branchmap_key]) + ctx = max((ctx.rev(), ctx) for ctx in contexts)[1] + except hg_error.RepoLookupError: commit = None else: diff --git a/hgitaly/tests/test_commit.py b/hgitaly/tests/test_commit.py --- a/hgitaly/tests/test_commit.py +++ b/hgitaly/tests/test_commit.py @@ -7,7 +7,9 @@ def test_find_commit(grpc_stub, server_repos_root): repo_path = server_repos_root / 'repo1' - wrapper = LocalRepoWrapper.init(repo_path) + wrapper = LocalRepoWrapper.init(repo_path, + config={b'extensions': {b'topic': b''}} + ) now = time.time() ctx = wrapper.write_commit('foo', utc_timestamp=now, @@ -18,7 +20,7 @@ request = FindCommitRequest( repository=Repository(relative_path='repo1'), - revision=ctx.node()) + revision=ctx.hex()) response = grpc_stub.FindCommit(request) commit = response.commit @@ -31,7 +33,7 @@ request = FindCommitRequest( repository=Repository(relative_path='repo1'), - revision=ctx2.node()) + revision=ctx2.hex()) response = grpc_stub.FindCommit(request) commit2 = response.commit @@ -45,6 +47,26 @@ request = FindCommitRequest( repository=Repository(relative_path='repo1'), - revision=b'.' * 20) + revision=b'branch/default') + response = grpc_stub.FindCommit(request) + assert response.commit == commit2 + + # TODO reuse heptapod testhelpers + wrapper.command(b'topics', b'antelope') + wrapper.write_commit('animals', + message="in topic", + parent=ctx) + request = FindCommitRequest( + repository=Repository(relative_path='repo1'), + revision=b'branch/default') + response = grpc_stub.FindCommit(request) + + commit_top = response.commit + assert commit_top is not None + assert commit_top.subject == b"in topic" + + request = FindCommitRequest( + repository=Repository(relative_path='repo1'), + revision=b'unknown') response = grpc_stub.FindCommit(request) assert not response.HasField('commit')