Patchwork [6,of,9,V3] template: compute user in obsfateusers

login
register
mail settings
Submitter Boris Feld
Date Aug. 21, 2017, 8:43 a.m.
Message ID <2fee3b06f7b09f35dcfa.1503305038@FB>
Download mbox | patch
Permalink /patch/23169/
State Superseded
Headers show

Comments

Boris Feld - Aug. 21, 2017, 8:43 a.m.
# HG changeset patch
# User Boris Feld <boris.feld@octobus.net>
# Date 1499088840 -7200
#      Mon Jul 03 15:34:00 2017 +0200
# Node ID 2fee3b06f7b09f35dcfa312b645cf94090c11fb9
# Parent  66a2b0407c8cffedfae4897bd7a2f0e2d6a22363
# EXP-Topic obsfatetemplate
template: compute user in obsfateusers

Extract, deduplicate users informations from obs markers in order to display
them.

Print all users for the moment, we might want to display users only in verbose
mode later.
Denis Laxalde - Aug. 21, 2017, 10:55 a.m.
Boris Feld a écrit :
> # HG changeset patch
> # User Boris Feld <boris.feld@octobus.net>
> # Date 1499088840 -7200
> #      Mon Jul 03 15:34:00 2017 +0200
> # Node ID 2fee3b06f7b09f35dcfa312b645cf94090c11fb9
> # Parent  66a2b0407c8cffedfae4897bd7a2f0e2d6a22363
> # EXP-Topic obsfatetemplate
> template: compute user in obsfateusers
> 
> Extract, deduplicate users informations from obs markers in order to display
> them.
> 
> Print all users for the moment, we might want to display users only in verbose
> mode later.
> 
> diff -r 66a2b0407c8c -r 2fee3b06f7b0 mercurial/obsutil.py
> --- a/mercurial/obsutil.py	Mon Jul 03 15:33:27 2017 +0200
> +++ b/mercurial/obsutil.py	Mon Jul 03 15:34:00 2017 +0200
> @@ -579,6 +579,18 @@
>           verb = 'split'
>       return {'verb': verb}
>   
> +def _successorsetusers(successorset, markers):
> +    """ Returns a sorted list of markers users without duplicates
> +    """
> +    if not markers:
> +        return {}
> +
> +    # Check that user is present in meta
> +    markersmeta = [dict(m[3]) for m in markers]
> +    users = set(meta.get('user') for meta in markersmeta if meta.get('user'))
> +
> +    return {'users': sorted(users)}

"users" set might be empty, do we want an empty dict instead in this case?

