bug 446459 - allow querying pushlog by user
authorTed Mielczarek <ted.mielczarek@gmail.com>
Fri, 21 Nov 2008 13:03:19 -0500
changeset 1110 2516f26f5a4f1d91e822409c16b8289d63c9eb1e
parent 1109 80555faca937b29bc77830881e5cb3f6140153e7
child 1111 45041dfc1d3b8bce8e50c9064eadd96dd3a520ef
push id159
push usergszorc@mozilla.com
push dateMon, 29 Sep 2014 18:14:30 +0000
treeherderversion-control-tools@e3d700020d5c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs446459
bug 446459 - allow querying pushlog by user
hgext/pushlog-legacy/pushlog-feed.py
hgext/pushlog-legacy/runtests.py
hgext/pushlog-legacy/testdata/test-repo-user-luser-someone.json
hgext/pushlog-legacy/testdata/test-repo-user-luser-startdate-enddate.json
hgext/pushlog-legacy/testdata/test-repo-user-luser-startdate.json
hgext/pushlog-legacy/testdata/test-repo-user-luser.json
hgext/pushlog-legacy/testdata/test-repo-user-someone.json
hgext/pushlog-legacy/testdata/test-repo-users.tar.bz2
--- a/hgext/pushlog-legacy/pushlog-feed.py
+++ b/hgext/pushlog-legacy/pushlog-feed.py
@@ -47,29 +47,31 @@ class PushlogQuery:
     # by default, we return the last 10 pushes
     querystart = QueryType.COUNT
     querystart_value = PUSHES_PER_PAGE
     # don't need a default here, since by default
     # we'll get everything newer than whatever your start
     # query is
     queryend = None
     queryend_value = None
+    # Allow query-by-user
+    userquery = []
 
     def __init__(self, repo, dbconn, urlbase='', tipsonly=False, reponame=''):
         self.repo = repo
         self.conn = dbconn
         self.urlbase = urlbase
         self.tipsonly = tipsonly
         self.reponame = reponame
 
     def DoQuery(self):
         """Figure out what the query parameters are, and query the database
         using those parameters."""
         self.entries = []
-        if self.querystart == QueryType.COUNT:
+        if self.querystart == QueryType.COUNT and not self.userquery:
             # Get entries from self.page, using self.querystart_value as
             # the number of pushes per page.
             try:
                 res = self.conn.execute("SELECT id, user, date FROM pushlog ORDER BY date DESC LIMIT ? OFFSET ?",
                                         (self.querystart_value,
                                          (self.page - 1) * self.querystart_value))
                 for (id,user,date) in res:
                     limit = ""
@@ -102,48 +104,63 @@ class PushlogQuery:
                 where.append("date < :end_date ")
                 params['end_date'] = self.queryend_value
             elif self.queryend == QueryType.CHANGESET:
                 where.append("id <= (select c.pushid from changesets c where c.node = :end_node)")
                 params['end_node'] = hex(self.repo.lookup(self.queryend_value))
             elif self.queryend == QueryType.PUSHID:
                 where.append("id <= :end_id ")
                 params['end_id'] = self.queryend_value
+
+            if self.userquery:
+                i = 0
+                subquery = []
+                for u in self.userquery:
+                    subquery.append("user = :user%d" % i)
+                    params['user%d' % i] = u
+                    i += 1
+                where.append('(' + ' OR '.join(subquery) + ')')
             
             query = basequery + ' AND '.join(where) + ' ORDER BY id DESC, rev DESC'
+            #print "query: %s" % query
+            #print "params: %s" % params
             try:
                 res = self.conn.execute(query, params)
                 lastid = None
                 for (id, user, date, node) in res:
                     if self.tipsonly and id == lastid:
                         continue
                     self.entries.append((id,user,date,node))
                     lastid = id
             except sqlite.OperationalError:
                 # likely just an empty db, so return an empty result
                 pass
 
     def description(self):
