Patchwork D210: pushvars: move fb extension pushvars to core

login
register
mail settings
Submitter phabricator
Date Aug. 2, 2017, 9:03 p.m.
Message ID <aaab89852ae2a116e26524392a95e6f2@localhost.localdomain>
Download mbox | patch
Permalink /patch/22648/
State Not Applicable
Headers show

Comments

phabricator - Aug. 2, 2017, 9:03 p.m.
pulkit updated this revision to Diff 512.
pulkit edited the summary of this revision.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D210?vs=493&id=512

REVISION DETAIL
  https://phab.mercurial-scm.org/D210

AFFECTED FILES
  mercurial/bundle2.py
  mercurial/commands.py
  mercurial/exchange.py
  tests/test-completion.t
  tests/test-pushvars.t

CHANGE DETAILS




To: pulkit, #hg-reviewers
Cc: quark, durin42, akushner, mercurial-devel

Patch

diff --git a/tests/test-pushvars.t b/tests/test-pushvars.t
new file mode 100644
--- /dev/null
+++ b/tests/test-pushvars.t
@@ -0,0 +1,71 @@ 
+Setup
+
+  $ PYTHONPATH=$TESTDIR/..:$PYTHONPATH
+  $ export PYTHONPATH
+
+  $ cat > $TESTTMP/pretxnchangegroup.sh << EOF
+  > #!/bin/sh
+  > env | egrep "^HG_USERVAR_(DEBUG|BYPASS_REVIEW)" | sort
+  > exit 0
+  > EOF
+  $ chmod +x $TESTTMP/pretxnchangegroup.sh
+  $ cat >> $HGRCPATH << EOF
+  > [hooks]
+  > pretxnchangegroup = $TESTTMP/pretxnchangegroup.sh
+  > [experimental]
+  > bundle2-exp = true
+  > EOF
+
+  $ hg init repo
+  $ hg clone -q repo child
+  $ cd child
+
+Test pushing vars to repo with pushvars.server not set
+
+  $ echo b > a
+  $ hg commit -Aqm a
+  $ hg push --pushvars "DEBUG=1" --pushvars "BYPASS_REVIEW=true"
+  pushing to $TESTTMP/repo (glob)
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 1 changes to 1 files
+
+Setting pushvars.sever = true and then pushing.
+
+  $ echo [push] >> $HGRCPATH
+  $ echo "pushvars.server = true" >> $HGRCPATH
+  $ echo b >> a
+  $ hg commit -Aqm a
+  $ hg push --pushvars "DEBUG=1" --pushvars "BYPASS_REVIEW=true"
+  pushing to $TESTTMP/repo
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 1 changes to 1 files
+  HG_USERVAR_BYPASS_REVIEW=true
+  HG_USERVAR_DEBUG=1
+
+Test pushing var with empty right-hand side
+
+  $ echo b >> a
+  $ hg commit -Aqm a
+  $ hg push --pushvars "DEBUG="
+  pushing to $TESTTMP/repo (glob)
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 1 changes to 1 files
+  HG_USERVAR_DEBUG=
+
+Test pushing bad vars
+
+  $ echo b >> a
+  $ hg commit -Aqm b
+  $ hg push --pushvars "DEBUG"
+  pushing to $TESTTMP/repo (glob)
+  abort: unable to parse variable 'DEBUG', should follow 'KEY=VALUE' or 'KEY=' format
+  [255]
diff --git a/tests/test-completion.t b/tests/test-completion.t
--- a/tests/test-completion.t
+++ b/tests/test-completion.t
@@ -228,7 +228,7 @@ 
   log: follow, follow-first, date, copies, keyword, rev, removed, only-merges, user, only-branch, branch, prune, patch, git, limit, no-merges, stat, graph, style, template, include, exclude
   merge: force, rev, preview, tool
   pull: update, force, rev, bookmark, branch, ssh, remotecmd, insecure