> +
>   def successorsandmarkers(repo, ctx):
>       """compute the raw data needed for computing obsfate
>       Returns a list of dict, one dict per successors set
> diff -r 66a2b0407c8c -r 2fee3b06f7b0 mercurial/templater.py
> --- a/mercurial/templater.py	Mon Jul 03 15:33:27 2017 +0200
> +++ b/mercurial/templater.py	Mon Jul 03 15:34:00 2017 +0200
> @@ -859,6 +859,24 @@
>   
>       return obsutil._successorsetverb(successors, markers)['verb']
>   
> +@templatefunc('obsfateusers(successors, markers)')
> +def obsfateusers(context, mapping, args):
> +    """ Compute obsfate related information based on successors and markers
> +    """
> +    successors = evalfuncarg(context, mapping, args[0])
> +    markers = evalfuncarg(context, mapping, args[1])
> +    data = obsutil._successorsetusers(successors, markers)
> +
> +    _hybrid = templatekw._hybrid
> +
> +    def makemap(x):
> +        return x
> +
> +    def joinfmt(d):
> +        return d
> +
> +    return _hybrid(None, [data], makemap, joinfmt)
> +
>   @templatefunc('relpath(path)')
>   def relpath(context, mapping, args):
>       """Convert a repository-absolute path into a filesystem path relative to
Boris Feld - Aug. 21, 2017, 1:05 p.m.
On Mon, 2017-08-21 at 12:55 +0200, Denis Laxalde wrote:
> Boris Feld a écrit :
> > # HG changeset patch
> > # User Boris Feld <boris.feld@octobus.net>
> > # Date 1499088840 -7200
> > #      Mon Jul 03 15:34:00 2017 +0200
> > # Node ID 2fee3b06f7b09f35dcfa312b645cf94090c11fb9
> > # Parent  66a2b0407c8cffedfae4897bd7a2f0e2d6a22363
> > # EXP-Topic obsfatetemplate
> > template: compute user in obsfateusers
> > 
> > Extract, deduplicate users informations from obs markers in order
> > to display
> > them.
> > 
> > Print all users for the moment, we might want to display users only
> > in verbose
> > mode later.
> > 
> > diff -r 66a2b0407c8c -r 2fee3b06f7b0 mercurial/obsutil.py
> > --- a/mercurial/obsutil.py	Mon Jul 03 15:33:27 2017 +0200
> > +++ b/mercurial/obsutil.py	Mon Jul 03 15:34:00 2017 +0200
> > @@ -579,6 +579,18 @@
> >           verb = 'split'
> >       return {'verb': verb}
> >   
> > +def _successorsetusers(successorset, markers):
> > +    """ Returns a sorted list of markers users without duplicates
> > +    """
> > +    if not markers:
> > +        return {}
> > +
> > +    # Check that user is present in meta
> > +    markersmeta = [dict(m[3]) for m in markers]
> > +    users = set(meta.get('user') for meta in markersmeta if
> > meta.get('user'))
> > +
> > +    return {'users': sorted(users)}
> 
> "users" set might be empty, do we want an empty dict instead in this
> case?

I think we want to distinguish the case where we don't have any marker
(empty dict) from the case markers are missing users information (empty
'users' list) which shouldn't be frequent.

We could also returns directly the users, the dict is an artifact of
the previous version of this series.

> 
> > +
> >   def successorsandmarkers(repo, ctx):
> >       """compute the raw data needed for computing obsfate
> >       Returns a list of dict, one dict per successors set
> > diff -r 66a2b0407c8c -r 2fee3b06f7b0 mercurial/templater.py
> > --- a/mercurial/templater.py	Mon Jul 03 15:33:27 2017 +0200
> > +++ b/mercurial/templater.py	Mon Jul 03 15:34:00 2017 +0200
> > @@ -859,6 +859,24 @@
> >   
> >       return obsutil._successorsetverb(successors, markers)['verb']
> >   
> > +@templatefunc('obsfateusers(successors, markers)')
> > +def obsfateusers(context, mapping, args):
> > +    """ Compute obsfate related information based on successors
> > and markers
> > +    """
> > +    successors = evalfuncarg(context, mapping, args[0])
> > +    markers = evalfuncarg(context, mapping, args[1])
> > +    data = obsutil._successorsetusers(successors, markers)
> > +
> > +    _hybrid = templatekw._hybrid
> > +
> > +    def makemap(x):
> > +        return x
> > +
> > +    def joinfmt(d):
> > +        return d
> > +
> > +    return _hybrid(None, [data], makemap, joinfmt)
> > +
> >   @templatefunc('relpath(path)')
> >   def relpath(context, mapping, args):
> >       """Convert a repository-absolute path into a filesystem path
> > relative to
Yuya Nishihara - Aug. 22, 2017, 3:02 p.m.
On Mon, 21 Aug 2017 10:43:58 +0200, Boris Feld wrote:
> # HG changeset patch
> # User Boris Feld <boris.feld@octobus.net>
> # Date 1499088840 -7200
> #      Mon Jul 03 15:34:00 2017 +0200
> # Node ID 2fee3b06f7b09f35dcfa312b645cf94090c11fb9
> # Parent  66a2b0407c8cffedfae4897bd7a2f0e2d6a22363
> # EXP-Topic obsfatetemplate
> template: compute user in obsfateusers

> +def _successorsetusers(successorset, markers):
> +    """ Returns a sorted list of markers users without duplicates
> +    """
> +    if not markers:
> +        return {}
> +
> +    # Check that user is present in meta
> +    markersmeta = [dict(m[3]) for m in markers]
> +    users = set(meta.get('user') for meta in markersmeta if meta.get('user'))
> +
> +    return {'users': sorted(users)}

