aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKonstantin Ryabitsev <konstantin@linuxfoundation.org>2022-09-30 14:16:45 -0400
committerKonstantin Ryabitsev <konstantin@linuxfoundation.org>2022-09-30 14:16:45 -0400
commit5166be6f9ac9e760c7c0407e643c8af0faf12bf9 (patch)
treec0cd2c97d6e374fe6fa3978ee0adff700ddd221b
parent601fdc2a68e023812fc3b47ef3c05da63a6093f8 (diff)
downloadb4-master.tar.gz
ez: initial prep --compare-to implementationHEADmaster
It is useful to be able to see the difference between the version that you have previously sent and the current working branch. This is the initial implementation that can be further improved to allow passing range-diff options. Signed-off-by: Konstantin Ryabitsev <konstantin@linuxfoundation.org>
-rw-r--r--b4/command.py4
-rw-r--r--b4/ez.py102
-rw-r--r--docs/contributor/prep.rst5
-rw-r--r--man/b4.55
-rw-r--r--man/b4.5.rst3
5 files changed, 86 insertions, 33 deletions
diff --git a/b4/command.py b/b4/command.py
index 245bfd0..b16043e 100644
--- a/b4/command.py
+++ b/b4/command.py
@@ -266,6 +266,8 @@ def cmd():
help='Show current series revision number')
spp_g.add_argument('--force-revision', metavar='N', type=int,
help='Force revision to be this number instead')
+ spp_g.add_argument('--compare-to', metavar='vN',
+ help='Display a range-diff to previously sent revision N')
spp_g.add_argument('--manual-reroll', dest='reroll', default=None, metavar='COVER_MSGID',
help='Mark current revision as sent and reroll (requires cover letter msgid)')
ag_prepn = sp_prep.add_argument_group('Create new branch', 'Create a new branch for working on patch series')
@@ -308,7 +310,7 @@ def cmd():
sp_send.add_argument('--cc', nargs='+', help='Addresses to add to the Cc: list')
sp_send.add_argument('--not-me-too', action='store_true', default=False,
help='Remove yourself from the To: or Cc: list')
- sp_send.add_argument('--resend', default=None,
+ sp_send.add_argument('--resend', metavar='vN', default=None,
help='Resend a previously sent version of the series')
sp_send.add_argument('--no-sign', action='store_true', default=False,
help='Do not add the cryptographic attestation signature header')
diff --git a/b4/ez.py b/b4/ez.py
index 58564fa..07c5b98 100644
--- a/b4/ez.py
+++ b/b4/ez.py
@@ -26,7 +26,7 @@ import gzip
import io
import copy
-from typing import Optional, Tuple, List
+from typing import Optional, Tuple, List, Union
from email import utils
from string import Template
@@ -45,6 +45,8 @@ except ModuleNotFoundError:
logger = b4.logger
MAGIC_MARKER = '--- b4-submit-tracking ---'
+# Make this configurable?
+SENT_TAG_PREFIX = 'sent/'
DEFAULT_COVER_TEMPLATE = """
${cover}
@@ -907,10 +909,7 @@ def print_pretty_addrs(addrs: list, hdrname: str) -> None:
logger.info(' %s', b4.format_addrs([addr]))
-def get_sent_tag_as_patches(tagname: str, revision: Optional[str] = None,
- prefixes: Optional[List[str]] = None,
- hide_cover_to_cc: bool = False
- ) -> Tuple[List, List, List[Tuple[str, email.message.Message]]]:
+def get_base_changeid_from_tag(tagname: str) -> Tuple[str, str, str]:
gitargs = ['cat-file', '-p', tagname]
ecode, tagmsg = b4.git_run_command(None, gitargs)
if ecode > 0:
@@ -926,12 +925,13 @@ def get_sent_tag_as_patches(tagname: str, revision: Optional[str] = None,
if not matches:
raise RuntimeError('Tag %s does not contain change-id info' % tagname)
change_id = matches.groups()[0]
- if revision is None:
- matches = re.search(r'.*-v(\d+)$', tagname, flags=re.I | re.M)
- if not matches:
- raise RuntimeError('Could not grok revision number from %s' % tagname)
- revision = matches.groups()[0]
+ return cover, base_commit, change_id
+
+def get_sent_tag_as_patches(tagname: str, revision: int, prefixes: Optional[List[str]] = None,
+ hide_cover_to_cc: bool = False
+ ) -> Tuple[List, List, List[Tuple[str, email.message.Message]]]:
+ cover, base_commit, change_id = get_base_changeid_from_tag(tagname)
# First line is the subject
csubject, cbody = cover.split('\n', maxsplit=1)
cbody = cbody.strip() + '\n-- \n' + b4.get_email_signature()
@@ -949,7 +949,7 @@ def get_sent_tag_as_patches(tagname: str, revision: Optional[str] = None,
if revision != 1:
prefixes.append(f'v{revision}')
seriests = int(time.time())
- msgid_tpt = make_msgid_tpt(change_id, revision)
+ msgid_tpt = make_msgid_tpt(change_id, str(revision))
usercfg = b4.get_user_config()
mailfrom = (usercfg.get('name'), usercfg.get('email'))
@@ -1102,8 +1102,6 @@ def cmd_send(cmdargs: argparse.Namespace) -> None:
auth_verify(cmdargs)
return
- # Should we make the sent/ prefix configurable?
- tagprefix = 'sent/'
mybranch = b4.git_get_current_branch()
prefixes = cmdargs.prefixes
if cmdargs.prefixes is None:
@@ -1114,17 +1112,11 @@ def cmd_send(cmdargs: argparse.Namespace) -> None:
cmdargs.hide_cover_to_cc = True
if cmdargs.resend:
- # We accept both a full tag name and just a vN short form
- matches = re.search(r'^v(\d+)$', cmdargs.resend)
- if matches:
- revision = matches.groups()[0]
- if mybranch.startswith('b4/'):
- tagname = f'{tagprefix}{mybranch[3:]}-v{revision}'
- else:
- tagname = f'{tagprefix}{mybranch}-v{revision}'
- else:
- revision = None
- tagname = cmdargs.resend
+ tagname, revision = get_sent_tagname(mybranch, SENT_TAG_PREFIX, cmdargs.resend)
+
+ if revision is None:
+ logger.critical('Could not figure out revision from %s', cmdargs.resend)
+ sys.exit(1)
prefixes.append('RESEND')
try:
@@ -1316,7 +1308,26 @@ def cmd_send(cmdargs: argparse.Namespace) -> None:
reroll(mybranch, cover_msg)
-def reroll(mybranch: str, cover_msg: email.message.Message, tagprefix: str = 'sent/'):
+def get_sent_tagname(branch: str, tagprefix: str, revstr: Union[str, int]) -> Tuple[str, Optional[int]]:
+ revision = None
+ try:
+ revision = int(revstr)
+ except ValueError:
+ matches = re.search(r'^v(\d+)$', revstr)
+ if not matches:
+ # assume we got a full tag name, so try to find the revision there
+ matches = re.search(r'v(\d+)$', revstr)
+ if matches:
+ revision = int(matches.groups()[0])
+ return revstr.replace('refs/tags/', ''), revision
+ revision = int(matches.groups()[0])
+
+ if branch.startswith('b4/'):
+ return f'{tagprefix}{branch[3:]}-v{revision}', revision
+ return f'{tagprefix}{branch}-v{revision}', revision
+
+
+def reroll(mybranch: str, cover_msg: email.message.Message, tagprefix: str = SENT_TAG_PREFIX):
# Prepare annotated tag body from the cover letter
lsubject = b4.LoreSubject(cover_msg.get('subject'))
cbody = cover_msg.get_payload()
@@ -1328,11 +1339,7 @@ def reroll(mybranch: str, cover_msg: email.message.Message, tagprefix: str = 'se
cover, tracking = load_cover(strip_comments=True)
revision = tracking['series']['revision']
- if mybranch.startswith('b4/'):
- tagname = f'{tagprefix}{mybranch[3:]}-v{revision}'
- else:
- tagname = f'{tagprefix}{mybranch}-v{revision}'
-
+ tagname, revision = get_sent_tagname(mybranch, tagprefix, revision)
logger.debug('checking if we already have %s', tagname)
gitargs = ['rev-parse', f'refs/tags/{tagname}']
ecode, out = b4.git_run_command(None, gitargs)
@@ -1458,6 +1465,38 @@ def force_revision(forceto: int) -> None:
store_cover(cover, tracking)
+def compare(compareto: str) -> None:
+ mybranch = b4.git_get_current_branch(None)
+ tagname, revision = get_sent_tagname(mybranch, SENT_TAG_PREFIX, compareto)
+ gitargs = ['rev-parse', tagname]
+ lines = b4.git_get_command_lines(None, gitargs)
+ if not lines:
+ logger.critical('CRITICAL: Could not rev-parse %s', tagname)
+ sys.exit(1)
+ prev_end = lines[0]
+ try:
+ cover, base_commit, change_id = get_base_changeid_from_tag(tagname)
+ except RuntimeError as ex:
+ logger.critical('CRITICAL: %s', str(ex))
+ sys.exit(1)
+ prev_start = base_commit
+ curr_start = get_series_start()
+ strategy = get_cover_strategy()
+ if strategy == 'tip-commit':
+ cover_commit = find_cover_commit()
+ series_end = f'{cover_commit}~1'
+ else:
+ series_end = 'HEAD'
+
+ gitargs = ['rev-parse', series_end]
+ lines = b4.git_get_command_lines(None, gitargs)
+ curr_end = lines[0]
+ grdcmd = ['git', 'range-diff', '%.12s..%.12s' % (prev_start, prev_end), '%.12s..%.12s' % (curr_start, curr_end)]
+ # We exec range-diff and let it take over
+ logger.debug('Running %s', ' '.join(grdcmd))
+ os.execvp(grdcmd[0], grdcmd)
+
+
def auto_to_cc() -> None:
tocmdstr = None
cccmdstr = None
@@ -1589,6 +1628,9 @@ def cmd_prep(cmdargs: argparse.Namespace) -> None:
if cmdargs.format_patch:
return format_patch(cmdargs.format_patch)
+ if cmdargs.compare_to:
+ return compare(cmdargs.compare_to)
+
if is_prep_branch():
logger.critical('CRITICAL: This appears to already be a b4-prep managed branch.')
sys.exit(1)
diff --git a/docs/contributor/prep.rst b/docs/contributor/prep.rst
index 61133d7..2a9f753 100644
--- a/docs/contributor/prep.rst
+++ b/docs/contributor/prep.rst
@@ -239,6 +239,11 @@ or modifying defaults for some of these flags.
Forces the revision to a different integer number. This modifies your
cover letter and tracking information and makes this change permanent.
+``--compare-to vN`` **(v0.11+)**
+ This executes a ``git range-diff`` command that lets you compare the
+ previously sent version of the series to what is currently in your
+ working branch.
+
``--manual-reroll MSGID``
Normally, your patch series will be automatically rerolled to the next
version after a successful ``b4 send`` (see :doc:`send`). However, if
diff --git a/man/b4.5 b/man/b4.5
index 56c13ac..198c4fc 100644
--- a/man/b4.5
+++ b/man/b4.5
@@ -523,7 +523,7 @@ Show all developer keys from the thread
.INDENT 0.0
.TP
.B usage:
-b4 prep [\-h] [\-c | \-p OUTPUT_DIR | \-\-edit\-cover | \-\-show\-revision | \-\-force\-revision N | \-\-manual\-reroll COVER_MSGID] [\-n NEW_SERIES_NAME] [\-f FORK_POINT] [\-F MSGID] [\-e ENROLL_BASE]
+b4 prep [\-h] [\-c | \-p OUTPUT_DIR | \-\-edit\-cover | \-\-show\-revision | \-\-force\-revision N | \-\-compare\-to vN | \-\-manual\-reroll COVER_MSGID] [\-n NEW_SERIES_NAME] [\-f FORK_POINT] [\-F MSGID] [\-e ENROLL_BASE]
.TP
.B options:
.INDENT 7.0
@@ -546,6 +546,9 @@ Show current series revision number
.BI \-\-force\-revision \ N
Force revision to be this number instead
.TP
+.BI \-\-compare\-to \ vN
+Display a range\-diff to previously sent revision N
+.TP
.BI \-\-manual\-reroll \ COVER_MSGID
Mark current revision as sent and reroll (requires cover letter msgid)
.UNINDENT
diff --git a/man/b4.5.rst b/man/b4.5.rst
index 072c107..073f32a 100644
--- a/man/b4.5.rst
+++ b/man/b4.5.rst
@@ -342,7 +342,7 @@ optional arguments:
b4 prep
~~~~~~~
usage:
- b4 prep [-h] [-c | -p OUTPUT_DIR | --edit-cover | --show-revision | --force-revision N | --manual-reroll COVER_MSGID] [-n NEW_SERIES_NAME] [-f FORK_POINT] [-F MSGID] [-e ENROLL_BASE]
+ b4 prep [-h] [-c | -p OUTPUT_DIR | --edit-cover | --show-revision | --force-revision N | --compare-to vN | --manual-reroll COVER_MSGID] [-n NEW_SERIES_NAME] [-f FORK_POINT] [-F MSGID] [-e ENROLL_BASE]
options:
-h, --help show this help message and exit
@@ -352,6 +352,7 @@ options:
--edit-cover Edit the cover letter in your defined $EDITOR (or core.editor)
--show-revision Show current series revision number
--force-revision N Force revision to be this number instead
+ --compare-to vN Display a range-diff to previously sent revision N
--manual-reroll COVER_MSGID
Mark current revision as sent and reroll (requires cover letter msgid)