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

login
register
mail settings
Submitter Anton Shestakov
Date Nov. 30, 2018, 11:30 a.m.
Message ID <081773196c85870990e9.1543577449@neuro>
Download mbox | patch
Permalink /patch/36874/
State Superseded
Headers show

Comments

Anton Shestakov - Nov. 30, 2018, 11:30 a.m.
# HG changeset patch
# User Anton Shestakov <av6@dwimlabs.net>
# Date 1541397139 -28800
#      Mon Nov 05 13:52:19 2018 +0800
# Node ID 081773196c85870990e9c438023c7665b1e73469
# 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'.

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=None,
+)
 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,34 @@  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', 'confirm', '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 == 'confirm':
+            if ui.promptchoice(_('push and publish %i changesets (yn)?'
+                                 '$$ &Yes $$ &No') % len(published)):
+                raise error.Abort(_('user quit'))
+        elif behavior == 'abort':
+            msg = _('push would publish %i changesets') % len(published)
+            hint = _("use --publish or adjust 'experimental.auto-publish'"
+                     " config")
+            raise error.Abort(msg, hint=hint)
+
 def _forcebundle1(op):
     """return true if a pull/push must use bundle1
 
@@ -533,6 +561,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,73 @@  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
+  (use --publish or adjust '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
+  (use --publish or adjust '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
+
+warn 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
+
+confirm behavior
+
+  $ mkcommit a-p-C
+  test-debug-phase: new rev 2:  x -> 1
+  $ hg push --config experimental.auto-publish=confirm
+  pushing to $TESTTMP/auto-publish-orig
+  push and publish 1 changesets (yn)? y
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 1 changes to 1 files
+  test-debug-phase: new rev 2:  x -> 0
+  test-debug-phase: move rev 2: 1 -> 0
+
+  $ cd ..
+
+
 --publish flag
 --------------