[...]

> +@templatefunc('obsfateusers(successors, markers)')
> +def obsfateusers(context, mapping, args):
> +    """ Compute obsfate related information based on successors and markers
> +    """
> +    successors = evalfuncarg(context, mapping, args[0])
> +    markers = evalfuncarg(context, mapping, args[1])
> +    data = obsutil._successorsetusers(successors, markers)
> +
> +    _hybrid = templatekw._hybrid
> +
> +    def makemap(x):
> +        return x
> +
> +    def joinfmt(d):
> +        return d
> +
> +    return _hybrid(None, [data], makemap, joinfmt)

Why isn't this a list of users, but a list of dict of list of users?
Boris Feld - Aug. 23, 2017, 2:31 p.m.
On Wed, 2017-08-23 at 00:02 +0900, Yuya Nishihara wrote:
> On Mon, 21 Aug 2017 10:43:58 +0200, Boris Feld wrote:
> > # HG changeset patch
> > # User Boris Feld <boris.feld@octobus.net>
> > # Date 1499088840 -7200
> > #      Mon Jul 03 15:34:00 2017 +0200
> > # Node ID 2fee3b06f7b09f35dcfa312b645cf94090c11fb9
> > # Parent  66a2b0407c8cffedfae4897bd7a2f0e2d6a22363
> > # EXP-Topic obsfatetemplate
> > template: compute user in obsfateusers
> > +def _successorsetusers(successorset, markers):
> > +    """ Returns a sorted list of markers users without duplicates
> > +    """
> > +    if not markers:
> > +        return {}
> > +
> > +    # Check that user is present in meta
> > +    markersmeta = [dict(m[3]) for m in markers]
> > +    users = set(meta.get('user') for meta in markersmeta if
> > meta.get('user'))
> > +
> > +    return {'users': sorted(users)}
> 
> [...]
> 
> > +@templatefunc('obsfateusers(successors, markers)')
> > +def obsfateusers(context, mapping, args):
> > +    """ Compute obsfate related information based on successors
> > and markers
> > +    """
> > +    successors = evalfuncarg(context, mapping, args[0])
> > +    markers = evalfuncarg(context, mapping, args[1])
> > +    data = obsutil._successorsetusers(successors, markers)
> > +
> > +    _hybrid = templatekw._hybrid
> > +
> > +    def makemap(x):
> > +        return x
> > +
> > +    def joinfmt(d):
> > +        return d
> > +
> > +    return _hybrid(None, [data], makemap, joinfmt)
> 
> Why isn't this a list of users, but a list of dict of list of users?

It was a artifact from the previous version of the series. It was meant
to permit this notation:

obsfateusers(successors, markers) % "{if(users, " by {join(users, ",
")}")}"

I've tried cleaning it, code is cleaner and the template is slighty
less clean now:

