From 797fc250c7dd64550f2283bdc749eda7555e3fa3 Mon Sep 17 00:00:00 2001 From: Konstantin Ryabitsev Date: Thu, 16 Jun 2022 16:22:55 -0400 Subject: Implement "b4 shazam -M" that execs git-merge In addition to just being able to fetch a series into FETCH_HEAD, also add an option to exec git-merge automatically so that people don't have to cut-and-paste the merge command to use with paths to the cover letter. Signed-off-by: Konstantin Ryabitsev --- b4/command.py | 11 ++++-- b4/mbox.py | 87 ++++++++++++++++++++++++++----------------- man/b4.5.rst | 60 +++++++++++++++++++++++++---- shazam-merge-template.example | 6 +-- 4 files changed, 115 insertions(+), 49 deletions(-) diff --git a/b4/command.py b/b4/command.py index aa307da..4f69231 100644 --- a/b4/command.py +++ b/b4/command.py @@ -152,15 +152,18 @@ def cmd(): sp_sh = subparsers.add_parser('shazam', help='Like b4 am, but applies the series to your tree') cmd_retrieval_common_opts(sp_sh) cmd_am_common_opts(sp_sh) - sp_sh.add_argument('-H', '--make-fetch-head', dest='makefetchhead', action='store_true', default=False, - help='Attempt to treat series as a pull request and fetch it into FETCH_HEAD') + sh_g = sp_sh.add_mutually_exclusive_group() + sh_g.add_argument('-H', '--make-fetch-head', dest='makefetchhead', action='store_true', default=False, + help='Attempt to treat series as a pull request and fetch it into FETCH_HEAD') + sh_g.add_argument('-M', '--merge', dest='merge', action='store_true', default=False, + help='Attempt to merge series as if it were a pull request (execs git-merge)') sp_sh.add_argument('--guess-lookback', dest='guessdays', type=int, default=21, - help=('(use with -H) When guessing base, go back this many days from the patch date ' + help=('(use with -H or -M) When guessing base, go back this many days from the patch date ' '(default: 3 weeks)')) sp_sh.set_defaults(func=cmd_shazam) # b4 attest - sp_att = subparsers.add_parser('attest', help='Create cryptographic attestation for a set of patches') + sp_att = subparsers.add_parser('attest', help='(DEPRECATED) Create cryptographic attestation for a set of patches') sp_att.add_argument('-f', '--from', dest='sender', default=None, help='OBSOLETE: this option does nothing and will be removed') sp_att.add_argument('-n', '--no-submit', dest='nosubmit', action='store_true', default=False, diff --git a/b4/mbox.py b/b4/mbox.py index 4ac2c29..277df89 100644 --- a/b4/mbox.py +++ b/b4/mbox.py @@ -34,9 +34,9 @@ logger = b4.logger DEFAULT_MERGE_TEMPLATE = """Merge ${patch_or_series} "${seriestitle}" ${authorname} <${authoremail}> says: -==================== -${coverletter} -==================== + +${covermessage} + Link: ${midurl} """ @@ -263,7 +263,7 @@ def make_am(msgs, cmdargs, msgid): b4.save_git_am_mbox(am_msgs, ifh) ambytes = ifh.getvalue().encode() if not cmdargs.makefetchhead: - amflags = config.get('git-am-flags', '') + amflags = config.get('shazam-am-flags', '') sp = shlex.shlex(amflags, posix=True) sp.whitespace_split = True amargs = list(sp) @@ -332,44 +332,59 @@ def make_am(msgs, cmdargs, msgid): logger.critical(out.strip()) sys.exit(ecode) mmf = os.path.join(fhf.rstrip(), 'b4-cover') + merge_template = DEFAULT_MERGE_TEMPLATE + if config.get('shazam-merge-template'): + # Try to load this template instead + try: + merge_template = b4.read_template(config['shazam-merge-template']) + except FileNotFoundError: + logger.critical('ERROR: shazam-merge-template says to use %s, but it does not exist', + config['shazam-merge-template']) + sys.exit(2) + + # Write out a sample merge message using the cover letter + if os.path.exists(mmf): + # Make sure any old cover letters don't confuse anyone + os.unlink(mmf) + if lser.has_cover: - merge_template = DEFAULT_MERGE_TEMPLATE - if config.get('shazam-merge-template'): - # Try to load this template instead - try: - merge_template = b4.read_template(config['shazam-merge-template']) - except FileNotFoundError: - logger.critical('ERROR: shazam-merge-template says to use %s, but it does not exist', - config['shazam-merge-template']) - sys.exit(2) - - # Write out a sample merge message using the cover letter cmsg = lser.patches[0] parts = b4.LoreMessage.get_body_parts(cmsg.body) - tptvals = { - 'seriestitle': cmsg.subject, - 'authorname': cmsg.fromname, - 'authoremail': cmsg.fromemail, - 'coverletter': parts[1], - 'midurl': linkurl, - } - if len(am_msgs) > 1: - tptvals['patch_or_series'] = 'patch series' - else: - tptvals['patch_or_series'] = 'patch' + covermessage = parts[1] + else: + cmsg = lser.patches[1] + covermessage = ('NOTE: No cover letter provided by the author.\n' + ' Add merge commit message here.') + tptvals = { + 'seriestitle': cmsg.subject, + 'authorname': cmsg.fromname, + 'authoremail': cmsg.fromemail, + 'covermessage': covermessage, + 'midurl': linkurl, + } + if len(am_msgs) > 1: + tptvals['patch_or_series'] = 'patch series' + else: + tptvals['patch_or_series'] = 'patch' - body = Template(merge_template).safe_substitute(tptvals) - with open(mmf, 'w') as mmh: - mmh.write(body) + body = Template(merge_template).safe_substitute(tptvals) + with open(mmf, 'w') as mmh: + mmh.write(body) - elif os.path.exists(mmf): - # Make sure any old cover letters don't confuse anyone - os.unlink(mmf) + mergeflags = config.get('shazam-merge-flags', '--signoff') + sp = shlex.shlex(mergeflags, posix=True) + sp.whitespace_split = True + mergeargs = ['merge', '--no-ff', '-F', mmf, '--edit', 'FETCH_HEAD'] + list(sp) + mergecmd = ['git'] + mergeargs - logger.info('You can now merge or checkout FETCH_HEAD') - if lser.has_cover: - logger.info(' e.g.: git merge -F $(git rev-parse --git-dir)/b4-cover --signoff --edit FETCH_HEAD') thanks_record_am(lser, cherrypick=cherrypick) + if cmdargs.merge: + # We exec git-merge and let it take over + logger.info('Invoking: %s', ' '.join(mergecmd)) + os.execvp(mergecmd[0], mergecmd) + + logger.info('You can now merge or checkout FETCH_HEAD') + logger.info(' e.g.: %s', ' '.join(mergecmd)) return if not base_commit: @@ -711,6 +726,8 @@ def main(cmdargs): cmdargs.nopartialreroll = False cmdargs.outdir = '-' cmdargs.guessbranch = None + if cmdargs.merge: + cmdargs.makefetchhead = True if cmdargs.makefetchhead: cmdargs.guessbase = True else: diff --git a/man/b4.5.rst b/man/b4.5.rst index 246d224..7bda7db 100644 --- a/man/b4.5.rst +++ b/man/b4.5.rst @@ -46,6 +46,12 @@ SUBCOMMAND OPTIONS ------------------ b4 mbox ~~~~~~~ + +This command allows retrieving entire threads from a remote public-inbox +instance. The resulting mbox file can then be opened with most MUA +clients for actions like replying to conversations or reviewing patch +submissions. + usage: b4 mbox [-h] [-p USEPROJECT] [-m LOCALMBOX] [-C] [-o OUTDIR] [-c] [-n WANTNAME] [-M] [-f] [msgid] @@ -76,6 +82,25 @@ options: b4 am ~~~~~ + +This command allows retrieving threads from a public-inbox instance and +preparing them for applying to a git repository using the "git am" +command. It will automatically perform the following operations: + +* pick the latest submitted version of the series (it can check for + newer threads using ``-c`` as well) +* check DKIM signatures and patatt attestation on all patches and code + review messages +* collate all submitted code-review trailers (Reviewed-by, Acked-by, + etc) and put them into the commit message +* add your own Signed-off-by trailer (with ``-s``) +* reroll series from partial updates (e.g. someone submits a v2 of a + single patch instead of rerolling the entire series) +* guess where in the tree history the patches belong, if the exact + commit-base is not specified (with ``-g``) +* prepare the tree for a 3-way merge (with ``-3``) +* cherry-pick a subset of patches from a large series (with ``-P``) + usage: b4 am [-h] [-p USEPROJECT] [-m LOCALMBOX] [-C] [-o OUTDIR] [-c] [-n WANTNAME] [-M] [-v WANTVER] [-t] [-S] [-T] [-s] [-l] [-P CHERRYPICK] [--cc-trailers] [--no-parent] [--allow-unicode-control-chars] [-Q] [-g] [-b GUESSBRANCH [GUESSBRANCH ...]] [--guess-lookback GUESSDAYS] [-3] [--no-cover] [--no-partial-reroll] [msgid] @@ -137,11 +162,20 @@ options: *Example*: b4 am 20200313231252.64999-1-keescook@chromium.org - b4 shazam --------- + +This is very similar to **b4 am**, but will also apply patches +directly to the current git tree using ``git am``. Alternatively, when +used with ``-H``, it can fetch the patch series into ``FETCH_HEAD`` as +if it were a pull request, so it can be reviewed and merged. In this +case, the cover letter is used as a template for the merge commit. + +If you want to automatically invoke git-merge, you can use ``-M`` +instead of ``-H``. + usage: - b4 shazam [-h] [-p USEPROJECT] [-m LOCALMBOX] [-C] [-v WANTVER] [-t] [-S] [-T] [-s] [-l] [-P CHERRYPICK] [--cc-trailers] [--no-parent] [--allow-unicode-control-chars] [-H] [--guess-lookback GUESSDAYS] [msgid] + b4 shazam [-h] [-p USEPROJECT] [-m LOCALMBOX] [-C] [-v WANTVER] [-t] [-S] [-T] [-s] [-l] [-P CHERRYPICK] [--cc-trailers] [--no-parent] [--allow-unicode-control-chars] [-H | -M] [--guess-lookback GUESSDAYS] [msgid] positional arguments: msgid Message ID to process, or pipe a raw message @@ -171,15 +205,15 @@ options: Allow unicode control characters (very rarely legitimate) -H, --make-fetch-head Attempt to treat series as a pull request and fetch it into FETCH_HEAD + -M, --merge + Attempt to merge series as if it were a pull request (execs git-merge) --guess-lookback GUESSDAYS - (use with -H) When guessing base, go back this many days from the patch date (default: 3 weeks) + (use with -H or -M) When guessing base, go back this many days from the patch date (default: 3 weeks) *Example*: b4 shazam -H 20200313231252.64999-1-keescook@chromium.org b4 attest ~~~~~~~~~ -usage: b4 attest [-h] patchfile [patchfile ...] - .. note:: **This subcommand is deprecated and will be removed in a future @@ -189,6 +223,9 @@ usage: b4 attest [-h] patchfile [patchfile ...] "patatt". You may instead install and use patatt directly with the same results. +usage: + b4 attest [-h] patchfile [patchfile ...] + positional arguments: patchfile Patches to attest @@ -196,6 +233,9 @@ positional arguments: b4 pr ~~~~~ +This command is for working with pull requests submitted using +``git-request-pull``. + usage: command.py pr [-h] [-g GITDIR] [-b BRANCH] [-c] [-e] [-o OUTMBOX] [msgid] @@ -251,7 +291,8 @@ optional arguments: b4 diff ~~~~~~~ -usage: b4 diff [-h] [-g GITDIR] [-p USEPROJECT] [-C] [-v WANTVERS [WANTVERS ...]] [-n] [-o OUTDIFF] [-c] [-m AMBOX AMBOX] [msgid] +usage: + b4 diff [-h] [-g GITDIR] [-p USEPROJECT] [-C] [-v WANTVERS [WANTVERS ...]] [-n] [-o OUTDIFF] [-c] [-m AMBOX AMBOX] [msgid] positional arguments: msgid Message ID to process, pipe a raw message, or use -m @@ -283,7 +324,8 @@ optional arguments: b4 kr ~~~~~ -usage: b4 kr [-h] [-p USEPROJECT] [-m LOCALMBOX] [-C] [--show-keys] [msgid] +usage: + b4 kr [-h] [-p USEPROJECT] [-m LOCALMBOX] [-C] [--show-keys] [msgid] positional arguments: msgid Message ID to process, or pipe a raw message @@ -370,6 +412,10 @@ Default configuration, with explanations:: thanks-pr-template = None # See thanks-am-template.example. If not set, a default template will be used. thanks-am-template = None + # additional flags to pass to "git am" when we run "b4 shazam" + shazam-am-flags = None + # additional flags to pass to "git merge" when we run "b4 shazam -M" + shazam-merge-flags = --signoff # Used when preparing merge messages from cover letters. See shazam-merge-template.example shazam-merge-template = None # Use to exclude certain mail addresses from ever being added to auto-generated mail diff --git a/shazam-merge-template.example b/shazam-merge-template.example index ab735b4..e4d49d2 100644 --- a/shazam-merge-template.example +++ b/shazam-merge-template.example @@ -7,12 +7,12 @@ Merge ${patch_or_series} "${seriestitle}" ${authorname} <${authoremail}> says: -==================== + # This will be the entirety of the cover letter minus anything # below the "-- \n" signature line. You will almost certainly # want to edit it down to only include the relevant info. -${coverletter} -==================== +${covermessage} + # This will contain a lore link to the patches in question Link: ${midurl} # git-merge will append any additional information here, depending -- cgit v1.2.3