Patchwork push: config option to control behavior when pushing to a publishing server

login
register
mail settings
Submitter Anton Shestakov
Date Nov. 23, 2018, 5:23 a.m.
Message ID <ea18d94ac7006faff714.1542950623@neuro>
Download mbox | patch
Permalink /patch/36729/
State Superseded
Headers show

Comments

Anton Shestakov - Nov. 23, 2018, 5:23 a.m.
# HG changeset patch
# User Anton Shestakov <av6@dwimlabs.net>
# Date 1541397139 -28800
#      Mon Nov 05 13:52:19 2018 +0800
# Node ID ea18d94ac7006faff7148cb2eca3b970655955b9
# Parent  efd0f79246e3e6633dfd06226464a48584f69b19
# EXP-Topic push-publish
push: config option to control behavior when pushing to a publishing server

Pushing to a publishing server by mistake can lead to a difficult situation to
solve because evolution doesn't work on public changesets. This new
experimental config tries to help avoiding unintentionally (or at least being
aware of) pushing to publishing remotes.

`hg push --publish` can be used to make push succeed even when auto-publish is
set to 'abort'.
Yuya Nishihara - Nov. 25, 2018, 3:35 a.m.
On Fri, 23 Nov 2018 13:23:43 +0800, Anton Shestakov wrote:
> # HG changeset patch
> # User Anton Shestakov <av6@dwimlabs.net>
> # Date 1541397139 -28800
> #      Mon Nov 05 13:52:19 2018 +0800
> # Node ID ea18d94ac7006faff7148cb2eca3b970655955b9
> # Parent  efd0f79246e3e6633dfd06226464a48584f69b19
> # EXP-Topic push-publish
> push: config option to control behavior when pushing to a publishing server