{if(obsfateusers(markers), " by {join(obsfateusers(markers), ", ")}")}
Yuya Nishihara - Aug. 23, 2017, 2:56 p.m.
On Wed, 23 Aug 2017 16:31:21 +0200, Boris Feld wrote:
> On Wed, 2017-08-23 at 00:02 +0900, Yuya Nishihara wrote:
> > On Mon, 21 Aug 2017 10:43:58 +0200, Boris Feld wrote:
> > > # HG changeset patch
> > > # User Boris Feld <boris.feld@octobus.net>
> > > # Date 1499088840 -7200
> > > #      Mon Jul 03 15:34:00 2017 +0200
> > > # Node ID 2fee3b06f7b09f35dcfa312b645cf94090c11fb9
> > > # Parent  66a2b0407c8cffedfae4897bd7a2f0e2d6a22363
> > > # EXP-Topic obsfatetemplate
> > > template: compute user in obsfateusers
> > > +def _successorsetusers(successorset, markers):
> > > +    """ Returns a sorted list of markers users without duplicates
> > > +    """
> > > +    if not markers:
> > > +        return {}
> > > +
> > > +    # Check that user is present in meta
> > > +    markersmeta = [dict(m[3]) for m in markers]
> > > +    users = set(meta.get('user') for meta in markersmeta if
> > > meta.get('user'))
> > > +
> > > +    return {'users': sorted(users)}
> > 
> > [...]
> > 
> > > +@templatefunc('obsfateusers(successors, markers)')
> > > +def obsfateusers(context, mapping, args):
> > > +    """ Compute obsfate related information based on successors
> > > and markers
> > > +    """
> > > +    successors = evalfuncarg(context, mapping, args[0])
> > > +    markers = evalfuncarg(context, mapping, args[1])
> > > +    data = obsutil._successorsetusers(successors, markers)
> > > +
> > > +    _hybrid = templatekw._hybrid
> > > +
> > > +    def makemap(x):
> > > +        return x
> > > +
> > > +    def joinfmt(d):
> > > +        return d
> > > +
> > > +    return _hybrid(None, [data], makemap, joinfmt)
> > 
> > Why isn't this a list of users, but a list of dict of list of users?
> 
> It was a artifact from the previous version of the series. It was meant
> to permit this notation:
> 
> obsfateusers(successors, markers) % "{if(users, " by {join(users, ",
> ")}")}"
> 
> I've tried cleaning it, code is cleaner and the template is slighty
> less clean now:
> 
> {if(obsfateusers(markers), " by {join(obsfateusers(markers), ", ")}")}

obsfateusers(markers) could be a templatealias or a keyword in mapfile.

  # .hgrc
  [templatealias]
  x = obsfateusers(markers)

  # mapfile
  x = '{join(obsfateusers(markers), ", ")}'
  ... = '{if(x, " by {x}")}'

I don't think it's good idea to design a template keyword/function for
a specific use case.

Patch

diff -r 66a2b0407c8c -r 2fee3b06f7b0 mercurial/obsutil.py
--- a/mercurial/obsutil.py	Mon Jul 03 15:33:27 2017 +0200
+++ b/mercurial/obsutil.py	Mon Jul 03 15:34:00 2017 +0200
@@ -579,6 +579,18 @@ 
         verb = 'split'
     return {'verb': verb}
 
+def _successorsetusers(successorset, markers):
+    """ Returns a sorted list of markers users without duplicates
+    """
+    if not markers:
+        return {}
+
+    # Check that user is present in meta
+    markersmeta = [dict(m[3]) for m in markers]
+    users = set(meta.get('user') for meta in markersmeta if meta.get('user'))
+
+    return {'users': sorted(users)}
+
 def successorsandmarkers(repo, ctx):
     """compute the raw data needed for computing obsfate
     Returns a list of dict, one dict per successors set
diff -r 66a2b0407c8c -r 2fee3b06f7b0 mercurial/templater.py
--- a/mercurial/templater.py	Mon Jul 03 15:33:27 2017 +0200
+++ b/mercurial/templater.py	Mon Jul 03 15:34:00 2017 +0200
@@ -859,6 +859,24 @@ 
 
     return obsutil._successorsetverb(successors, markers)['verb']
 
+@templatefunc('obsfateusers(successors, markers)')
+def obsfateusers(context, mapping, args):
+    """ Compute obsfate related information based on successors and markers
+    """
+    successors = evalfuncarg(context, mapping, args[0])
+    markers = evalfuncarg(context, mapping, args[1])
+    data = obsutil._successorsetusers(successors, markers)
+
+    _hybrid = templatekw._hybrid
+
+    def makemap(x):
+        return x
+
+    def joinfmt(d):
+        return d
+
+    return _hybrid(None, [data], makemap, joinfmt)
+
 @templatefunc('relpath(path)')
 def relpath(context, mapping, args):
     """Convert a repository-absolute path into a filesystem path relative to