-        if self.querystart == QueryType.COUNT:
+        if self.querystart == QueryType.COUNT and self.userquery is None:
             return ''
         bits = []
         isotime = lambda x: datetime.utcfromtimestamp(x).isoformat(' ')
         if self.querystart == QueryType.DATE:
             bits.append('after %s' % isotime(self.querystart_value))
         elif self.querystart == QueryType.CHANGESET:
             bits.append('after changeset %s' % self.querystart_value)
         elif self.querystart == QueryType.PUSHID:
             bits.append('after push ID %s' % self.querystart_value)
 
         if self.queryend == QueryType.DATE:
             bits.append('before %s' % isotime(self.queryend_value))
         elif self.queryend == QueryType.CHANGESET:
             bits.append('up to and including changeset %s' % self.queryend_value)
         elif self.queryend == QueryType.PUSHID:
             bits.append('up to and including push ID %s' % self.queryend_value)
+
+        if self.userquery is not None:
+            bits.append('by user %s' % ' or '.join(self.userquery))
+
         return 'Changes pushed ' + ', '.join(bits)
 
 def localdate(ts):
     """Given a timestamp, return a (timestamp, tzoffset) tuple,
     which is what Mercurial works with. Attempts to get DST
     correct as well."""
     t = time.localtime(ts)
     offset = time.timezone
@@ -223,16 +240,19 @@ def pushlogSetup(repo, req):
         query.queryend_value = enddate
     elif 'tochange' in req.form:
         query.queryend = QueryType.CHANGESET
         query.queryend_value = req.form.get('tochange', ['default'])[0]
     elif 'endID' in req.form:
         query.queryend = QueryType.PUSHID
         query.queryend_value = req.form.get('endID', [None])[0]
 
+    if 'user' in req.form:
+        query.userquery = req.form.get('user', [])
+
     query.DoQuery()
     return query
     
 def pushlogFeed(web, req):
     """WebCommand for producing the ATOM feed of the pushlog."""
     query = pushlogSetup(web.repo, req)
     isotime = lambda x: datetime.utcfromtimestamp(x).isoformat() + 'Z'
     
--- a/hgext/pushlog-legacy/runtests.py
+++ b/hgext/pushlog-legacy/runtests.py
@@ -32,16 +32,30 @@ style=gitweb_mozilla
 def ensure_templates():
     # need to grab the moz hg templates
     if not os.path.isdir(templatepath):
         check_call(["hg", "clone", "http://hg.mozilla.org/hg_templates/",
                     templatepath], stdout=devnull, stderr=STDOUT)
     # make sure it's updated
     check_call(["hg","-R",templatepath,"pull","-u"], stdout=devnull, stderr=STDOUT)
 
+def loadjsonurl(url):
+    """Load JSON from a URL into an object."""
+    u = urlopen(url)
+    j = simplejson.loads(''.join(u.readlines()))
+    u.close()
+    return j
+
+def loadjsonfile(f):
+    """Given a file path relative to the srcdir, load the file as a JSON object."""
+    f = file(os.path.join(mydir, f))
+    j = simplejson.loads(''.join(f.readlines()))
+    f.close()
+    return j
+
 class TestEmptyRepo(unittest.TestCase):
     hgwebprocess = None
     def setUp(self):
         # create an empty repo
         repodir = "/tmp/hg-empty-repo/"
         check_call(["rm", "-rf", repodir])
         os.mkdir(repodir)
         check_call(["hg","init",repodir])
@@ -86,41 +100,27 @@ class TestPushlog(unittest.TestCase):
         sleep(1)
         os.environ['TZ'] = "America/New_York"
 
     def tearDown(self):
         # kill hgweb process
         if self.hgwebprocess is not None:
             os.kill(self.hgwebprocess.pid, SIGTERM)
             self.hgwebprocess = None
-
-    def loadjsonurl(self, url):
-        """Load JSON from a URL into an object."""
-        u = urlopen(url)
-        j = simplejson.loads(''.join(u.readlines()))
-        u.close()
-        return j
-
-    def loadjsonfile(self, f):
-        """Given a file path relative to the srcdir, load the file as a JSON object."""
-        f = file(os.path.join(mydir, f))
-        j = simplejson.loads(''.join(f.readlines()))
-        f.close()
-        return j
         
     def testalljsonpushes(self):
         """Get all json data from json-pushes."""
