Bump version to 24.04.3.4
[LibreOffice.git] / bin / check-missing-unittests.py
blob0ee36ef76aafc0d0a3d579508df2a09cf3171e95
1 #!/usr/bin/env python3
3 # This file is part of the LibreOffice project.
5 # This Source Code Form is subject to the terms of the Mozilla Public
6 # License, v. 2.0. If a copy of the MPL was not distributed with this
7 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 # Use this script to update
10 # https://wiki.documentfoundation.org/MissingUnitTests
12 import os
13 import datetime
14 import subprocess
15 import sys
16 import re
17 import json
18 import requests
20 def splitList(lst, n):
21 for i in range(0, len(lst), n):
22 yield lst[i:i + n]
24 def whiteboardNotes(whiteboard):
25 if not whiteboard:
26 return ''
27 if ' ' in whiteboard:
28 whiteboardList = reversed(whiteboard.split(' '))
29 for w in whiteboardList:
30 if w.startswith("unitTestNotes"):
31 return w.split(':')[1]
32 elif whiteboard.startswith("unitTestNotes"):
33 return whiteboard.split(':')[1]
35 return ''
37 def main(ignoredBugs):
38 results = {
39 'export': {
40 'docx': {},
41 'doc': {},
42 'pptx': {},
43 'xlsx': {},
44 'xhtml': {},
45 'html': {},
47 'writer': {
48 'undo': {},
49 'autoformat': {},
50 'autocorrect': {},
51 'others': {},
53 'calc': {
54 'import': {},
55 'format': {},
56 'others': {},
58 'impress': {
59 'drawingml': {},
60 'slidesorter': {},
61 'others': {},
65 hasTestSet = set()
67 repoPath = os.path.dirname(os.path.abspath(__file__)) + '/..'
68 branch = subprocess.check_output(
69 ['git', '-C', repoPath, 'rev-parse', '--abbrev-ref', 'HEAD'],
70 stderr=subprocess.DEVNULL)
71 last_hash = subprocess.check_output(
72 ['git', '-C', repoPath, 'rev-parse', 'HEAD'],
73 stderr=subprocess.DEVNULL)
74 output = subprocess.check_output(
75 ['git', '-C', repoPath, 'log', '--since="2012-01-01', '--name-only' ,'--pretty=format:"%s%n%ad"', '--date=format:"%Y/%m/%d"'],
76 stderr=subprocess.DEVNULL)
77 commits = output.decode('utf-8', 'ignore').split('\n\n')
79 for commit in reversed(commits):
81 commitInfo = commit.split('\n')
83 summary = commitInfo[0].strip('"').lower()
85 # Check for bugIds in the summary. Ignore those with a '-' after the digits.
86 # Those are used for file names ( e.g. tdf129410-1.ods )
87 bugIds = re.findall("\\b(?:bug|fdo|tdf|lo)[#:]?(\\d+)(?!-)\\b", summary)
88 if bugIds is None or len(bugIds) == 0:
89 continue
91 for bugId in bugIds:
93 isIgnored = False
94 for i in ignoredBugs:
95 if i in summary:
96 isIgnored = True
97 if isIgnored:
98 continue
100 if bugId in hasTestSet:
101 continue
103 date = commitInfo[1].strip('"')
104 infoList = [date, summary]
106 changedFiles = "".join(commitInfo[2:])
107 if 'qa' in changedFiles:
108 hasTestSet.add(bugId)
109 continue
111 elif 'sw/source/filter/ww8/docx' in changedFiles or \
112 'writerfilter/source/dmapper' in changedFiles or \
113 'starmath/source/ooxmlimport' in changedFiles:
114 results['export']['docx'][bugId] = infoList
116 elif 'sw/source/filter/ww8/ww8' in changedFiles:
117 results['export']['doc'][bugId] = infoList
119 elif 'sc/source/filter/excel/xe' in changedFiles:
120 results['export']['xlsx'][bugId] = infoList
122 elif 'oox/source/export/' in changedFiles:
123 results['export']['pptx'][bugId] = infoList
125 elif 'filter/source/xslt/odf2xhtml/export' in changedFiles:
126 results['export']['xhtml'][bugId] = infoList
128 elif 'sw/source/filter/html/' in changedFiles:
129 results['export']['html'][bugId] = infoList
131 elif 'sw/source/core/undo/' in changedFiles:
132 results['writer']['undo'][bugId] = infoList
134 elif 'sw/source/core/edit/autofmt' in changedFiles:
135 results['writer']['autoformat'][bugId] = infoList
137 elif 'sw/source/core/edit/acorrect' in changedFiles:
138 results['writer']['autocorrect'][bugId] = infoList
140 elif 'drawingml' in changedFiles:
141 results['impress']['drawingml'][bugId] = infoList
143 elif 'sd/source/ui/slidesorter/' in changedFiles:
144 results['impress']['slidesorter'][bugId] = infoList
146 elif 'sc/source/core/tool/interpr' in changedFiles:
147 results['calc']['import'][bugId] = infoList
149 elif 'svl/source/numbers/' in changedFiles:
150 results['calc']['format'][bugId] = infoList
152 # Keep the following if statements at the end
154 elif 'sc/source/core/' in changedFiles:
155 results['calc']['others'][bugId] = infoList
157 elif 'sw/source/core/' in changedFiles:
158 results['writer']['others'][bugId] = infoList
160 elif 'sd/source/core/' in changedFiles:
161 results['impress']['others'][bugId] = infoList
163 listOfBugIdsWithoutTest = []
164 for k,v in results.items():
165 for k1, v1 in v.items():
166 for bugId, info in v1.items():
167 if bugId not in hasTestSet:
168 listOfBugIdsWithoutTest.append(bugId)
171 bugzillaJson = []
172 resultList = []
173 fixList = []
174 #Split the list into different chunks for the requests, otherwise it fails
175 for chunk in splitList(listOfBugIdsWithoutTest, 50):
176 urlGet = 'https://bugs.documentfoundation.org/rest/bug?id=' + ','.join(chunk)
177 rGet = requests.get(urlGet)
178 rawData = json.loads(rGet.text)
179 rGet.close()
180 bugzillaJson.extend(rawData['bugs'])
182 for k,v in results.items():
183 for k1, v1 in v.items():
184 for bugId, info in v1.items():
186 resolution = ''
187 keywords = []
188 priority = ''
189 notes = ''
190 for bug in bugzillaJson:
191 if str(bug['id']) == str(bugId):
192 resolution = bug['resolution']
193 keywords = bug['keywords']
194 priority = bug['priority']
195 notes = whiteboardNotes(bug['whiteboard'])
196 break
198 # Only care about FIXED bugs
199 # Ignore performance bugs and accessibility bugs
200 if resolution and resolution == 'FIXED' and 'perf' not in keywords \
201 and 'accessibility' not in keywords:
202 fixList.append({
203 "id": bugId,
204 "date": info[0],
205 "priority": priority.upper(),
206 "summary": info[1],
207 "maintopic":k,
208 "subtopic":k1,
209 "notes": notes
212 resultList.append([{
213 "Generator": os.path.basename(sys.argv[0]),
214 "Date": str(datetime.datetime.now()),
215 "Commits": str(len(commits)),
216 "Branch": branch.decode().strip(),
217 "Hash": str(last_hash.decode().strip()),
219 resultList.append(fixList)
220 print(json.dumps(resultList))
222 def usage():
223 message = """usage: {program} [bugs to ignore (each one is one argument)]
225 Sample: {program} 10000 10001 10002"""
226 print(message.format(program = os.path.basename(sys.argv[0])))
228 if __name__ == '__main__':
230 args = set()
231 if len(sys.argv) > 1:
232 arg1 = sys.argv[1]
233 if arg1 == '-h' or arg1 == "--help":
234 usage()
235 sys.exit(1)
236 for i in sys.argv:
237 if i.isdigit():
238 args.add(i)
240 main(sorted(args))