diff -r 66a2b0407c8c -r 2fee3b06f7b0 tests/test-obsmarker-template.t
--- a/tests/test-obsmarker-template.t	Mon Jul 03 15:33:27 2017 +0200
+++ b/tests/test-obsmarker-template.t	Mon Jul 03 15:34:00 2017 +0200
@@ -14,7 +14,9 @@ 
   > [templates]
   > obsfatesuccessors = " as {join(successors, ", ")}"
   > obsfateverb = "{obsfateverb(successors, markers)}"
-  > obsfate = "{obsfateverb}{obsfatesuccessors}; "
+  > obsfateuserstmpl = "{if(users, " by {join(users, ", ")}")}"
+  > obsfateusers = "{obsfateusers(successors, markers) % "{obsfateuserstmpl}"}"
+  > obsfate = "{obsfateverb}{obsfatesuccessors}{obsfateusers}; "
   > [alias]
   > tlog = log -G -T '{node|short}\
   >     {if(predecessors, "\n  Predecessors: {predecessors}")}\
@@ -93,21 +95,21 @@ 
   o  d004c8f274b9
   |
   | @  471f378eab4c
-  |/     Obsfate: rewritten as 4:d004c8f274b9;
+  |/     Obsfate: rewritten as 4:d004c8f274b9 by test1, test2;
   o  ea207398892e
   
   $ hg fatelog
   o  d004c8f274b9
   |
   | @  471f378eab4c
-  |/     Obsfate: rewritten as 4:d004c8f274b9;
+  |/     Obsfate: rewritten as 4:d004c8f274b9 by test1, test2;
   o  ea207398892e
   
   $ hg fatelog -v
   o  d004c8f274b9
   |
   | @  471f378eab4c
-  |/     Obsfate: rewritten as 4:d004c8f274b9;
+  |/     Obsfate: rewritten as 4:d004c8f274b9 by test1, test2;
   o  ea207398892e
   
   $ hg up 'desc(A1)' --hidden
@@ -130,7 +132,7 @@ 
   o  d004c8f274b9
   |
   | @  a468dc9b3633
-  |/     Obsfate: rewritten as 4:d004c8f274b9;
+  |/     Obsfate: rewritten as 4:d004c8f274b9 by test2;
   o  ea207398892e
   
 Predecessors template should show all the predecessors as we force their display
@@ -161,11 +163,11 @@ 
   o  d004c8f274b9
   |
   | @  a468dc9b3633
-  |/     Obsfate: rewritten as 4:d004c8f274b9;
+  |/     Obsfate: rewritten as 4:d004c8f274b9 by test2;
   | x  f137d23bb3e1
   | |
   | x  471f378eab4c
-  |/     Obsfate: rewritten as 3:a468dc9b3633;
+  |/     Obsfate: rewritten as 3:a468dc9b3633 by test1;
   o  ea207398892e
   
 
@@ -210,14 +212,13 @@ 
   @  d004c8f274b9
   |
   | x  a468dc9b3633
-  |/     Obsfate: rewritten as 4:d004c8f274b9;
+  |/     Obsfate: rewritten as 4:d004c8f274b9 by test2;
   | x  f137d23bb3e1
   | |
   | x  471f378eab4c
-  |/     Obsfate: rewritten as 3:a468dc9b3633;
+  |/     Obsfate: rewritten as 3:a468dc9b3633 by test1;
   o  ea207398892e
   
-
   $ hg fatelogjson --hidden
   @  d004c8f274b9
   |
@@ -319,7 +320,7 @@ 
   o  337fec4d2edc
   |
   | @  471597cad322
-  |/     Obsfate: split as 2:337fec4d2edc, 3:f257fde29c7a;
+  |/     Obsfate: split as 2:337fec4d2edc, 3:f257fde29c7a by test;
   o  ea207398892e
   
   $ hg up f257fde29c7a
@@ -360,7 +361,7 @@ 
   o  337fec4d2edc
   |
   | x  471597cad322
-  |/     Obsfate: split as 2:337fec4d2edc, 3:f257fde29c7a;
+  |/     Obsfate: split as 2:337fec4d2edc, 3:f257fde29c7a by test;
   o  ea207398892e
   
   $ hg fatelogjson --hidden