-        testjson = self.loadjsonurl("http://localhost:8000/json-pushes?startID=0")
-        expectedjson = self.loadjsonfile("testdata/test-repo-data.json")
+        testjson = loadjsonurl("http://localhost:8000/json-pushes?startID=0")
+        expectedjson = loadjsonfile("testdata/test-repo-data.json")
         self.assertEqual(testjson, expectedjson, "json-pushes did not yield expected json data!")
 
     def testprintpushlog(self):
         """Get all json data via 'hg printpushlog'."""
         testjson = simplejson.loads(Popen(["hg", "-R", self.repodir, "printpushlog"], stdout=PIPE).communicate()[0])
-        expectedjson = self.loadjsonfile("testdata/test-repo-data.json")
+        expectedjson = loadjsonfile("testdata/test-repo-data.json")
         self.assertEqual(testjson, expectedjson, "printpushlog did not yield expected json data!")
 
     def assertEqualFeeds(self, a, b):
         self.assertEqual(a.feed.title, b.feed.title, "not the same title, %s != %s" % (a.feed.title, b.feed.title))
         self.assertEqual(a.feed.updated, b.feed.updated, "not the same updated time, %s != %s" % (a.feed.updated, b.feed.updated))
         self.assertEqual(len(a.entries), len(b.entries), "not the same number of entries, %d != %d" % (len(a.entries), len(b.entries)))
         for ae, be in zip(a.entries, b.entries):
             self.assertEqual(ae.updated, be.updated, "not the same updated time, %s != %s" % (ae.updated, be.updated))
@@ -179,44 +179,101 @@ class TestPushlog(unittest.TestCase):
     def testdatequerytrailingspaceatom(self):
         """Dates with leading/trailing spaces should work properly."""
         testfeed = feedparser.parse("http://localhost:8000/pushlog?startdate=%202008-11-20%2010:52:25%20&enddate=%202008-11-20%2010:53:25%20&foo=bar")
         expectedfeed = feedparser.parse(os.path.join(mydir, "testdata/test-repo-date-query-data.xml"))
         self.assertEqualFeeds(testfeed, expectedfeed)
 
     def teststartidtoenddatequery(self):
         """Query with a startID and an enddate."""
-        testjson = self.loadjsonurl("http://localhost:8000/json-pushes?startID=5&enddate=2008-11-20%2010:53:25")
-        expectedjson = self.loadjsonfile("testdata/test-repo-startid-enddate-query.json")
+        testjson = loadjsonurl("http://localhost:8000/json-pushes?startID=5&enddate=2008-11-20%2010:53:25")
+        expectedjson = loadjsonfile("testdata/test-repo-startid-enddate-query.json")
         self.assertEqual(testjson, expectedjson, "json-pushes did not yield expected json data!")
 
     def teststartdatetoendidquery(self):
         """Query with a startdate and an endID."""
-        testjson = self.loadjsonurl("http://localhost:8000/json-pushes?startdate=2008-11-20%2010:52:25&endID=15")
-        expectedjson = self.loadjsonfile("testdata/test-repo-startdate-endid-query.json")
+        testjson = loadjsonurl("http://localhost:8000/json-pushes?startdate=2008-11-20%2010:52:25&endID=15")
+        expectedjson = loadjsonfile("testdata/test-repo-startdate-endid-query.json")
         self.assertEqual(testjson, expectedjson, "json-pushes did not yield expected json data!")
 
     def testfromchangetoendidquery(self):
         """Query with fromchange and an endID."""
-        testjson = self.loadjsonurl("http://localhost:8000/json-pushes?fromchange=cc07cc0e87f8&endID=15")
-        expectedjson = self.loadjsonfile("testdata/test-repo-fromchange-endid-query.json")
+        testjson = loadjsonurl("http://localhost:8000/json-pushes?fromchange=cc07cc0e87f8&endID=15")
+        expectedjson = loadjsonfile("testdata/test-repo-fromchange-endid-query.json")
         self.assertEqual(testjson, expectedjson, "json-pushes did not yield expected json data!")
 
     def teststartidtochangequery(self):
         """Query with a startID and tochange."""
