Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package b4 for openSUSE:Factory checked in at 2023-06-26 18:16:15 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/b4 (Old) and /work/SRC/openSUSE:Factory/.b4.new.15902 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "b4" Mon Jun 26 18:16:15 2023 rev:35 rq:1095311 version:0.12.3 Changes: -------- --- /work/SRC/openSUSE:Factory/b4/b4.changes 2023-06-23 21:53:05.834784318 +0200 +++ /work/SRC/openSUSE:Factory/.b4.new.15902/b4.changes 2023-06-26 18:16:29.334575664 +0200 @@ -1,0 +2,29 @@ +Mon Jun 26 05:20:06 UTC 2023 - Jiri Slaby <[email protected]> + +- update to 0.12.3: + * ez: store sent prefixes with the tag message + * Properly quote the address before adding into From + * shazam: switch to top of git tree before running git-am + * trailers: normalize address after parsing + * Fix wrong CTR header after 8bit cover content is mixed in + * ez: make it easier to send single-patch series + * ez: make message-ids use today's date + * ez: only include base-branch when using non-default strategy + * Fix to properly handle under-scissors patches with a unixfrom line + * Clean headers before adding them to the pre-scissors email + * b4: Fix envelopeSender handling + * am, shazam: allow cherry-picking an out-of-series patch + * mbox.py::make_am: simplify check for early return + * ez: Fix 'trailers -F' used on a single commit + * b4.sh: keep existing PYTHONPATH if set + * b4: Allow prep new branch while on a b4 managed branch + * docs: fix smtpServerPort option + * trailers: add 'Closes' as recognized link trailer + * trailers: accept recognized link trailers + * Consider '@' safe in msgid URLs + * ez: better fix for "no follow-up trailers" condition + * Add subscribe/unsubscribe to badtrailers + * ez: do not trust local commands to properly reflect + * ez-trailers: don't crash when there are no follow-ups received + +------------------------------------------------------------------- Old: ---- b4-0.12.2.tar.gz New: ---- b4-0.12.3.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ b4.spec ++++++ --- /var/tmp/diff_new_pack.kQ0Th4/_old 2023-06-26 18:16:29.854577974 +0200 +++ /var/tmp/diff_new_pack.kQ0Th4/_new 2023-06-26 18:16:29.854577974 +0200 @@ -17,7 +17,7 @@ Name: b4 -Version: 0.12.2 +Version: 0.12.3 Release: 0 Summary: Helper scripts for kernel.org patches License: GPL-2.0-or-later ++++++ b4-0.12.2.tar.gz -> b4-0.12.3.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/b4-0.12.2/b4/__init__.py new/b4-0.12.3/b4/__init__.py --- old/b4-0.12.2/b4/__init__.py 2023-03-10 21:47:51.000000000 +0100 +++ new/b4-0.12.3/b4/__init__.py 2023-06-23 19:50:24.000000000 +0200 @@ -28,6 +28,7 @@ import mailbox # noinspection PyCompatibility import pwd +import io import requests @@ -59,7 +60,7 @@ # global setting allowing us to turn off networking can_network = True -__VERSION__ = '0.12.2' +__VERSION__ = '0.12.3' PW_REST_API_VERSION = '1.2' @@ -868,7 +869,7 @@ addr: Optional[Tuple[str, str]] = None lmsg = None # Small list of recognized utility trailers - _utility: Set[str] = {'fixes', 'link', 'buglink', 'obsoleted-by', 'message-id', 'change-id', 'base-commit'} + _utility: Set[str] = {'fixes', 'link', 'buglink', 'closes', 'obsoleted-by', 'message-id', 'change-id', 'base-commit'} def __init__(self, name: Optional[str] = None, value: Optional[str] = None, extinfo: Optional[str] = None, msg: Optional[email.message.Message] = None): @@ -886,6 +887,8 @@ elif re.search(r'\S+@\S+\.\S+', value): self.type = 'person' self.addr = email.utils.parseaddr(value) + # Normalize the value with parsed data + self.value = format_addrs([self.addr]) else: self.type = 'unknown' self.lname = self.name.lower() @@ -1063,7 +1066,8 @@ if self.reply: for trailer in trailers: # These are commonly part of patch/commit metadata - badtrailers = {'from', 'author', 'cc', 'to', 'date', 'subject'} + badtrailers = {'from', 'author', 'cc', 'to', 'date', 'subject', + 'subscribe', 'unsubscribe'} if trailer.lname not in badtrailers: self.trailers.append(trailer) @@ -1638,7 +1642,8 @@ def find_trailers(body: str, followup: bool = False) -> Tuple[List[LoreTrailer], List[str]]: ignores = {'phone', 'email'} headers = {'subject', 'date', 'from'} - nonperson = {'fixes', 'subject', 'date', 'link', 'buglink', 'obsoleted-by', 'change-id', 'base-commit'} + links = {'link', 'buglink', 'closes'} + nonperson = links | {'fixes', 'subject', 'date', 'obsoleted-by', 'change-id', 'base-commit'} # Ignore everything below standard email signature marker body = body.split('\n-- \n', 1)[0].strip() + '\n' # Fix some more common copypasta trailer wrapping @@ -1656,7 +1661,9 @@ trailers = list() others = list() was_trailer = False + at = 0 for line in body.split('\n'): + at += 1 line = line.strip('\r') matches = re.search(r'^\s*(\w\S+):\s+(\S.*)', line, flags=re.I) if matches: @@ -1664,27 +1671,28 @@ # We only accept headers if we haven't seen any non-trailer lines lname = oname.lower() if lname in ignores: - logger.debug('Ignoring known non-trailer: %s', line) + logger.debug('Ignoring %d: %s (known non-trailer)', at, line) continue if len(others) and lname in headers: - logger.debug('Ignoring %s (header after other content)', line) + logger.debug('Ignoring %d: %s (header after other content)', at, line) continue if followup: if not lname.isascii(): - logger.debug('Ignoring known non-ascii follow-up trailer: %s', lname) + logger.debug('Ignoring %d: %s (known non-ascii follow-up trailer)', at, lname) continue mperson = re.search(r'\S+@\S+\.\S+', ovalue) if not mperson and lname not in nonperson: - logger.debug('Ignoring %s (not a recognized non-person trailer)', line) + logger.debug('Ignoring %d: %s (not a recognized non-person trailer)', at, line) continue - if re.search(r'https?://', ovalue): - logger.debug('Ignoring %s (not a recognized link trailer)', line) + mlink = re.search(r'https?://', ovalue) + if mlink and lname not in links: + logger.debug('Ignoring %d: %s (not a recognized link trailer)', at, line) continue extinfo = None mextinfo = re.search(r'(.*\S+)(\s+#[^#]+)$', ovalue) if mextinfo: - logger.debug('Trailer contains hashtag extinfo: %s', line) + logger.debug('Trailer contains hashtag extinfo: %d: %s', at, line) # Found extinfo of the hashtag genre egr = mextinfo.groups() ovalue = egr[0] @@ -1993,22 +2001,21 @@ # Remove anything that's cut off by scissors mi_msg = email.message.EmailMessage() - mi_msg['From'] = self.msg['From'] - mi_msg['Date'] = self.msg['Date'] - mi_msg['Subject'] = self.msg['Subject'] + mi_msg['From'] = LoreMessage.clean_header(self.msg['From']) + mi_msg['Date'] = LoreMessage.clean_header(self.msg['Date']) + mi_msg['Subject'] = LoreMessage.clean_header(self.msg['Subject']) mi_msg.set_payload(self.body, charset='utf-8') mi_msg.set_charset('utf-8') - i, m, p = get_mailinfo(mi_msg.as_bytes(policy=emlpolicy), scissors=True) + ifh = io.BytesIO() + save_mboxrd_mbox([mi_msg], ifh, mangle_from=True) + i, m, p = get_mailinfo(ifh.getvalue(), scissors=True) self.body = m.decode() + p.decode() if add_trailers: self.fix_trailers(copyccs=copyccs, addmysob=addmysob, extras=extras) am_msg = email.message.EmailMessage() - if i.get('Author'): - hfrom = f'{i.get("Author")} <{i.get("Email")}>' - else: - hfrom = i.get('Email') + hfrom = format_addrs([(i.get('Author', ''), i.get('Email'))]) am_msg.add_header('Subject', self.get_am_subject(indicate_reroll=False, use_subject=i.get('Subject'))) am_msg.add_header('From', hfrom) am_msg.add_header('Date', i.get('Date')) @@ -2295,7 +2302,8 @@ def git_run_command(gitdir: Optional[str], args: List[str], stdin: Optional[bytes] = None, - logstderr: bool = False, decode: bool = True) -> Tuple[int, Union[str, bytes]]: + logstderr: bool = False, decode: bool = True, + rundir: Optional[str] = None) -> Tuple[int, Union[str, bytes]]: cmdargs = ['git', '--no-pager'] if gitdir: if os.path.exists(os.path.join(gitdir, '.git')): @@ -2308,7 +2316,7 @@ cmdargs += args - ecode, out, err = _run_command(cmdargs, stdin=stdin) + ecode, out, err = _run_command(cmdargs, stdin=stdin, rundir=rundir) if decode: out = out.decode(errors='replace') @@ -2815,7 +2823,7 @@ def get_pi_thread_by_msgid(msgid: str, nocache: bool = False, onlymsgids: Optional[set] = None) -> Optional[list]: - qmsgid = urllib.parse.quote_plus(msgid) + qmsgid = urllib.parse.quote_plus(msgid, safe='@') config = get_main_config() loc = urllib.parse.urlparse(config['midmask']) # The public-inbox instance may provide a unified index at /all/. @@ -3205,7 +3213,10 @@ # Do we have the envelopesender defined? env_sender = sconfig.get('envelopesender', '') if env_sender: - envpair = email.utils.parseaddr(env_sender) + if env_sender == "auto": + envpair = email.utils.parseaddr(fromaddr) + else: + envpair = email.utils.parseaddr(env_sender) else: envpair = email.utils.parseaddr(fromaddr) if envpair[1]: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/b4-0.12.2/b4/ez.py new/b4-0.12.3/b4/ez.py --- old/b4-0.12.2/b4/ez.py 2023-03-10 21:47:51.000000000 +0100 +++ new/b4-0.12.3/b4/ez.py 2023-06-23 19:50:24.000000000 +0200 @@ -454,18 +454,18 @@ # create a default cover letter and store it where the strategy indicates cover = ('EDITME: cover title for %s' % seriesname, '', + '# Describe the purpose of this series. The information you put here', + '# will be used by the project maintainer to make a decision whether', + '# your patches should be reviewed, and in what priority order. Please be', + '# very detailed and link to any relevant discussions or sites that the', + '# maintainer can review to better understand your proposed changes. If you', + '# only have a single patch in your series, the contents of the cover', + '# letter will be appended to the "under-the-cut" portion of the patch.', + '', '# Lines starting with # will be removed from the cover letter. You can', '# use them to add notes or reminders to yourself. If you want to use', '# markdown headers in your cover letter, start the line with ">#".', '', - 'EDITME: describe the purpose of this series. The information you put', - 'here will be used by the project maintainer to make a decision whether', - 'your patches should be reviewed, and in what priority order. Please be', - 'very detailed and link to any relevant discussions or sites that the', - 'maintainer can review to better understand your proposed changes. If you', - 'only have a single patch in your series, the contents of the cover', - 'letter will be appended to the "under-the-cut" portion of the patch.', - '', '# You can add trailers to the cover letter. Any email addresses found in', '# these trailers will be added to the addresses specified/generated', '# during the b4 send stage. You can also run "b4 prep --auto-to-cc" to', @@ -496,12 +496,14 @@ 'series': { 'revision': revision, 'change-id': changeid, - 'base-branch': basebranch, 'prefixes': prefixes, }, } if thread_msgid: tracking['series']['from-thread'] = thread_msgid + if strategy != 'commit': + # We only need the base-branch info when using strategies other than 'commit' + tracking['series']['base-branch'] = basebranch store_cover(cover, tracking, new=True) if cherry_range: @@ -813,6 +815,8 @@ break prevparent = parent prevcommit = commit + if prevcommit is None: + prevcommit = end start = f'{prevcommit}~1' else: logger.critical('CRITICAL: Please specify -F msgid to look up trailers from remote.') @@ -866,11 +870,13 @@ lser = bbox.get_series(sloppytrailers=cmdargs.sloppytrailers) mismatches = list(lser.trailer_mismatches) for lmsg in lser.patches[1:]: - addtrailers = list(lmsg.followup_trailers) - if lser.has_cover and len(lser.patches[0].followup_trailers): + addtrailers = list() + if lmsg.followup_trailers: + addtrailers += list(lmsg.followup_trailers) + if lser.has_cover and lser.patches[0].followup_trailers: addtrailers += list(lser.patches[0].followup_trailers) if not addtrailers: - logger.debug('No follow-up trailers received to: %s', lmsg.subject) + logger.debug('No new follow-up trailers to add to: %s', lmsg.subject) continue commit = None if lmsg.subject in by_subject: @@ -1005,12 +1011,17 @@ if myemail: domain = re.sub(r'^[^@]*@', '', myemail) else: - # Use the hostname of the system - import platform - domain = platform.node() + # Just use "b4" for the domain name (it doesn't need to be anything real) + domain = 'b4' chunks = change_id.rsplit('-', maxsplit=1) stablepart = chunks[0] + # Replace the change-id origin date with current date + chunks = stablepart.split('-', maxsplit=1) + if len(chunks) == 2 and len(chunks[0]) == 8: + # If someone uses b4 in year 10000, look me up. + stablepart = '%s-%s' % (datetime.date.today().strftime('%Y%m%d'), chunks[1]) + # Message-IDs must not be predictable to avoid stuffing attacks randompart = uuid.uuid4().hex[:12] msgid_tpt = f'<{stablepart}-v{revision}-%s-{randompart}@{domain}>' @@ -1096,6 +1107,9 @@ pbody = b4.LoreMessage.rebuild_message(pheaders, pmessage, ptrailers, newbasement, csignature) msg.set_payload(pbody, charset='utf-8') + # Check if the new body now has 8bit content and fix CTR + if msg.get('Content-Transfer-Encoding') != '8bit' and not pbody.isascii(): + msg.replace_header('Content-Transfer-Encoding', '8bit') def get_cover_subject_body(cover: str) -> Tuple[b4.LoreSubject, str]: @@ -1202,7 +1216,11 @@ if addtracking: patches[0][1].add_header('X-B4-Tracking', thdata) - tag_msg = f'{csubject.full_subject}\n\n{cover_letter}' + header = csubject.full_subject + if prefixes: + header = '[' + ', '.join(prefixes) + f'] {header}' + tag_msg = f'{header}\n\n{cover_letter}' + return alltos, allccs, tag_msg, patches @@ -1289,15 +1307,7 @@ logger.info('Converted the tag to %s messages', len(patches)) else: - # Check if the cover letter has 'EDITME' in it cover, tracking = load_cover(strip_comments=True) - if 'EDITME' in cover: - logger.critical('CRITICAL: Looks like the cover letter needs to be edited first.') - logger.info('---') - logger.info(cover) - logger.info('---') - sys.exit(1) - status = b4.git_get_repo_status() if len(status): logger.critical('CRITICAL: Repository contains uncommitted changes.') @@ -1309,6 +1319,15 @@ except RuntimeError as ex: logger.critical('CRITICAL: Failed to convert range to patches: %s', ex) sys.exit(1) + + # Check if "EDITME" shows up in the first message + if b'EDITME' in b4.LoreMessage.get_msg_as_bytes(patches[0][1]): + logger.critical('CRITICAL: Looks like the cover letter needs to be edited first.') + logger.info('---') + logger.info(cover) + logger.info('---') + sys.exit(1) + logger.info('Converted the branch to %s messages', len(patches)) usercfg = b4.get_user_config() @@ -1453,7 +1472,22 @@ logger.info(' - with envelope-from: %s', fromaddr) smtpserver = sconfig.get('smtpserver', 'localhost') - logger.info(' - via SMTP server %s', smtpserver) + if '/' in smtpserver: + logger.info(' - via local command %s', smtpserver) + if cmdargs.reflect and sconfig.get('b4-really-reflect-via') != smtpserver: + logger.critical('---') + logger.critical('CRITICAL: Cowardly refusing to reflect via %s.', smtpserver) + logger.critical(' There is no guarantee that this command will do the right thing') + logger.critical(' and will not send mail to actual addressees.') + logger.critical('---') + logger.critical('If you are ABSOLUTELY SURE that this command will do the right thing,') + logger.critical('add the following to the [sendemail] section:') + logger.critical('b4-really-reflect-via = %s', smtpserver) + sys.exit(1) + + else: + logger.info(' - via SMTP server %s', smtpserver) + if not (cmdargs.reflect or cmdargs.resend): logger.info(' - tag and reroll the series to the next revision') logger.info('') @@ -1939,8 +1973,12 @@ if cmdargs.compare_to: return compare(cmdargs.compare_to) + if cmdargs.enroll_base and cmdargs.new_series_name: + logger.critical('CRITICAL: -n NEW_SERIES_NAME and -e [ENROLL_BASE] can not be used together.') + sys.exit(1) + if cmdargs.enroll_base or cmdargs.new_series_name: - if is_prep_branch(): + if is_prep_branch() and not cmdargs.fork_point: logger.critical('CRITICAL: This appears to already be a b4-prep managed branch.') sys.exit(1) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/b4-0.12.2/b4/mbox.py new/b4-0.12.3/b4/mbox.py --- old/b4-0.12.2/b4/mbox.py 2023-03-10 21:47:51.000000000 +0100 +++ new/b4-0.12.3/b4/mbox.py 2023-06-23 19:50:24.000000000 +0200 @@ -57,11 +57,11 @@ reroll = False lser = lmbx.get_series(revision=wantver, sloppytrailers=cmdargs.sloppytrailers, reroll=reroll) - if lser is None and wantver is None: - logger.critical('No patches found.') - return - if lser is None: - logger.critical('Unable to find revision %s', wantver) + if lser is None and cmdargs.cherrypick != '_': + if wantver is None: + logger.critical('No patches found.') + else: + logger.critical('Unable to find revision %s', wantver) return if len(lmbx.series) > 1 and not wantver: logger.info('Will use the latest revision: v%s', lser.revision) @@ -70,6 +70,13 @@ if cmdargs.cherrypick: cherrypick = list() if cmdargs.cherrypick == '_': + # We might want to pick a patch sent as a followup, so create a fake series + # and add followups with diffs + if lser is None: + lser = b4.LoreSeries(revision=1, expected=1) + for followup in lmbx.followups: + if followup.has_diff: + lser.add_patch(followup) # Only grab the exact msgid provided at = 0 for lmsg in lser.patches[1:]: @@ -255,7 +262,7 @@ sp = shlex.shlex(amflags, posix=True) sp.whitespace_split = True amargs = list(sp) - ecode, out = b4.git_run_command(topdir, ['am'] + amargs, stdin=ambytes, logstderr=True) + ecode, out = b4.git_run_command(topdir, ['am'] + amargs, stdin=ambytes, logstderr=True, rundir=topdir) logger.info(out.strip()) if ecode == 0: thanks_record_am(lser, cherrypick=cherrypick) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/b4-0.12.2/b4.sh new/b4-0.12.3/b4.sh --- old/b4-0.12.2/b4.sh 2023-03-10 21:47:51.000000000 +0100 +++ new/b4-0.12.3/b4.sh 2023-06-23 19:50:24.000000000 +0200 @@ -6,4 +6,5 @@ REAL_SCRIPT=$(realpath -e ${BASH_SOURCE[0]}) SCRIPT_TOP="${SCRIPT_TOP:-$(dirname ${REAL_SCRIPT})}" -exec env PYTHONPATH="${SCRIPT_TOP}:${SCRIPT_TOP}/patatt" python3 "${SCRIPT_TOP}/b4/command.py" "${@}" +PYTHONPATH="${SCRIPT_TOP}:${SCRIPT_TOP}/patatt${PYTHONPATH:+:$PYTHONPATH}" \ + exec python3 "${SCRIPT_TOP}/b4/command.py" "${@}" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/b4-0.12.2/docs/contributor/send.rst new/b4-0.12.3/docs/contributor/send.rst --- old/b4-0.12.2/docs/contributor/send.rst 2023-03-10 21:47:51.000000000 +0100 +++ new/b4-0.12.3/docs/contributor/send.rst 2023-06-23 19:50:24.000000000 +0200 @@ -130,7 +130,7 @@ [sendemail] smtpServer = smtp.example.org - smtpPort = 465 + smtpServerPort = 465 smtpEncryption = ssl smtpUser = [email protected] smtpPass = [omitted] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/b4-0.12.2/tests/samples/trailers-thread-with-cover-followup.mbox new/b4-0.12.3/tests/samples/trailers-thread-with-cover-followup.mbox --- old/b4-0.12.2/tests/samples/trailers-thread-with-cover-followup.mbox 2023-03-10 21:47:51.000000000 +0100 +++ new/b4-0.12.3/tests/samples/trailers-thread-with-cover-followup.mbox 2023-06-23 19:50:24.000000000 +0200 @@ -225,6 +225,8 @@ > Signed-off-by: Konstantin Ryabitsev <[email protected]> Tested-by: Follow Upper <[email protected]> +Link: https://example.org +Closes: https://example.org/bug/1234 -- Follow Upper diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/b4-0.12.2/tests/samples/trailers-thread-with-cover-followup.verify new/b4-0.12.3/tests/samples/trailers-thread-with-cover-followup.verify --- old/b4-0.12.2/tests/samples/trailers-thread-with-cover-followup.verify 2023-03-10 21:47:51.000000000 +0100 +++ new/b4-0.12.3/tests/samples/trailers-thread-with-cover-followup.verify 2023-06-23 19:50:24.000000000 +0200 @@ -4,6 +4,8 @@ Signed-off-by: Konstantin Ryabitsev <[email protected]> Tested-by: Follow Upper <[email protected]> +Link: https://example.org +Closes: https://example.org/bug/1234 Reviewed-by: Cover Upper <[email protected]> Signed-off-by: Test Override <[email protected]> ---
