This instance will be upgraded to Heptapod 0.19.0rc2 on 2021-01-18 at 11:00 UTC+1 (a few minutes of downtime)

Commit 518cc79d authored by Sushil Khanchi's avatar Sushil Khanchi 🏳🌈

commit: add multiple filtering options in FindCommits

parent 17cd31f154e3
Pipeline #13627 failed with stages
in 46 seconds
......@@ -6,9 +6,11 @@
# SPDX-License-Identifier: GPL-2.0-or-later
import logging
from google.protobuf.timestamp_pb2 import Timestamp
from mercurial import (
error,
pycompat,
logcmdutil,
)
from ..errors import (
......@@ -257,19 +259,11 @@ class CommitServicer(CommitServiceServicer, HGitalyServicer):
context) -> FindCommitsResponse:
# TODO: yet to finish this method to support all lookups
repo = self.load_repo(request.repository, context)
revision = request.revision
if revision:
ctx = gitlab_revision_changeset(repo, revision)
revs = repo.revs('::%s', ctx)
else:
# Note: if revision is not passed, we return all revs for now.
# `revision` and `all` are mutually exclusive
revs = repo.revs('all()')
# order revision from top to bottom i.e (tip:0)
revs.reverse()
limit = request.limit
if limit and len(revs) > limit:
revs = revs.slice(0, limit)
paths = request.paths
# XXX: raise error if one of the path given is an empty string
opts = parse_find_commits_request_opts(request, repo)
walk_opts = logcmdutil.parseopts(repo.ui, paths, opts)
revs, _differ = logcmdutil.getrevs(repo, walk_opts)
for chunk in chunked(revs):
yield FindCommitsResponse(
commits=(message.commit(repo[rev]) for rev in chunk))
......@@ -380,3 +374,61 @@ class CommitServicer(CommitServiceServicer, HGitalyServicer):
context) -> GetCommitMessagesResponse:
return not_implemented(context, GetCommitMessagesResponse,
issue=25) # pragma no cover
def parse_find_commits_request_opts(request, repo):
opts = {
b'follow': request.follow,
b'no_merges': request.skip_merges,
b'follow_first': request.first_parent,
}
if request.limit:
opts[b'limit'] = request.limit
if request.author:
opts[b'user'] = [request.author]
after = request.after.ToSeconds()
before = request.before.ToSeconds()
date = getdate(after, before)
if date is not None:
opts[b'date'] = date
revision = request.revision
if not (revision or request.all):
revision = default_revision_name(request, repo)
revision = b"reverse(::%s)" % revision.encode()
if revision and not request.all:
# `revision` and `all` are mutually exclusive,
# if both present `all` gets the precedence
opts[b'rev'] = [revision]
return opts
def default_revision_name(request, repo):
"""Return default branch name of a repository."""
# XXX: for now we return "branch/default" but, this method would
# probably end up being useful to return default branch name as
# per repository configuration.
revision_name = "default"
return revision_name
def getdate(after, before):
if after and before:
after = _isoformat_from_seconds(after)
before = _isoformat_from_seconds(before)
return "%s to %s UTC" % (after, before)
elif after:
after = _isoformat_from_seconds(after)
return ">%s UTC" % after
elif before:
before = _isoformat_from_seconds(before)
return "<%s UTC" % before
return None
def _isoformat_from_seconds(secs):
ts = Timestamp()
ts.FromSeconds(int(secs))
dt = ts.ToDatetime()
return dt.isoformat()
......@@ -8,6 +8,7 @@ import time
from mercurial import (
pycompat,
)
from google.protobuf.timestamp_pb2 import Timestamp
from hgext3rd.heptapod.branch import set_default_gitlab_branch
from hgitaly.tests.common import (
......@@ -186,37 +187,53 @@ def test_find_commits(grpc_channel, server_repos_root):
# prepare repo as:
#
# 2 (branch/default)
# 3 (topic/default/feature)
# |
# 1
# | 3 (topic/default/feature)
# | 2 (branch/stable)
# | /
# | 1 (branch/default)
# | /
# 0
#
def do_rpc(revision=None, limit=None):
request = FindCommitsRequest(repository=grpc_repo,
revision=revision,
limit=limit)
def do_rpc(**opts):
request = FindCommitsRequest(repository=grpc_repo, **opts)
resp = grpc_stub.FindCommits(request)
return [pycompat.sysbytes(commit.id)
for chunk in resp for commit in chunk.commits]
ctx0 = wrapper.write_commit('foo')
ctx1 = wrapper.write_commit('bar', parent=ctx0)
ctx2 = wrapper.write_commit('baz', parent=ctx1)
ctx1 = wrapper.write_commit('bar', parent=ctx0, user="testuser2")
ctx2 = wrapper.write_commit('baz', branch='stable', parent=ctx0)
offset = 50
now = int(time.time()) + offset
date = Timestamp()
date.FromSeconds(now)
ctx3 = wrapper.write_commit('animals',
topic='feature',
parent=ctx0)
# find commits on branch/default
assert do_rpc(revision=b'branch/default') == [
ctx2.hex(), ctx1.hex(), ctx0.hex()]
# find commits on topic/default/feature
assert do_rpc(revision=b'topic/default/feature') == [
ctx3.hex(), ctx0.hex()]
# when no revision passed; return all for now
assert do_rpc() == [ctx3.hex(), ctx2.hex(), ctx1.hex(), ctx0.hex()]
# when limit passed
assert do_rpc(limit=2) == [ctx3.hex(), ctx2.hex()]
parent=ctx0,
utc_timestamp=int(now))
assert do_rpc(revision=b'0::3') == [ctx0.hex(), ctx3.hex()]
assert do_rpc(revision=b'0::2') == [ctx0.hex(), ctx2.hex()]
assert do_rpc(revision=b'0::1') == [ctx0.hex(), ctx1.hex()]
assert do_rpc(revision=b'3:0') == [
ctx3.hex(), ctx2.hex(), ctx1.hex(), ctx0.hex()]
# with date specs
assert do_rpc(all=True, before=date) == [
ctx3.hex(), ctx2.hex(), ctx1.hex(), ctx0.hex()]
assert do_rpc(all=True, after=date) == [ctx3.hex()]
assert do_rpc(all=True, after=date, before=date) == [
ctx3.hex(), ctx2.hex(), ctx1.hex(), ctx0.hex()]
# when no revision passed; return revs("reverse(::default_branch)")
assert do_rpc() == [ctx1.hex(), ctx0.hex()]
# with all, return all the commits
assert do_rpc(all=True) == [ctx3.hex(), ctx2.hex(), ctx1.hex(), ctx0.hex()]
# test limit
assert do_rpc(all=True, limit=2) == [ctx3.hex(), ctx2.hex()]
# test author
assert do_rpc(all=True, author=b"testuser2") == [ctx1.hex()]
def test_list_commits_by_ref_name(grpc_channel, server_repos_root):
......
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