-        testjson = self.loadjsonurl("http://localhost:8000/json-pushes?startID=5&tochange=af5fb85d9324")
-        expectedjson = self.loadjsonfile("testdata/test-repo-startid-tochange-query.json")
+        testjson = loadjsonurl("http://localhost:8000/json-pushes?startID=5&tochange=af5fb85d9324")
+        expectedjson = loadjsonfile("testdata/test-repo-startid-tochange-query.json")
         self.assertEqual(testjson, expectedjson, "json-pushes did not yield expected json data!")
 
     def testfromchangetoenddatequery(self):
         """Query with fromchange and an enddate."""
-        testjson = self.loadjsonurl("http://localhost:8000/json-pushes?fromchange=cc07cc0e87f8&enddate=2008-11-20%2010:52:56")
-        expectedjson = self.loadjsonfile("testdata/test-repo-fromchange-enddate-query.json")
+        testjson = loadjsonurl("http://localhost:8000/json-pushes?fromchange=cc07cc0e87f8&enddate=2008-11-20%2010:52:56")
+        expectedjson = loadjsonfile("testdata/test-repo-fromchange-enddate-query.json")
         self.assertEqual(testjson, expectedjson, "json-pushes did not yield expected json data!")
 
     def teststartdatetochangequery(self):
         """Query with a startdate and tochange."""
-        testjson = self.loadjsonurl("http://localhost:8000/json-pushes?startdate=2008-11-20%2010:52:25&tochange=af5fb85d9324")
-        expectedjson = self.loadjsonfile("testdata/test-repo-startdate-tochange-query.json")
+        testjson = loadjsonurl("http://localhost:8000/json-pushes?startdate=2008-11-20%2010:52:25&tochange=af5fb85d9324")
+        expectedjson = loadjsonfile("testdata/test-repo-startdate-tochange-query.json")
         self.assertEqual(testjson, expectedjson, "json-pushes did not yield expected json data!")
 
+class TestPushlogUserQueries(unittest.TestCase):
+    hgwebprocess = None
+    repodir = ''
+
+    def setUp(self):
+        "Untar the test repo and add the pushlog extension to it."
+        # unpack the test repo
+        repoarchive = os.path.join(mydir, "testdata/test-repo-users.tar.bz2")
+        repodir = "/tmp/hg-test/"
+        self.repodir = repodir
+        check_call(["rm", "-rf", repodir])
+        check_call(["tar", "xjf", repoarchive], cwd="/tmp")
+        write_hgrc(repodir)
+        ensure_templates()
+        # now run hg serve on it
+        self.hgwebprocess = Popen(["hg", "-R", repodir, "serve"], stdout=devnull, stderr=STDOUT)
+        # give it a second to be ready
+        sleep(1)
+        os.environ['TZ'] = "America/New_York"
+
+    def tearDown(self):
+        # kill hgweb process
+        if self.hgwebprocess is not None:
+            os.kill(self.hgwebprocess.pid, SIGTERM)
+            self.hgwebprocess = None
+
+    def testuserquery(self):
+        """Query for an individual user's pushes."""
+        testjson = loadjsonurl("http://localhost:8000/json-pushes?user=luser")
+        expectedjson = loadjsonfile("testdata/test-repo-user-luser.json")
+        self.assertEqual(testjson, expectedjson, "json-pushes did not yield expected json data!")
+        testjson = loadjsonurl("http://localhost:8000/json-pushes?user=someone")
+        expectedjson = loadjsonfile("testdata/test-repo-user-someone.json")
+        self.assertEqual(testjson, expectedjson, "json-pushes did not yield expected json data!")
+
+    def testmultiuserquery(self):
+        """Query for two users' pushes."""
+        testjson = loadjsonurl("http://localhost:8000/json-pushes?user=luser&user=someone")
+        expectedjson = loadjsonfile("testdata/test-repo-user-luser-someone.json")
+        self.assertEqual(testjson, expectedjson, "json-pushes did not yield expected json data!")
+
+    def testmultiuserstartidquery(self):
+        """Querying for all users' pushes + a startID should be equivalent to just querying for that startID."""
+        testjson = loadjsonurl("http://localhost:8000/json-pushes?user=luser&user=someone&user=johndoe&startID=20")
+        expectedjson = loadjsonurl("http://localhost:8000/json-pushes?startID=20")
+        self.assertEqual(testjson, expectedjson, "json-pushes did not yield expected json data!")
+
+    def testuserstartdatequery(self):
+        """Query for a user and a startdate."""
+        testjson = loadjsonurl("http://localhost:8000/json-pushes?user=luser&startdate=2008-11-21%2011:36:40")
+        expectedjson = loadjsonfile("testdata/test-repo-user-luser-startdate.json")
+
+    def testuserstartdateenddatequery(self):
+        """Query for a user with a startdate and an enddate."""
+        testjson = loadjsonurl("http://localhost:8000/json-pushes?user=luser&startdate=2008-11-21%2011:36:40&enddate=2008-11-21%2011:37:10")
+        expectedjson = loadjsonfile("testdata/test-repo-user-luser-startdate-enddate.json")
+
 if __name__ == '__main__':
     unittest.main()
