poky/meta/lib/patchtest/tests/test_mbox.py
Trevor Gamblin dab2dcae89 patchtest: add test_commit_message_user_tags
This test makes patchtest check to ensure that there aren't any
GitHub-style user account names being tagged in the commit message, e.g.
it should catch lines like:

"fix added by @threexc"

This is desired so that if (for example) we add upstream changelogs in
recipe upgrade commit messages verbatim, we don't end up subscribing any
associated maintainers to our repo mirrors' updates by accident.

There is a small possibility of a false positive with this test, where
if someone is mentioning Python decorators in their commit message (or
similar syntax from other languages), it will fail when it should pass.
However, having this test in place to guard against username inclusion
is more important that the occasional false positive for that reason.

With this addition, a failure will look like:

|FAIL: test commit message user tags: Mbox includes one or more GitHub-style username tags. Ensure that any "@" symbols are stripped out of usernames (test_mbox.TestMbox.test_commit_message_user_tags)

(From OE-Core rev: 8278d82d8203212bb159eb3805d4a5617c5370df)

Signed-off-by: Trevor Gamblin <tgamblin@baylibre.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2024-10-23 17:35:23 +01:00

180 lines
8.5 KiB
Python

# Checks related to the patch's author
#
# Copyright (C) 2016 Intel Corporation
#
# SPDX-License-Identifier: GPL-2.0-only
import base
import collections
import patchtest_patterns
import pyparsing
import re
import subprocess
from patchtest_parser import PatchtestParser
def headlog():
output = subprocess.check_output(
"cd %s; git log --pretty='%%h#%%aN#%%cD:#%%s' -1" % PatchtestParser.repodir,
universal_newlines=True,
shell=True
)
return output.split('#')
class TestMbox(base.Base):
# base paths of main yocto project sub-projects
paths = {
'oe-core': ['meta-selftest', 'meta-skeleton', 'meta', 'scripts'],
'bitbake': ['bitbake'],
'documentation': ['documentation'],
'poky': ['meta-poky','meta-yocto-bsp'],
'oe': ['meta-gpe', 'meta-gnome', 'meta-efl', 'meta-networking', 'meta-multimedia','meta-initramfs', 'meta-ruby', 'contrib', 'meta-xfce', 'meta-filesystems', 'meta-perl', 'meta-webserver', 'meta-systemd', 'meta-oe', 'meta-python']
}
# scripts folder is a mix of oe-core and poky, most is oe-core code except:
poky_scripts = ['scripts/yocto-bsp', 'scripts/yocto-kernel', 'scripts/yocto-layer', 'scripts/lib/bsp']
Project = collections.namedtuple('Project', ['name', 'listemail', 'gitrepo', 'paths'])
bitbake = Project(name='Bitbake', listemail='bitbake-devel@lists.openembedded.org', gitrepo='http://git.openembedded.org/bitbake/', paths=paths['bitbake'])
doc = Project(name='Documentantion', listemail='yocto@yoctoproject.org', gitrepo='http://git.yoctoproject.org/cgit/cgit.cgi/yocto-docs/', paths=paths['documentation'])
poky = Project(name='Poky', listemail='poky@yoctoproject.org', gitrepo='http://git.yoctoproject.org/cgit/cgit.cgi/poky/', paths=paths['poky'])
oe = Project(name='oe', listemail='openembedded-devel@lists.openembedded.org', gitrepo='http://git.openembedded.org/meta-openembedded/', paths=paths['oe'])
def test_signed_off_by_presence(self):
for commit in self.commits:
# skip those patches that revert older commits, these do not required the tag presence
if patchtest_patterns.mbox_revert_shortlog_regex.search_string(commit.shortlog):
continue
if not patchtest_patterns.signed_off_by.search_string(commit.payload):
self.fail(
'Mbox is missing Signed-off-by. Add it manually or with "git commit --amend -s"',
commit=commit,
)
def test_shortlog_format(self):
for commit in self.commits:
shortlog = commit.shortlog
if not shortlog.strip():
self.skip('Empty shortlog, no reason to execute shortlog format test')
else:
# no reason to re-check on revert shortlogs
if shortlog.startswith('Revert "'):
continue
try:
patchtest_patterns.shortlog.parseString(shortlog)
except pyparsing.ParseException as pe:
self.fail('Commit shortlog (first line of commit message) should follow the format "<target>: <summary>"',
commit=commit)
def test_shortlog_length(self):
for commit in self.commits:
# no reason to re-check on revert shortlogs
shortlog = re.sub('^(\[.*?\])+ ', '', commit.shortlog)
if shortlog.startswith('Revert "'):
continue
l = len(shortlog)
if l > patchtest_patterns.mbox_shortlog_maxlength:
self.fail(
"Edit shortlog so that it is %d characters or less (currently %d characters)"
% (patchtest_patterns.mbox_shortlog_maxlength, l),
commit=commit,
)
def test_series_merge_on_head(self):
self.skip("Merge test is disabled for now")
if PatchtestParser.repo.patch.branch != "master":
self.skip(
"Skipping merge test since patch is not intended"
" for master branch. Target detected is %s"
% PatchtestParser.repo.patch.branch
)
if not PatchtestParser.repo.canbemerged:
commithash, author, date, shortlog = headlog()
self.fail(
"Series does not apply on top of target branch %s"
% PatchtestParser.repo.patch.branch,
data=[
(
"Targeted branch",
"%s (currently at %s)"
% (PatchtestParser.repo.patch.branch, commithash),
)
],
)
def test_target_mailing_list(self):
"""Check for other targeted projects"""
# a meta project may be indicted in the message subject, if this is the case, just fail
# TODO: there may be other project with no-meta prefix, we also need to detect these
project_regex = pyparsing.Regex("\[(?P<project>meta-.+)\]")
for commit in self.commits:
match = project_regex.search_string(commit.subject)
if match:
self.fail('Series sent to the wrong mailing list or some patches from the series correspond to different mailing lists',
commit=commit)
for patch in self.patchset:
folders = patch.path.split('/')
base_path = folders[0]
for project in [self.bitbake, self.doc, self.oe, self.poky]:
if base_path in project.paths:
self.fail('Series sent to the wrong mailing list or some patches from the series correspond to different mailing lists',
data=[('Suggested ML', '%s [%s]' % (project.listemail, project.gitrepo)),
('Patch\'s path:', patch.path)])
# check for poky's scripts code
if base_path.startswith('scripts'):
for poky_file in self.poky_scripts:
if patch.path.startswith(poky_file):
self.fail('Series sent to the wrong mailing list or some patches from the series correspond to different mailing lists',
data=[('Suggested ML', '%s [%s]' % (self.poky.listemail, self.poky.gitrepo)),('Patch\'s path:', patch.path)])
def test_mbox_format(self):
if self.unidiff_parse_error:
self.fail('Series has malformed diff lines. Create the series again using git-format-patch and ensure it applies using git am',
data=[('Diff line',self.unidiff_parse_error)])
def test_commit_message_presence(self):
for commit in self.commits:
if not commit.commit_message.strip():
self.fail('Please include a commit message on your patch explaining the change', commit=commit)
# This may incorrectly report a failure if something such as a
# Python decorator is included in the commit message, but this
# scenario is much less common than the username case it is written
# to protect against
def test_commit_message_user_tags(self):
for commit in self.commits:
if patchtest_patterns.mbox_github_username.search_string(commit.commit_message):
self.fail('Mbox includes one or more GitHub-style username tags. Ensure that any "@" symbols are stripped out of usernames', commit=commit)
def test_bugzilla_entry_format(self):
for commit in self.commits:
if not patchtest_patterns.mbox_bugzilla.search_string(commit.commit_message):
self.skip("No bug ID found")
elif not patchtest_patterns.mbox_bugzilla_validation.search_string(
commit.commit_message
):
self.fail(
'Bugzilla issue ID is not correctly formatted - specify it with format: "[YOCTO #<bugzilla ID>]"',
commit=commit,
)
def test_author_valid(self):
for commit in self.commits:
for invalid in patchtest_patterns.invalid_submitters:
if invalid.search_string(commit.author):
self.fail('Invalid author %s. Resend the series with a valid patch author' % commit.author, commit=commit)
def test_non_auh_upgrade(self):
for commit in self.commits:
if patchtest_patterns.auh_email in commit.commit_message:
self.fail(
"Invalid author %s. Resend the series with a valid patch author"
% patchtest_patterns.auh_email,
commit=commit,
)