summaryrefslogtreecommitdiffstats
path: root/meta/lib/patchtest/tests/test_mbox.py
diff options
context:
space:
mode:
Diffstat (limited to 'meta/lib/patchtest/tests/test_mbox.py')
-rw-r--r--meta/lib/patchtest/tests/test_mbox.py183
1 files changed, 183 insertions, 0 deletions
diff --git a/meta/lib/patchtest/tests/test_mbox.py b/meta/lib/patchtest/tests/test_mbox.py
new file mode 100644
index 0000000000..95002c9e2a
--- /dev/null
+++ b/meta/lib/patchtest/tests/test_mbox.py
@@ -0,0 +1,183 @@
1# Checks related to the patch's author
2#
3# Copyright (C) 2016 Intel Corporation
4#
5# SPDX-License-Identifier: GPL-2.0-only
6
7import base
8import collections
9import parse_cve_tags
10import parse_shortlog
11import parse_signed_off_by
12import pyparsing
13import subprocess
14from data import PatchTestInput
15
16def headlog():
17 output = subprocess.check_output(
18 "cd %s; git log --pretty='%%h#%%aN#%%cD:#%%s' -1" % PatchTestInput.repodir,
19 universal_newlines=True,
20 shell=True
21 )
22 return output.split('#')
23
24class TestMbox(base.Base):
25
26 auh_email = 'auh@auh.yoctoproject.org'
27
28 invalids = [pyparsing.Regex("^Upgrade Helper.+"),
29 pyparsing.Regex(auh_email),
30 pyparsing.Regex("uh@not\.set"),
31 pyparsing.Regex("\S+@example\.com")]
32
33 rexp_detect = pyparsing.Regex('\[\s?YOCTO.*\]')
34 rexp_validation = pyparsing.Regex('\[(\s?YOCTO\s?#\s?(\d+)\s?,?)+\]')
35 revert_shortlog_regex = pyparsing.Regex('Revert\s+".*"')
36 prog = parse_cve_tags.cve_tag
37 patch_prog = parse_cve_tags.patch_cve_tag
38 signoff_prog = parse_signed_off_by.signed_off_by
39 revert_shortlog_regex = pyparsing.Regex('Revert\s+".*"')
40 maxlength = 90
41
42 # base paths of main yocto project sub-projects
43 paths = {
44 'oe-core': ['meta-selftest', 'meta-skeleton', 'meta', 'scripts'],
45 'bitbake': ['bitbake'],
46 'documentation': ['documentation'],
47 'poky': ['meta-poky','meta-yocto-bsp'],
48 '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']
49 }
50
51 # scripts folder is a mix of oe-core and poky, most is oe-core code except:
52 poky_scripts = ['scripts/yocto-bsp', 'scripts/yocto-kernel', 'scripts/yocto-layer', 'scripts/lib/bsp']
53
54 Project = collections.namedtuple('Project', ['name', 'listemail', 'gitrepo', 'paths'])
55
56 bitbake = Project(name='Bitbake', listemail='bitbake-devel@lists.openembedded.org', gitrepo='http://git.openembedded.org/bitbake/', paths=paths['bitbake'])
57 doc = Project(name='Documentantion', listemail='yocto@yoctoproject.org', gitrepo='http://git.yoctoproject.org/cgit/cgit.cgi/yocto-docs/', paths=paths['documentation'])
58 poky = Project(name='Poky', listemail='poky@yoctoproject.org', gitrepo='http://git.yoctoproject.org/cgit/cgit.cgi/poky/', paths=paths['poky'])
59 oe = Project(name='oe', listemail='openembedded-devel@lists.openembedded.org', gitrepo='http://git.openembedded.org/meta-openembedded/', paths=paths['oe'])
60
61
62 def test_signed_off_by_presence(self):
63 for commit in TestMbox.commits:
64 # skip those patches that revert older commits, these do not required the tag presence
65 if self.revert_shortlog_regex.search_string(commit.shortlog):
66 continue
67 if not self.signoff_prog.search_string(commit.payload):
68 self.fail('Mbox is missing Signed-off-by. Add it manually or with "git commit --amend -s"',
69 commit=commit)
70
71 def test_shortlog_format(self):
72 for commit in TestMbox.commits:
73 shortlog = commit.shortlog
74 if not shortlog.strip():
75 self.skip('Empty shortlog, no reason to execute shortlog format test')
76 else:
77 # no reason to re-check on revert shortlogs
78 if shortlog.startswith('Revert "'):
79 continue
80 try:
81 parse_shortlog.shortlog.parseString(shortlog)
82 except pyparsing.ParseException as pe:
83 self.fail('Commit shortlog (first line of commit message) should follow the format "<target>: <summary>"',
84 commit=commit)
85
86 def test_shortlog_length(self):
87 for commit in TestMbox.commits:
88 # no reason to re-check on revert shortlogs
89 shortlog = commit.shortlog
90 if shortlog.startswith('Revert "'):
91 continue
92 l = len(shortlog)
93 if l > self.maxlength:
94 self.fail('Edit shortlog so that it is %d characters or less (currently %d characters)' % (self.maxlength, l),
95 commit=commit)
96
97 def test_series_merge_on_head(self):
98 self.skip("Merge test is disabled for now")
99 if PatchTestInput.repo.branch != "master":
100 self.skip("Skipping merge test since patch is not intended for master branch. Target detected is %s" % PatchTestInput.repo.branch)
101 if not PatchTestInput.repo.ismerged:
102 commithash, author, date, shortlog = headlog()
103 self.fail('Series does not apply on top of target branch. Rebase your series and ensure the target is correct',
104 data=[('Targeted branch', '%s (currently at %s)' % (PatchTestInput.repo.branch, commithash))])
105
106 def test_target_mailing_list(self):
107 """In case of merge failure, check for other targeted projects"""
108 if PatchTestInput.repo.ismerged:
109 self.skip('Series merged, no reason to check other mailing lists')
110
111 # a meta project may be indicted in the message subject, if this is the case, just fail
112 # TODO: there may be other project with no-meta prefix, we also need to detect these
113 project_regex = pyparsing.Regex("\[(?P<project>meta-.+)\]")
114 for commit in TestMbox.commits:
115 match = project_regex.search_string(commit.subject)
116 if match:
117 self.fail('Series sent to the wrong mailing list. Check the project\'s README (%s) and send the patch to the indicated list' % match.group('project'),
118 commit=commit)
119
120 for patch in self.patchset:
121 folders = patch.path.split('/')
122 base_path = folders[0]
123 for project in [self.bitbake, self.doc, self.oe, self.poky]:
124 if base_path in project.paths:
125 self.fail('Series sent to the wrong mailing list or some patches from the series correspond to different mailing lists. Send the series again to the correct mailing list (ML)',
126 data=[('Suggested ML', '%s [%s]' % (project.listemail, project.gitrepo)),
127 ('Patch\'s path:', patch.path)])
128
129 # check for poky's scripts code
130 if base_path.startswith('scripts'):
131 for poky_file in self.poky_scripts:
132 if patch.path.startswith(poky_file):
133 self.fail('Series sent to the wrong mailing list or some patches from the series correspond to different mailing lists. Send the series again to the correct mailing list (ML)',
134 data=[('Suggested ML', '%s [%s]' % (self.poky.listemail, self.poky.gitrepo)),('Patch\'s path:', patch.path)])
135
136 def test_mbox_format(self):
137 if self.unidiff_parse_error:
138 self.fail('Series cannot be parsed correctly due to malformed diff lines. Create the series again using git-format-patch and ensure it can be applied using git am',
139 data=[('Diff line',self.unidiff_parse_error)])
140
141 def test_commit_message_presence(self):
142 for commit in TestMbox.commits:
143 if not commit.commit_message.strip():
144 self.fail('Mbox is missing a descriptive commit message. Please include a commit message on your patch explaining the change', commit=commit)
145
146 def test_cve_presence_in_commit_message(self):
147 if self.unidiff_parse_error:
148 self.skip('Parse error %s' % self.unidiff_parse_error)
149
150 # we are just interested in series that introduce CVE patches, thus discard other
151 # possibilities: modification to current CVEs, patch directly introduced into the
152 # recipe, upgrades already including the CVE, etc.
153 new_patches = [p for p in self.patchset if p.path.endswith('.patch') and p.is_added_file]
154 if not new_patches:
155 self.skip('No new patches introduced')
156
157 for commit in TestMbox.commits:
158 # skip those patches that revert older commits, these do not required the tag presence
159 if self.revert_shortlog_regex.search_string(commit.shortlog):
160 continue
161 if not self.patch_prog.search_string(commit.payload):
162 self.skip("No CVE tag in added patch, so not needed in mbox")
163 elif not self.prog.search_string(commit.payload):
164 self.fail('Missing or incorrectly formatted CVE tag in mbox. Correct or include the CVE tag in the mbox with format: "CVE: CVE-YYYY-XXXX"',
165 commit=commit)
166
167 def test_bugzilla_entry_format(self):
168 for commit in TestMbox.commits:
169 if not self.rexp_detect.search_string(commit.commit_message):
170 self.skip("No bug ID found")
171 elif not self.rexp_validation.search_string(commit.commit_message):
172 self.fail('Bugzilla issue ID is not correctly formatted - specify it with format: "[YOCTO #<bugzilla ID>]"', commit=commit)
173
174 def test_author_valid(self):
175 for commit in self.commits:
176 for invalid in self.invalids:
177 if invalid.search_string(commit.author):
178 self.fail('Invalid author %s. Resend the series with a valid patch author' % commit.author, commit=commit)
179
180 def test_non_auh_upgrade(self):
181 for commit in self.commits:
182 if self.auh_email in commit.payload:
183 self.fail('Invalid author %s. Resend the series with a valid patch author' % self.auh_email, commit=commit)