new file mode 100644
--- /dev/null
+++ b/hgext/pushlog-legacy/testdata/test-repo-user-luser-someone.json
@@ -0,0 +1,169 @@
+{
+ "1": {
+  "date": 1227285382, 
+  "changesets": [
+   "82a183adcac8f198fce35618388dda055b312f16"
+  ], 
+  "user": "luser"
+ }, 
+ "2": {
+  "date": 1227285387, 
+  "changesets": [
+   "7d0c7e6804e863ef9c5529d93add6508bc91db5f", 
+   "e3299c6a5bfc06e97d1a04602a734a4563da10fa"
+  ], 
+  "user": "luser"
+ }, 
+ "3": {
+  "date": 1227285387, 
+  "changesets": [
+   "c8311f60f21bcfe26aed4caf8aa52dc805cb2d36", 
+   "bbb7e4566ca9ab3d1e20eef8f0ed95b1691836af"
+  ], 
+  "user": "someone"
+ }, 
+ "5": {
+  "date": 1227285393, 
+  "changesets": [
+   "8fb7b3c761187f553092ff6d834b3fa977175b01", 
+   "6d275508462ca92de798344fa0ff01695bf6bcae"
+  ], 
+  "user": "luser"
+ }, 
+ "6": {
+  "date": 1227285393, 
+  "changesets": [
+   "d43d28890f45de8a0385f2c32004b23d82feb9fd", 
+   "235f091ee07f0dceaa82e5b334c6a3699f81dd16"
+  ], 
+  "user": "someone"
+ }, 
+ "8": {
+  "date": 1227285399, 
+  "changesets": [
+   "59e7afd892d84c609f3a9c2b349ce14ff44b405a", 
+   "9611a64462f753471fd66109dc178e941288c492"
+  ], 
+  "user": "luser"
+ }, 
+ "9": {
+  "date": 1227285399, 
+  "changesets": [
+   "51dc6a719d2f59c5e7123d819506d19344939bad", 
+   "f529613a7153aaaaab0bda93cf8f3b26c9658574"
+  ], 
+  "user": "someone"
+ }, 
+ "11": {
+  "date": 1227285405, 
+  "changesets": [
+   "1c15de92d865cb59f9663e27f79bcf8296861812", 
+   "a97fae3d904e48233cbe2511d43594e1e2989e3c"
+  ], 
+  "user": "luser"
+ }, 
+ "12": {
+  "date": 1227285405, 
+  "changesets": [
+   "8ddbc1695c3851e16f5bd06252d35a65510d2c28", 
+   "6c7c0fa112e3696ce9ac0ef7c2a92e20248729d5"
+  ], 
+  "user": "someone"
+ }, 
+ "14": {
+  "date": 1227285411, 
+  "changesets": [
+   "d50331967a1546a9a5c2255f27f17b65ed00762a", 
+   "46cb21abac283daa27168869567d0d69446c9a4f"
+  ], 
+  "user": "luser"
+ }, 
+ "15": {
+  "date": 1227285411, 
+  "changesets": [
+   "537eb8ffb447a0d5c097dfb720e44242547a3bf1", 
+   "eac1e148871b1044caa72c395b85a2bf20c28ae0"
+  ], 
+  "user": "someone"
+ }, 
+ "17": {
+  "date": 1227285417, 
+  "changesets": [
+   "2ecb22462e0e76a30f8e37aeb135805ae23e5d89", 
+   "7ab06003dd0f773f445b1381aa7ddbbaca4a8185"
+  ], 
+  "user": "luser"
+ }, 
+ "18": {
+  "date": 1227285417, 
+  "changesets": [
+   "9cdb228fc89909791ad6960dd4c748a31b5c0a26", 
+   "a783678e6090c78677c87ce66ff750b2c728cd12"
+  ], 
+  "user": "someone"
+ }, 
+ "20": {
+  "date": 1227285423, 
+  "changesets": [
+   "5abaf9bbac91e5f587ce7712bfa112d0f5eff12c", 
+   "b7b01a0e779ca8acbf439456dc66b6ee7ece61de"
+  ], 
+  "user": "luser"
+ }, 
+ "21": {
+  "date": 1227285423, 
+  "changesets": [
+   "fd55cede0fed5a7daae158c3c1248ea546b2fc43", 
+   "fdf9029a566778d282178da28116cfca15a7552c"
+  ], 
+  "user": "someone"
+ }, 
+ "23": {
+  "date": 1227285429, 
+  "changesets": [
+   "ca915ef4f88089f5dc56f03c15d770d6583cfaea", 
+   "bd8f8e4817edca57783c95cde913f999a8b7310f"
+  ], 
+  "user": "luser"
+ }, 
+ "24": {
+  "date": 1227285429, 
+  "changesets": [
+   "1c5dd5f1dea7a96ce54f3c01cafe1856d2666527", 
+   "4eb202ea02522a752957f87c5d4c7ba09accefc1"
+  ], 
+  "user": "someone"
+ }, 
+ "26": {
+  "date": 1227285435, 
+  "changesets": [
+   "36907dc7d6e26700ab40ac62d219f2b721a19a94", 
+   "ce034385224fa359abe0384d0d1ba7c5b3525942"
+  ], 
+  "user": "luser"
+ }, 
+ "27": {
+  "date": 1227285435, 
+  "changesets": [
+   "f33863ab90b1f2acee779753b8f3cd1c3bb23cd3", 
+   "dc9f7a4a7b4fea591c010a4856158167e813e7c9"
+  ], 
+  "user": "someone"
+ }, 
+ "29": {
+  "date": 1227285441, 
+  "changesets": [
+   "edd2698e8172d1326f220d1cd747803fc8f9d61a", 
+   "bb17debf2f554dd71ab215755627c2770701fde2"
+  ], 
+  "user": "luser"
+ }, 
+ "30": {
+  "date": 1227285441, 
+  "changesets": [
+   "4353d15d5838b12c81861314fcf1e727b93b22e5", 
+   "51a1b7a730d8d242c05bac500b95d3eac102bf01"
+  ], 
+  "user": "someone"
+ }
+}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/hgext/pushlog-legacy/testdata/test-repo-user-luser-startdate-enddate.json
@@ -0,0 +1,42 @@
+{
+ "17": {
+  "date": 1227285417, 
+  "changesets": [
+   "2ecb22462e0e76a30f8e37aeb135805ae23e5d89", 
+   "7ab06003dd0f773f445b1381aa7ddbbaca4a8185"
+  ], 
+  "user": "luser"
+ }, 
+ "11": {
+  "date": 1227285405, 
+  "changesets": [
+   "1c15de92d865cb59f9663e27f79bcf8296861812", 
+   "a97fae3d904e48233cbe2511d43594e1e2989e3c"
+  ], 
+  "user": "luser"
+ }, 
+ "20": {
+  "date": 1227285423, 
+  "changesets": [
+   "5abaf9bbac91e5f587ce7712bfa112d0f5eff12c", 
+   "b7b01a0e779ca8acbf439456dc66b6ee7ece61de"
+  ], 
+  "user": "luser"
+ }, 
+ "14": {
+  "date": 1227285411, 
+  "changesets": [
+   "d50331967a1546a9a5c2255f27f17b65ed00762a", 
+   "46cb21abac283daa27168869567d0d69446c9a4f"
+  ], 
+  "user": "luser"
+ }, 
+ "23": {
+  "date": 1227285429, 
+  "changesets": [
+   "ca915ef4f88089f5dc56f03c15d770d6583cfaea", 
+   "bd8f8e4817edca57783c95cde913f999a8b7310f"
+  ], 
+  "user": "luser"
+ }
+}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/hgext/pushlog-legacy/testdata/test-repo-user-luser-startdate.json
@@ -0,0 +1,58 @@
+{
+ "11": {
+  "date": 1227285405, 
+  "changesets": [
+   "1c15de92d865cb59f9663e27f79bcf8296861812", 
+   "a97fae3d904e48233cbe2511d43594e1e2989e3c"
+  ], 
+  "user": "luser"
+ }, 
+ "14": {
+  "date": 1227285411, 
+  "changesets": [
+   "d50331967a1546a9a5c2255f27f17b65ed00762a", 
+   "46cb21abac283daa27168869567d0d69446c9a4f"
+  ], 
+  "user": "luser"
+ }, 
+ "17": {
+  "date": 1227285417, 
+  "changesets": [
+   "2ecb22462e0e76a30f8e37aeb135805ae23e5d89", 
+   "7ab06003dd0f773f445b1381aa7ddbbaca4a8185"
+  ], 
+  "user": "luser"
+ }, 
+ "20": {
+  "date": 1227285423, 
+  "changesets": [
+   "5abaf9bbac91e5f587ce7712bfa112d0f5eff12c", 
+   "b7b01a0e779ca8acbf439456dc66b6ee7ece61de"
+  ], 
+  "user": "luser"
+ }, 
+ "23": {
+  "date": 1227285429, 
+  "changesets": [
+   "ca915ef4f88089f5dc56f03c15d770d6583cfaea", 
+   "bd8f8e4817edca57783c95cde913f999a8b7310f"
+  ], 
+  "user": "luser"
+ }, 
+ "26": {
+  "date": 1227285435, 
+  "changesets": [
+   "36907dc7d6e26700ab40ac62d219f2b721a19a94", 
+   "ce034385224fa359abe0384d0d1ba7c5b3525942"
+  ], 
+  "user": "luser"
+ }, 
+ "29": {
+  "date": 1227285441, 
+  "changesets": [
+   "edd2698e8172d1326f220d1cd747803fc8f9d61a", 
+   "bb17debf2f554dd71ab215755627c2770701fde2"
+  ], 
+  "user": "luser"
+ }
+}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/hgext/pushlog-legacy/testdata/test-repo-user-luser.json
@@ -0,0 +1,89 @@
+{
+ "1": {
+  "date": 1227285382, 
+  "changesets": [
+   "82a183adcac8f198fce35618388dda055b312f16"
+  ], 
+  "user": "luser"
+ }, 
+ "2": {
+  "date": 1227285387, 
+  "changesets": [
+   "7d0c7e6804e863ef9c5529d93add6508bc91db5f", 
+   "e3299c6a5bfc06e97d1a04602a734a4563da10fa"
+  ], 
+  "user": "luser"
+ }, 
+ "5": {
+  "date": 1227285393, 
+  "changesets": [
+   "8fb7b3c761187f553092ff6d834b3fa977175b01", 
+   "6d275508462ca92de798344fa0ff01695bf6bcae"
+  ], 
+  "user": "luser"
+ }, 
+ "8": {
+  "date": 1227285399, 
+  "changesets": [
+   "59e7afd892d84c609f3a9c2b349ce14ff44b405a", 
+   "9611a64462f753471fd66109dc178e941288c492"
+  ], 
+  "user": "luser"
+ }, 
+ "11": {
+  "date": 1227285405, 
+  "changesets": [
+   "1c15de92d865cb59f9663e27f79bcf8296861812", 
+   "a97fae3d904e48233cbe2511d43594e1e2989e3c"
+  ], 
+  "user": "luser"
+ }, 
+ "14": {
+  "date": 1227285411, 
+  "changesets": [
+   "d50331967a1546a9a5c2255f27f17b65ed00762a", 
+   "46cb21abac283daa27168869567d0d69446c9a4f"
+  ], 
+  "user": "luser"
+ }, 
+ "17": {
+  "date": 1227285417, 
+  "changesets": [
+   "2ecb22462e0e76a30f8e37aeb135805ae23e5d89", 
+   "7ab06003dd0f773f445b1381aa7ddbbaca4a8185"
+  ], 
+  "user": "luser"
+ }, 
+ "20": {
+  "date": 1227285423, 
+  "changesets": [
+   "5abaf9bbac91e5f587ce7712bfa112d0f5eff12c", 
+   "b7b01a0e779ca8acbf439456dc66b6ee7ece61de"
+  ], 
+  "user": "luser"
+ }, 
+ "23": {
+  "date": 1227285429, 
+  "changesets": [
+   "ca915ef4f88089f5dc56f03c15d770d6583cfaea", 
+   "bd8f8e4817edca57783c95cde913f999a8b7310f"
+  ], 
+  "user": "luser"
+ }, 
+ "26": {
+  "date": 1227285435, 
+  "changesets": [
+   "36907dc7d6e26700ab40ac62d219f2b721a19a94", 
+   "ce034385224fa359abe0384d0d1ba7c5b3525942"
+  ], 
+  "user": "luser"
+ }, 
+ "29": {
+  "date": 1227285441, 
+  "changesets": [
+   "edd2698e8172d1326f220d1cd747803fc8f9d61a", 
+   "bb17debf2f554dd71ab215755627c2770701fde2"
+  ], 
+  "user": "luser"
+ }
+}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/hgext/pushlog-legacy/testdata/test-repo-user-someone.json
@@ -0,0 +1,82 @@
+{
+ "3": {
+  "date": 1227285387, 
+  "changesets": [
+   "c8311f60f21bcfe26aed4caf8aa52dc805cb2d36", 
+   "bbb7e4566ca9ab3d1e20eef8f0ed95b1691836af"
+  ], 
+  "user": "someone"
+ }, 
+ "6": {
+  "date": 1227285393, 
+  "changesets": [
+   "d43d28890f45de8a0385f2c32004b23d82feb9fd", 
+   "235f091ee07f0dceaa82e5b334c6a3699f81dd16"
+  ], 
+  "user": "someone"
+ }, 
+ "9": {
+  "date": 1227285399, 
+  "changesets": [
+   "51dc6a719d2f59c5e7123d819506d19344939bad", 
+   "f529613a7153aaaaab0bda93cf8f3b26c9658574"
+  ], 
+  "user": "someone"
+ }, 
+ "12": {
+  "date": 1227285405, 
+  "changesets": [
+   "8ddbc1695c3851e16f5bd06252d35a65510d2c28", 
+   "6c7c0fa112e3696ce9ac0ef7c2a92e20248729d5"
+  ], 
+  "user": "someone"
+ }, 
+ "15": {
+  "date": 1227285411, 
+  "changesets": [
+   "537eb8ffb447a0d5c097dfb720e44242547a3bf1", 
+   "eac1e148871b1044caa72c395b85a2bf20c28ae0"
+  ], 
+  "user": "someone"
+ }, 
+ "18": {
+  "date": 1227285417, 
+  "changesets": [
+   "9cdb228fc89909791ad6960dd4c748a31b5c0a26", 
+   "a783678e6090c78677c87ce66ff750b2c728cd12"
+  ], 
+  "user": "someone"
+ }, 
+ "21": {
+  "date": 1227285423, 
+  "changesets": [
+   "fd55cede0fed5a7daae158c3c1248ea546b2fc43", 
+   "fdf9029a566778d282178da28116cfca15a7552c"
+  ], 
+  "user": "someone"
+ }, 
+ "24": {
+  "date": 1227285429, 
+  "changesets": [
+   "1c5dd5f1dea7a96ce54f3c01cafe1856d2666527", 
+   "4eb202ea02522a752957f87c5d4c7ba09accefc1"
+  ], 
+  "user": "someone"
+ }, 
+ "27": {
+  "date": 1227285435, 
+  "changesets": [
+   "f33863ab90b1f2acee779753b8f3cd1c3bb23cd3", 
+   "dc9f7a4a7b4fea591c010a4856158167e813e7c9"
+  ], 
+  "user": "someone"
+ }, 
+ "30": {
+  "date": 1227285441, 
+  "changesets": [
+   "4353d15d5838b12c81861314fcf1e727b93b22e5", 
+   "51a1b7a730d8d242c05bac500b95d3eac102bf01"
+  ], 
+  "user": "someone"
+ }
+}
\ No newline at end of file
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..7b5827b81c8620cce1e548a2b764c86d053e6a32
GIT binary patch
literal 17693
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
IHRT5YKuHwa+W-In