# HG changeset patch # User Pulkit Goyal <7895pulkit@gmail.com> # Date 1501475382 -19800 # Node ID db3dc11356edd09d11705cf0fe285b290cea53fa # Parent f100354cce52918420f7116e588cfc61ae8690ca pushvars: move fb extension pushvars to core pushvars extension in fbext adds a --pushvars flag to push command using which one send strings to server which becomes environment variables there prepended with HG_USERVAR_. These variables can then be used to run hooks on the server. The extension is moved directly to core and unbundling of the strings and converting them to environment variables at server is disabled by default for security reasons. One can turn that on by following config: [push] pushvars.server = true This patch also adds the test for the extension. Differential Revision: https://phab.mercurial-scm.org/D210 diff -r f100354cce52 -r db3dc11356ed mercurial/bundle2.py --- a/mercurial/bundle2.py Fri Aug 04 12:21:23 2017 -0700 +++ b/mercurial/bundle2.py Mon Jul 31 09:59:42 2017 +0530 @@ -1879,3 +1879,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) diff -r f100354cce52 -r db3dc11356ed mercurial/commands.py --- a/mercurial/commands.py Fri Aug 04 12:21:23 2017 -0700 +++ b/mercurial/commands.py Mon Jul 31 09:59:42 2017 +0530 @@ -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 -r f100354cce52 -r db3dc11356ed mercurial/exchange.py --- a/mercurial/exchange.py Fri Aug 04 12:21:23 2017 -0700 +++ b/mercurial/exchange.py Mon Jul 31 09:59:42 2017 +0530 @@ -893,6 +893,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 -r f100354cce52 -r db3dc11356ed tests/test-completion.t --- a/tests/test-completion.t Fri Aug 04 12:21:23 2017 -0700 +++ b/tests/test-completion.t Mon Jul 31 09:59:42 2017 +0530 @@ -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 -r f100354cce52 -r db3dc11356ed tests/test-pushvars.t --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-pushvars.t Mon Jul 31 09:59:42 2017 +0530 @@ -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 (glob) + 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]