> `hg push --publish` can be used to make push succeed even when auto-publish is
> set to 'abort'.
> 
> diff --git a/mercurial/configitems.py b/mercurial/configitems.py
> --- a/mercurial/configitems.py
> +++ b/mercurial/configitems.py
> @@ -449,6 +449,9 @@ coreconfigitem('email', 'to',
>  coreconfigitem('experimental', 'archivemetatemplate',
>      default=dynamicdefault,
>  )
> +coreconfigitem('experimental', 'auto-publish',
> +    default='ignore',

auto-publish=ignore sounds like the push operation will never promote the
changesets to public. Perhaps, it can be renamed to 'allow'?

> --- a/mercurial/exchange.py
> +++ b/mercurial/exchange.py
> @@ -334,6 +334,30 @@ def _computeoutgoing(repo, heads, common
>          heads = cl.heads()
>      return discovery.outgoing(repo, common, heads)
>  
> +def _checkpublish(pushop):
> +    repo = pushop.repo
> +    ui = repo.ui
> +    behavior = ui.config('experimental', 'auto-publish')
> +    if pushop.publish or behavior not in ('warn', 'abort'):
> +        return
> +    remotephases = listkeys(pushop.remote, 'phases')
> +    if not remotephases.get('publishing', False):
> +        return
> +
> +    if pushop.revs is None:
> +        published = repo.filtered('served').revs('not public()')
> +    else:
> +        published = repo.revs('::%ln - public()', pushop.revs)
> +    if published:
> +        if behavior == 'warn':
> +            ui.warn(_('%i changesets about to be published\n')
> +                    % len(published))

I don't think 'warn' is useful unless there's a reliable way to interrupt
the push operation.

> +        elif behavior == 'abort':
> +            msg = _('push would publish %i changesets') % len(published)
> +            hint = _("behavior controlled by 'experimental.auto-publish'"
> +                        " config")

Shouldn't we instead suggest "hg push --publish"?
Anton Shestakov - Nov. 30, 2018, 11:36 a.m.
On Sun, 25 Nov 2018 12:35:17 +0900
Yuya Nishihara <yuya@tcha.org> wrote:

> On Fri, 23 Nov 2018 13:23:43 +0800, Anton Shestakov wrote:
> > # HG changeset patch
> > # User Anton Shestakov <av6@dwimlabs.net>
> > # Date 1541397139 -28800
> > #      Mon Nov 05 13:52:19 2018 +0800
> > # Node ID ea18d94ac7006faff7148cb2eca3b970655955b9
> > # Parent  efd0f79246e3e6633dfd06226464a48584f69b19
> > # EXP-Topic push-publish
> > push: config option to control behavior when pushing to a publishing server  
> 
> > `hg push --publish` can be used to make push succeed even when auto-publish is
> > set to 'abort'.
> > 
> > diff --git a/mercurial/configitems.py b/mercurial/configitems.py
> > --- a/mercurial/configitems.py
> > +++ b/mercurial/configitems.py
> > @@ -449,6 +449,9 @@ coreconfigitem('email', 'to',
> >  coreconfigitem('experimental', 'archivemetatemplate',
> >      default=dynamicdefault,
> >  )
> > +coreconfigitem('experimental', 'auto-publish',
> > +    default='ignore',  
> 
> auto-publish=ignore sounds like the push operation will never promote the
> changesets to public. Perhaps, it can be renamed to 'allow'?

I did default=None in V2. 'allow' almost suggests that we can also
have auto-publish=disallow to prevent remote from publishing changesets,
but still receive them on push (which is not true).

> > --- a/mercurial/exchange.py
> > +++ b/mercurial/exchange.py
> > @@ -334,6 +334,30 @@ def _computeoutgoing(repo, heads, common
> >          heads = cl.heads()
> >      return discovery.outgoing(repo, common, heads)
> >  
> > +def _checkpublish(pushop):
> > +    repo = pushop.repo
> > +    ui = repo.ui
> > +    behavior = ui.config('experimental', 'auto-publish')
> > +    if pushop.publish or behavior not in ('warn', 'abort'):
> > +        return
> > +    remotephases = listkeys(pushop.remote, 'phases')
> > +    if not remotephases.get('publishing', False):
> > +        return
> > +
> > +    if pushop.revs is None:
> > +        published = repo.filtered('served').revs('not public()')
> > +    else:
> > +        published = repo.revs('::%ln - public()', pushop.revs)
> > +    if published:
> > +        if behavior == 'warn':
> > +            ui.warn(_('%i changesets about to be published\n')
> > +                    % len(published))  
> 
> I don't think 'warn' is useful unless there's a reliable way to interrupt
> the push operation.

I left 'warn' as an option, but there's now 'confirm' too.

> > +        elif behavior == 'abort':
> > +            msg = _('push would publish %i changesets') % len(published)
> > +            hint = _("behavior controlled by 'experimental.auto-publish'"
> > +                        " config")  
> 
> Shouldn't we instead suggest "hg push --publish"?

Yep. I've sent V2, sorry for the delay.
Anton Shestakov - Nov. 30, 2018, 2:43 p.m.
On Fri, 30 Nov 2018 19:36:28 +0800
Anton Shestakov <av6@dwimlabs.net> wrote:

> On Sun, 25 Nov 2018 12:35:17 +0900
> Yuya Nishihara <yuya@tcha.org> wrote:
> 
> > On Fri, 23 Nov 2018 13:23:43 +0800, Anton Shestakov wrote:  
> > > # HG changeset patch
> > > # User Anton Shestakov <av6@dwimlabs.net>
> > > # Date 1541397139 -28800
> > > #      Mon Nov 05 13:52:19 2018 +0800
> > > # Node ID ea18d94ac7006faff7148cb2eca3b970655955b9
> > > # Parent  efd0f79246e3e6633dfd06226464a48584f69b19
> > > # EXP-Topic push-publish
> > > push: config option to control behavior when pushing to a publishing server    
> >   
> > > `hg push --publish` can be used to make push succeed even when auto-publish is
> > > set to 'abort'.
> > > 
> > > diff --git a/mercurial/configitems.py b/mercurial/configitems.py
> > > --- a/mercurial/configitems.py
> > > +++ b/mercurial/configitems.py
> > > @@ -449,6 +449,9 @@ coreconfigitem('email', 'to',
> > >  coreconfigitem('experimental', 'archivemetatemplate',
> > >      default=dynamicdefault,
> > >  )
> > > +coreconfigitem('experimental', 'auto-publish',
> > > +    default='ignore',    
> > 
> > auto-publish=ignore sounds like the push operation will never promote the
> > changesets to public. Perhaps, it can be renamed to 'allow'?  
> 
> I did default=None in V2. 'allow' almost suggests that we can also
> have auto-publish=disallow to prevent remote from publishing changesets,
> but still receive them on push (which is not true).

I was suggested 'publish' as the default value so that it's a string and
users could revert to it freely, and I've used it in V3.

Patch

diff --git a/mercurial/configitems.py b/mercurial/configitems.py
--- a/mercurial/configitems.py
+++ b/mercurial/configitems.py
@@ -449,6 +449,9 @@  coreconfigitem('email', 'to',
 coreconfigitem('experimental', 'archivemetatemplate',
     default=dynamicdefault,
 )
+coreconfigitem('experimental', 'auto-publish',
+    default='ignore',
+)
 coreconfigitem('experimental', 'bundle-phases',
     default=False,
 )
diff --git a/mercurial/exchange.py b/mercurial/exchange.py
--- a/mercurial/exchange.py
+++ b/mercurial/exchange.py
@@ -334,6 +334,30 @@  def _computeoutgoing(repo, heads, common
         heads = cl.heads()
     return discovery.outgoing(repo, common, heads)
 
+def _checkpublish(pushop):
+    repo = pushop.repo
+    ui = repo.ui
+    behavior = ui.config('experimental', 'auto-publish')
+    if pushop.publish or behavior not in ('warn', 'abort'):
+        return
+    remotephases = listkeys(pushop.remote, 'phases')
+    if not remotephases.get('publishing', False):
+        return
+
+    if pushop.revs is None:
+        published = repo.filtered('served').revs('not public()')
+    else:
+        published = repo.revs('::%ln - public()', pushop.revs)
+    if published:
+        if behavior == 'warn':
+            ui.warn(_('%i changesets about to be published\n')
+                    % len(published))
+        elif behavior == 'abort':
+            msg = _('push would publish %i changesets') % len(published)
+            hint = _("behavior controlled by 'experimental.auto-publish'"
+                        " config")
+            raise error.Abort(msg, hint=hint)
+
 def _forcebundle1(op):
     """return true if a pull/push must use bundle1
 
@@ -533,6 +557,7 @@  def push(repo, remote, force=False, revs
             lock or util.nullcontextmanager(), \
             pushop.trmanager or util.nullcontextmanager():
         pushop.repo.checkpush(pushop)
+        _checkpublish(pushop)
         _pushdiscovery(pushop)
         if not _forcebundle1(pushop):
             _pushbundle2(pushop)
diff --git a/tests/test-phases-exchange.t b/tests/test-phases-exchange.t
--- a/tests/test-phases-exchange.t
+++ b/tests/test-phases-exchange.t
@@ -1562,6 +1562,58 @@  of phase heads computation)
   $ killdaemons.py
 
 
+auto-publish config
+-------------------
+
+  $ hg init auto-publish-orig
+  $ hg clone -q auto-publish-orig auto-publish-clone
+  $ cd auto-publish-clone
+  $ mkcommit a-p-A
+  test-debug-phase: new rev 0:  x -> 1
+  $ mkcommit a-p-B
+  test-debug-phase: new rev 1:  x -> 1
+
+abort behavior
+
+  $ hg push --config experimental.auto-publish=abort
+  pushing to $TESTTMP/auto-publish-orig
+  abort: push would publish 2 changesets
+  (behavior controlled by 'experimental.auto-publish' config)
+  [255]
+  $ hg push -r '.^' --config experimental.auto-publish=abort
+  pushing to $TESTTMP/auto-publish-orig
+  abort: push would publish 1 changesets
+  (behavior controlled by 'experimental.auto-publish' config)
+  [255]
+
+--publish flag makes push succeed
+
+  $ hg push -r '.^' --publish --config experimental.auto-publish=abort
+  pushing to $TESTTMP/auto-publish-orig
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 1 changes to 1 files
+  test-debug-phase: new rev 0:  x -> 0
+  test-debug-phase: move rev 0: 1 -> 0
+
+warning behavior
+
+  $ hg push --config experimental.auto-publish=warn
+  pushing to $TESTTMP/auto-publish-orig
+  1 changesets about to be published
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 1 changes to 1 files
+  test-debug-phase: new rev 1:  x -> 0
+  test-debug-phase: move rev 1: 1 -> 0
+
+  $ cd ..
+
+
 --publish flag
 --------------