From 2a6a9fed8abe3767c4e101d29662707c18df8888 Mon Sep 17 00:00:00 2001 From: Durham Goode Date: Wed, 10 Jul 2019 20:10:40 -0700 Subject: [PATCH] push: add option to block hg push if no reason is provided Summary: We want to start tracking down why people use hg push instead of arc land. To begin with, let's add an option that will require they provide a reason to run hg push directly. Later we may block pushes or limit it to a whitelist in some way. Reviewed By: quark-zju Differential Revision: D16156871 fbshipit-source-id: f46c039a91073fa3380d3b4b7f35722829eeb72a --- edenscm/mercurial/commands/__init__.py | 17 +++++++++++++++++ edenscm/mercurial/configitems.py | 2 ++ tests/test-pushvars.t | 26 ++++++++++++++++++++++++++ 3 files changed, 45 insertions(+) diff --git a/edenscm/mercurial/commands/__init__.py b/edenscm/mercurial/commands/__init__.py index 199706a3bf..a3b4d7411c 100644 --- a/edenscm/mercurial/commands/__init__.py +++ b/edenscm/mercurial/commands/__init__.py @@ -4868,6 +4868,13 @@ def push(ui, repo, dest=None, **opts): [push] pushvars.server = true + If ``push.requirereason`` is set to true, users will need to pass + ``--pushvars PUSH_REASON="..."`` in order to push, and their reason will + be logged via ``ui.log(...)``. + + ``push.requirereasonmsg`` can be used to set the message shown to users + when they don't provide a reason. + Returns 0 if push was successful, 1 if nothing to push. """ @@ -4914,6 +4921,16 @@ def push(ui, repo, dest=None, **opts): _("default push revset for path evaluates to an " "empty set") ) + if ui.configbool("push", "requirereason"): + pushvar = "PUSH_REASON=" + reasons = list(v for v in opts.get("pushvars", []) if v.startswith(pushvar)) + if reasons: + reason = reasons[-1][len(pushvar):] + ui.log("pushreason", "bypassing push block with reason: %s", reason, pushreason=reason) + else: + msg = ui.config("push", "requirereasonmsg") + raise error.Abort(msg, hint="use `--pushvars PUSH_REASON='because ...'`") + opargs = dict(opts.get("opargs", {})) # copy opargs since we may mutate it opargs.setdefault("pushvars", []).extend(opts.get("pushvars", [])) diff --git a/edenscm/mercurial/configitems.py b/edenscm/mercurial/configitems.py index 7348a210f4..7a778086cd 100644 --- a/edenscm/mercurial/configitems.py +++ b/edenscm/mercurial/configitems.py @@ -404,6 +404,8 @@ coreconfigitem("progress", "renderer", default="classic") coreconfigitem("progress", "width", default=dynamicdefault) coreconfigitem("pull", "automigrate", default=True) coreconfigitem("push", "pushvars.server", default=True) +coreconfigitem("push", "requirereason", default=False) +coreconfigitem("push", "requirereasonmsg", default="") coreconfigitem("sendunbundlereplay", "respondlightly", default=True) coreconfigitem("server", "bookmarks-pushkey-compat", default=True) coreconfigitem("server", "bundle1", default=True) diff --git a/tests/test-pushvars.t b/tests/test-pushvars.t index 0f0217e3f3..47988be7a7 100644 --- a/tests/test-pushvars.t +++ b/tests/test-pushvars.t @@ -80,6 +80,7 @@ Test Python hooks > ui.write("Got pushvar: %s=%s\n" % (k, v)) > EOF + $ cp $HGRCPATH $TESTTMP/hgrc.bak $ cat >> $HGRCPATH << EOF > [hooks] > pretxnchangegroup.pyhook = python:$TESTTMP/pyhook.py:hook @@ -94,3 +95,28 @@ Test Python hooks added 1 changesets with 1 changes to 1 files Got pushvar: USERVAR_A=1 Got pushvar: USERVAR_B=2 + $ cp $TESTTMP/hgrc.bak $HGRCPATH + +Test pushvars for enforcing push reasons + $ cat >> .hg/hgrc < [push] + > requirereason=True + > requirereasonmsg="Because I said so" + > EOF + $ echo c >> a + $ hg commit -Aqm c + $ hg push + pushing to $TESTTMP/repo + abort: "Because I said so" + (use `--pushvars PUSH_REASON='because ...'`) + [255] + $ hg push --pushvars PUSH_REASON="I want to" + pushing to $TESTTMP/repo + searching for changes + adding changesets + adding manifests + adding file changes + added 1 changesets with 1 changes to 1 files + $ hg blackbox --pattern '{"legacy_log": {"service": "pushreason"}}' + * [legacy][pushreason] bypassing push block with reason: I want to (glob) + $ cp $TESTTMP/hgrc.bak $HGRCPATH