@@ -461,7 +462,7 @@ 
   o  eb5a0daa2192
   |
   | @  471f378eab4c
-  |/     Obsfate: rewritten as 3:eb5a0daa2192;
+  |/     Obsfate: rewritten as 3:eb5a0daa2192 by test;
   o  ea207398892e
   
   $ hg up 'desc(B0)' --hidden
@@ -490,9 +491,9 @@ 
   o  eb5a0daa2192
   |
   | @  0dec01379d3b
-  | |    Obsfate: rewritten as 3:eb5a0daa2192;
+  | |    Obsfate: rewritten as 3:eb5a0daa2192 by test;
   | x  471f378eab4c
-  |/     Obsfate: rewritten as 3:eb5a0daa2192;
+  |/     Obsfate: rewritten as 3:eb5a0daa2192 by test;
   o  ea207398892e
   
   $ hg up 'desc(C0)'
@@ -528,9 +529,9 @@ 
   @  eb5a0daa2192
   |
   | x  0dec01379d3b
-  | |    Obsfate: rewritten as 3:eb5a0daa2192;
+  | |    Obsfate: rewritten as 3:eb5a0daa2192 by test;
   | x  471f378eab4c
-  |/     Obsfate: rewritten as 3:eb5a0daa2192;
+  |/     Obsfate: rewritten as 3:eb5a0daa2192 by test;
   o  ea207398892e
   
 
@@ -667,7 +668,7 @@ 
   | o  fdf9bde5129a
   |/
   | @  471f378eab4c
-  |/     Obsfate: rewritten as 2:fdf9bde5129a; rewritten as 4:019fadeab383;
+  |/     Obsfate: rewritten as 2:fdf9bde5129a by test; rewritten as 4:019fadeab383 by test;
   o  ea207398892e
   
   $ hg up 'desc(A1)'
@@ -723,11 +724,11 @@ 
   o  019fadeab383
   |
   | x  65b757b745b9
-  |/     Obsfate: rewritten as 4:019fadeab383;
+  |/     Obsfate: rewritten as 4:019fadeab383 by test;
   | @  fdf9bde5129a
   |/
   | x  471f378eab4c
-  |/     Obsfate: rewritten as 2:fdf9bde5129a; rewritten as 3:65b757b745b9;
+  |/     Obsfate: rewritten as 2:fdf9bde5129a by test; rewritten as 3:65b757b745b9 by test;
   o  ea207398892e
   
 
@@ -845,7 +846,7 @@ 
   o  eb5a0daa2192
   |
   | @  471f378eab4c
-  |/     Obsfate: rewritten as 4:eb5a0daa2192;
+  |/     Obsfate: rewritten as 4:eb5a0daa2192 by test;
   o  ea207398892e
   
   $ hg up 'desc(B0)' --hidden
@@ -873,9 +874,9 @@ 
   o  eb5a0daa2192
   |
   | @  0dec01379d3b
-  | |    Obsfate: rewritten as 4:eb5a0daa2192;
+  | |    Obsfate: rewritten as 4:eb5a0daa2192 by test;
   | x  471f378eab4c
-  |/     Obsfate: rewritten as 4:eb5a0daa2192;
+  |/     Obsfate: rewritten as 4:eb5a0daa2192 by test;
   o  ea207398892e
   
   $ hg up 'desc(B1)' --hidden
@@ -903,9 +904,9 @@ 
   o  eb5a0daa2192
   |
   | @  b7ea6d14e664
-  | |    Obsfate: rewritten as 4:eb5a0daa2192;
+  | |    Obsfate: rewritten as 4:eb5a0daa2192 by test;
   | x  471f378eab4c
-  |/     Obsfate: rewritten as 4:eb5a0daa2192;
+  |/     Obsfate: rewritten as 4:eb5a0daa2192 by test;
   o  ea207398892e
   
   $ hg up 'desc(C0)'
@@ -954,11 +955,11 @@ 
   @  eb5a0daa2192
   |
   | x  b7ea6d14e664