-  push: force, rev, bookmark, branch, new-branch, ssh, remotecmd, insecure
+  push: force, rev, bookmark, branch, new-branch, pushvars, ssh, remotecmd, insecure
   remove: after, force, subrepos, include, exclude
   serve: accesslog, daemon, daemon-postexec, errorlog, port, address, prefix, name, web-conf, webdir-conf, pid-file, stdio, cmdserver, templates, style, ipv6, certificate, subrepos
   status: all, modified, added, removed, deleted, clean, unknown, ignored, no-status, terse, copies, print0, rev, change, include, exclude, subrepos, template
diff --git a/mercurial/exchange.py b/mercurial/exchange.py
--- a/mercurial/exchange.py
+++ b/mercurial/exchange.py
@@ -891,6 +891,14 @@ 
                         pushop.bkresult = 1
     return handlereply
 
+@b2partsgenerator('pushvars', idx=0)
+def _getbundlesendvars(pushop, bundler):
+    '''send shellvars via bundle2'''
+    if getattr(pushop.repo, '_shellvars', ()):
+        part = bundler.newpart('pushvars')
+
+        for key, value in pushop.repo._shellvars.iteritems():
+            part.addparam(key, value, mandatory=False)
 
 def _pushbundle2(pushop):
     """push data to the remote using bundle2
diff --git a/mercurial/commands.py b/mercurial/commands.py
--- a/mercurial/commands.py
+++ b/mercurial/commands.py
@@ -3970,6 +3970,7 @@ 
     ('b', 'branch', [],
      _('a specific branch you would like to push'), _('BRANCH')),
     ('', 'new-branch', False, _('allow pushing a new branch')),
+    ('', 'pushvars', [], _('variables that can be sent to server (ADVANCED)')),
     ] + remoteopts,
     _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
 def push(ui, repo, dest=None, **opts):
@@ -4007,6 +4008,25 @@ 
     Please see :hg:`help urls` for important details about ``ssh://``
     URLs. If DESTINATION is omitted, a default path will be used.
 
+    .. container:: verbose
+
+        The --pushvars option sends strings to the server that become
+        environment variables prepended with ``HG_USERVAR_``. For example,
+        ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
+        ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
+
+        pushvars can provide for user-overridable hooks as well as set debug
+        levels. One example is having a hook that blocks commits containing
+        conflict markers, but enables the user to override the hook if the file
+        is using conflict markers for testing purposes or the file format has
+        strings that look like conflict markers.
+
+        By default, servers will ignore `--pushvars`. To enable it add the
+        following to your configuration file
+
+            [push]
+            pushvars.server = true
+
     Returns 0 if push was successful, 1 if nothing to push.
     """
 
@@ -4059,11 +4079,28 @@ 
                 return not result
     finally:
         del repo._subtoppath
+
+    pushvars = opts.get('pushvars')
+    if pushvars:
+        shellvars = {}
+        for raw in pushvars:
+            if '=' not in raw:
+                msg = ("unable to parse variable '%s', should follow "
+                        "'KEY=VALUE' or 'KEY=' format")
+                raise error.Abort(msg % raw)
+            k, v = raw.split('=', 1)
+            shellvars[k] = v
+
+        repo._shellvars = shellvars
+
     pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
                            newbranch=opts.get('new_branch'),
                            bookmarks=opts.get('bookmark', ()),
                            opargs=opts.get('opargs'))
 
+    if pushvars:
+        del repo._shellvars
+
     result = not pushop.cgresult
 
     if pushop.bkresult is not None:
diff --git a/mercurial/bundle2.py b/mercurial/bundle2.py
--- a/mercurial/bundle2.py
+++ b/mercurial/bundle2.py
@@ -1872,3 +1872,17 @@ 
 
     cache.write()
     op.ui.debug('applied %i hgtags fnodes cache entries\n' % count)
+
+@parthandler('pushvars')
+def bundle2getvars(op, part):
+    '''unbundle a bundle2 containing shellvars on the server'''
+    # An option to disable unbundling on server-side for security reasons
+    if op.ui.configbool('push', 'pushvars.server', False):
+        hookargs = {}
+        for key, value in part.advisoryparams:
+            key = key.upper()
+            # We want pushed variables to have USERVAR_ prepended so we know
+            # they came from the --pushvar flag.
+            key = "USERVAR_" + key
+            hookargs[key] = value
+        op.addhookargs(hookargs)