From ff7e964d49873a263fd3fe332c2980a272140333 Mon Sep 17 00:00:00 2001 From: Jun Wu Date: Fri, 6 Oct 2023 11:15:52 -0700 Subject: [PATCH] commit: support `.committemplate` based on changed files Summary: See the test for an example. This can be useful to set templates for sub-projects in a larger project. Reviewed By: zzl0 Differential Revision: D49781544 fbshipit-source-id: ce9336c0b394377d3e90f135fcccf1fae01e81cb --- .../config/loader/src/builtin_static/core.rs | 6 +-- eden/scm/sapling/cmdutil.py | 42 ++++++++++++++++++ eden/scm/tests/test-commit-localtemplate.t | 43 +++++++++++++++++++ 3 files changed, 88 insertions(+), 3 deletions(-) create mode 100644 eden/scm/tests/test-commit-localtemplate.t diff --git a/eden/scm/lib/config/loader/src/builtin_static/core.rs b/eden/scm/lib/config/loader/src/builtin_static/core.rs index de8a07716aeff..c117e976c851f 100644 --- a/eden/scm/lib/config/loader/src/builtin_static/core.rs +++ b/eden/scm/lib/config/loader/src/builtin_static/core.rs @@ -51,6 +51,9 @@ exportstack-max-bytes=1M log-implicit-follow-threshold=10000 +titles-namespace=true +local-committemplate=true + [zsh] completion-age=7 completion-description=false @@ -65,7 +68,4 @@ selectivepulldiscovery=true autopullhoistpattern= autopullpattern=re:^(?:default|remote)/[A-Za-z0-9._/-]+$ hoist=default - -[experimental] -titles-namespace=true "#); diff --git a/eden/scm/sapling/cmdutil.py b/eden/scm/sapling/cmdutil.py index 2c34ef6560080..9b368b45b5cb2 100644 --- a/eden/scm/sapling/cmdutil.py +++ b/eden/scm/sapling/cmdutil.py @@ -4012,6 +4012,11 @@ def buildcommittemplate(repo, ctx, extramsg, ref): for k, v in repo.ui.configitems("committemplate") ) + # load extra aliases based on changed files + if repo.ui.configbool("experimental", "local-committemplate"): + localtemplate = localcommittemplate(repo, ctx) + t.t.cache.update((k, templater.unquotestring(v)) for k, v in localtemplate) + if not extramsg: extramsg = "" # ensure that extramsg is string @@ -4020,6 +4025,43 @@ def buildcommittemplate(repo, ctx, extramsg, ref): return pycompat.decodeutf8(ui.popbufferbytes(), errors="replace") +def localcommittemplate(repo, ctx): + """return [(k, v)], local [committemplate] config based on changed files. + + The local commit template only works for working copy ctx. + + The local commit template is decided in these steps: + - First, calculate the common prefix of the changed files. + For example, the common prefix of a/x/1, a/x/2/3 is a/x. + - Then, find the config file, starting with prefix/.committemplate, + recursively look at parent directories until repo root. + For the above example, check a/x/.committemplate, then a/.committemplate, + then .committemplate from repo root. + - Load the config file. The format of the config file is ``key = value``, + similar to config files but without the [committemplate] header. + """ + + if ctx.node() is None: + files = ctx.files() + prefix = os.path.commonpath(files) if files else "" + wvfs = repo.wvfs + while True: + config_path = prefix + (prefix and "/" or "") + ".committemplate" + if wvfs.isdir(prefix) and wvfs.exists(config_path): + cfg = bindings.configloader.config() + content = wvfs.tryreadutf8(config_path) + cfg.parse(content, source=config_path) + section = "" + names = cfg.names(section) + return [(name, cfg.get(section, name)) for name in names] + next_prefix = os.path.dirname(prefix) + if next_prefix == prefix: + break + prefix = next_prefix + + return [] + + def hgprefix(msg): return "\n".join([f"{identity.tmplprefix()}: {a}" for a in msg.split("\n") if a]) diff --git a/eden/scm/tests/test-commit-localtemplate.t b/eden/scm/tests/test-commit-localtemplate.t new file mode 100644 index 0000000000000..f05f33ef46684 --- /dev/null +++ b/eden/scm/tests/test-commit-localtemplate.t @@ -0,0 +1,43 @@ +#debugruntest-compatible + + $ newrepo + $ setconfig 'committemplate.changeset={foo}\n' + $ setconfig 'committemplate.foo=foo' + +Default commit template + + $ HGEDITOR=cat hg commit --config ui.allowemptycommit=true + foo + abort: commit message unchanged + [255] + + $ mkdir -p x/y/z/k z/y + $ touch x/y/z/k/1 x/y/z/1 x/y/1 x/1 z/y/1 + $ echo 'foo = z' > x/y/z/.committemplate + $ echo 'foo = y' > x/y/.committemplate + $ echo 'foo = x' > x/.committemplate + $ echo 'foo = root' > .committemplate + +When x/y/z/k/.committemplate does not exist, check parents x/y/z: + + $ hg add -q x/y/z/k/1 + $ HGEDITOR=cat hg commit --config ui.allowemptycommit=true + z + abort: commit message unchanged + [255] + +Common prefix is now y: + + $ hg add -q x/y/1 + $ HGEDITOR=cat hg commit --config ui.allowemptycommit=true + y + abort: commit message unchanged + [255] + +Common prefix is now repo root: + + $ hg add z/y/1 + $ HGEDITOR=cat hg commit --config ui.allowemptycommit=true + root + abort: commit message unchanged + [255]