-  | |    Obsfate: rewritten as 4:eb5a0daa2192;
+  | |    Obsfate: rewritten as 4:eb5a0daa2192 by test;
   | | x  0dec01379d3b
-  | |/     Obsfate: rewritten as 3:b7ea6d14e664;
+  | |/     Obsfate: rewritten as 3:b7ea6d14e664 by test;
   | x  471f378eab4c
-  |/     Obsfate: rewritten as 4:eb5a0daa2192;
+  |/     Obsfate: rewritten as 4:eb5a0daa2192 by test;
   o  ea207398892e
   
 
@@ -1082,7 +1083,7 @@ 
   o  7a230b46bf61
   |
   | @  471f378eab4c
-  |/     Obsfate: rewritten as 2:7a230b46bf61;
+  |/     Obsfate: rewritten as 2:7a230b46bf61 by test;
   o  ea207398892e
   
   $ hg up 'desc(A2)'
@@ -1119,7 +1120,7 @@ 
   @  7a230b46bf61
   |
   | x  471f378eab4c
-  |/     Obsfate: rewritten as 2:7a230b46bf61;
+  |/     Obsfate: rewritten as 2:7a230b46bf61 by test;
   o  ea207398892e
   
 
@@ -1194,9 +1195,9 @@ 
   o  f897c6137566
   |
   | @  0dec01379d3b
-  | |    Obsfate: rewritten as 3:f897c6137566; rewritten as 1:471f378eab4c;
+  | |    Obsfate: rewritten as 3:f897c6137566 by test; rewritten as 1:471f378eab4c by test;
   | x  471f378eab4c
-  |/     Obsfate: rewritten as 2:0dec01379d3b;
+  |/     Obsfate: rewritten as 2:0dec01379d3b by test;
   o  ea207398892e
   
 
@@ -1452,7 +1453,7 @@ 
   | o  ba2ed02b0c9a
   | |
   | x  4a004186e638
-  |/     Obsfate: rewritten as 8:b18bc8331526; rewritten as 9:0b997eb7ceee;
+  |/     Obsfate: rewritten as 8:b18bc8331526 by test; rewritten as 9:0b997eb7ceee by test;
   o  dd800401bd8c
   |
   o  f897c6137566
@@ -1525,17 +1526,17 @@ 
   | o  ba2ed02b0c9a
   | |
   | x  4a004186e638
-  |/     Obsfate: rewritten as 8:b18bc8331526; rewritten as 9:0b997eb7ceee;
+  |/     Obsfate: rewritten as 8:b18bc8331526 by test; rewritten as 9:0b997eb7ceee by test;
   o  dd800401bd8c
   |
   | x  9bd10a0775e4
-  |/     Obsfate: split as 5:dd800401bd8c, 6:4a004186e638, 7:ba2ed02b0c9a;
+  |/     Obsfate: split as 5:dd800401bd8c, 6:4a004186e638, 7:ba2ed02b0c9a by test;
   o  f897c6137566
   |
   | x  0dec01379d3b
-  | |    Obsfate: rewritten as 3:f897c6137566; rewritten as 1:471f378eab4c;
+  | |    Obsfate: rewritten as 3:f897c6137566 by test; rewritten as 1:471f378eab4c by test;
   | x  471f378eab4c
-  |/     Obsfate: rewritten as 2:0dec01379d3b;
+  |/     Obsfate: rewritten as 2:0dec01379d3b by test;
   o  ea207398892e
   
   $ hg fatelogjson --hidden
@@ -1604,7 +1605,7 @@ 
   o  dd800401bd8c
   |
   | @  9bd10a0775e4
-  |/     Obsfate: split as 5:dd800401bd8c, 9:0b997eb7ceee, 10:eceed8f98ffc; split as 5:dd800401bd8c, 8:b18bc8331526, 10:eceed8f98ffc;
+  |/     Obsfate: split as 5:dd800401bd8c, 9:0b997eb7ceee, 10:eceed8f98ffc by test; split as 5:dd800401bd8c, 8:b18bc8331526, 10:eceed8f98ffc by test;
   o  f897c6137566
   |
   o  ea207398892e