Commit 1242897d authored by Georges Racinet's avatar Georges Racinet 🦑
Browse files

RefService.DeleteRefs: implement except_prefix

Closes #55

Since we're only removing special refs, comparison to Gitaly
has to be understood as assuming that only special refs will be
removed on the Git side, which we arrange for directly.

branch : stable
parent 18de9ce81bfb
Pipeline #25168 passed with stage
in 1 minute and 33 seconds
......@@ -31,7 +31,6 @@ from hgext3rd.heptapod.keep_around import (
from ..errors import (
from ..stub.shared_pb2 import (
......@@ -337,13 +336,6 @@ class RefServicer(RefServiceServicer, HGitalyServicer):
return invalid_argument(
context, DeleteRefsResponse,
"DeleteRefs: ExceptWithPrefix and Refs are mutually exclusive")
if except_prefix:
# TODO implement, while still enforcing our rule
# to remove only special refs (hard error or ignore?, must
# take a look at callers)
return not_implemented( # pragma no cover
context, DeleteRefsResponse,
repo = self.load_repo(request.repository, context)
srefs = special_refs(repo)
......@@ -359,6 +351,9 @@ class RefServicer(RefServiceServicer, HGitalyServicer):
if err is not None:
return DeleteRefsResponse(git_error=err)
if except_prefix:
srefs = special_refs_matching_prefixes(srefs, except_prefix)
write_special_refs(repo, srefs)
return DeleteRefsResponse()
......@@ -532,3 +527,21 @@ def remove_special_refs(special_refs, to_remove):
"not keep-arounds) can be directly deleted in Mercurial, "
"got %r" % ref)
special_refs.pop(name, None)
def special_refs_matching_prefixes(special_refs, prefixes):
"""Return a sub-mapping of special refs matching given prefixes
:param prefixes: given as full ref names, e.g. `refs/pipelines`.
Any such prefix that would not be a special ref is simply ignored.
# Don't use parse_special_ref here, even if tempting: it would
# not accept prefixes without trailing slashes, such as `refs/pipelines`
# nor more partial prefixes, such as `refs/pipe`. Currently all used
# prefixes are full with trailing slash, but if upstream developers
# ever use a more partial prefix, this would result in data loss
short_prefixes = {pref[5:] for pref in prefixes
if pref.startswith(b'refs/')}
return {name: target for name, target in special_refs.items()
if any(name.startswith(prefix) for prefix in short_prefixes)}
......@@ -253,6 +253,29 @@ def test_delete_refs(grpc_channel, server_repos_root):
setattr(repo, '_gitlab_refs_special-refs', None)
assert special_refs(repo) == {}
other_special_ref_name = b'environments/124'
for prefix in (b'refs/environments',
write_gitlab_special_ref(repo, special_ref_name, ctx.hex())
write_gitlab_special_ref(repo, other_special_ref_name, ctx.hex())
# double check
assert special_refs(repo) == {special_ref_name: ctx.hex(),
other_special_ref_name: ctx.hex()}
assert not do_rpc(except_prefixes=[prefix]).git_error
# TODO use the future wrapper.reload()
setattr(repo, '_gitlab_refs_special-refs', None)
assert special_refs(repo) == {other_special_ref_name: ctx.hex()}
# exclusion matching both special refs
write_gitlab_special_ref(repo, special_ref_name, ctx.hex())
write_gitlab_special_ref(repo, other_special_ref_name, ctx.hex())
assert not do_rpc(except_prefixes=[b'refs/environ',
assert special_refs(repo) == {special_ref_name: ctx.hex(),
other_special_ref_name: ctx.hex()}
def test_list_branch_names_containing_commit(grpc_channel, server_repos_root):
"""Test ListBranchNamesContainingCommit on a repo a bit more spread
......@@ -118,6 +118,37 @@ def test_delete_refs(gitaly_comparison):
setattr(hg_repo, '_gitlab_refs_special-refs', None)
assert special_refs(hg_repo) == {}
# using except_with_prefix
env_ref_name = b'environments/2877'
env_ref_path = b'refs/' + env_ref_name
def setup_env_ref():
git_repo.write_ref(env_ref_path.decode(), git_sha)
write_gitlab_special_ref(hg_repo, env_ref_name, hg_sha)
# TODO use the future wrapper.reload()
setattr(hg_repo, '_gitlab_refs_special-refs', None)
assert env_ref_path in git_repo.all_refs()
assert env_ref_name in special_refs(hg_repo)
# on the Mercurial side, we'll consider the special ref only,
# but on the Git side, the `refs/heads` prefix has to be ignored.
# This is similar to what the current actual caller,
# `Projects::AfterImportService`, does.
for except_prefixes in (
[b'refs/environments/', b'refs/heads/'],
[b'refs/environments', b'refs/heads/'],
[b'refs/envir', b'refs/heads/'],
assert git_repo.all_refs() == {b'refs/heads/branch/default': git_sha,
env_ref_path: git_sha}
# TODO use the future wrapper.reload()
setattr(hg_repo, '_gitlab_refs_special-refs', None)
assert special_refs(hg_repo) == {env_ref_name: hg_sha}
def test_find_ref_name(gitaly_comparison):
fixture = gitaly_comparison
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment