python3: upgrade to release 3.8.13
[LibreOffice.git] / bin / check-missing-unittests.py
blob5ea891396d6a8d9e3bed796bb7dabf003ff19027
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 main(ignoredBugs):
25 results = {
26 'export': {
27 'docx': {},
28 'doc': {},
29 'pptx': {},
30 'xlsx': {},
31 'xhtml': {},
32 'html': {},
34 'writer': {
35 'undo': {},
36 'autoformat': {},
37 'autocorrect': {},
38 'others': {},
40 'calc': {
41 'import': {},
42 'format': {},
43 'others': {},
45 'impress': {
46 'drawingml': {},
47 'slidesorter': {},
48 'others': {},
52 hasTestSet = set()
54 repoPath = os.path.dirname(os.path.abspath(__file__)) + '/..'
55 branch = subprocess.check_output(
56 ['git', '-C', repoPath, 'rev-parse', '--abbrev-ref', 'HEAD'],
57 stderr=subprocess.DEVNULL)
58 last_hash = subprocess.check_output(
59 ['git', '-C', repoPath, 'rev-parse', 'HEAD'],
60 stderr=subprocess.DEVNULL)
61 output = subprocess.check_output(
62 ['git', '-C', repoPath, 'log', '--since="2012-01-01', '--name-only' ,'--pretty=format:"%s%n%ad"', '--date=format:"%Y/%m/%d"'],
63 stderr=subprocess.DEVNULL)
64 commits = output.decode('utf-8', 'ignore').split('\n\n')
66 for commit in reversed(commits):
68 commitInfo = commit.split('\n')
70 summary = commitInfo[0].strip('"').lower()
72 # Check for bugIds in the summary. Ignore those with a '-' after the digits.
73 # Those are used for file names ( e.g. tdf129410-1.ods )
74 bugIds = re.findall("\\b(?:bug|fdo|tdf|lo)[#:]?(\\d+)(?!-)\\b", summary)
75 if bugIds is None or len(bugIds) == 0:
76 continue
78 for bugId in bugIds:
80 isIgnored = False
81 for i in ignoredBugs:
82 if i in summary:
83 isIgnored = True
84 if isIgnored:
85 continue
87 if bugId in hasTestSet:
88 continue
90 date = commitInfo[1].strip('"')
91 infoList = [date, summary]
93 changedFiles = "".join(commitInfo[2:])
94 if 'qa' in changedFiles:
95 hasTestSet.add(bugId)
96 continue
98 elif 'sw/source/filter/ww8/docx' in changedFiles or \
99 'writerfilter/source/dmapper' in changedFiles or \
100 'starmath/source/ooxmlimport' in changedFiles:
101 results['export']['docx'][bugId] = infoList
103 elif 'sw/source/filter/ww8/ww8' in changedFiles:
104 results['export']['doc'][bugId] = infoList
106 elif 'sc/source/filter/excel/xe' in changedFiles:
107 results['export']['xlsx'][bugId] = infoList
109 elif 'oox/source/export/' in changedFiles:
110 results['export']['pptx'][bugId] = infoList
112 elif 'filter/source/xslt/odf2xhtml/export' in changedFiles:
113 results['export']['xhtml'][bugId] = infoList
115 elif 'sw/source/filter/html/' in changedFiles:
116 results['export']['html'][bugId] = infoList
118 elif 'sw/source/core/undo/' in changedFiles:
119 results['writer']['undo'][bugId] = infoList
121 elif 'sw/source/core/edit/autofmt' in changedFiles:
122 results['writer']['autoformat'][bugId] = infoList
124 elif 'sw/source/core/edit/acorrect' in changedFiles:
125 results['writer']['autocorrect'][bugId] = infoList
127 elif 'drawingml' in changedFiles:
128 results['impress']['drawingml'][bugId] = infoList
130 elif 'sd/source/ui/slidesorter/' in changedFiles:
131 results['impress']['slidesorter'][bugId] = infoList
133 elif 'sc/source/core/tool/interpr' in changedFiles:
134 results['calc']['import'][bugId] = infoList
136 elif 'svl/source/numbers/' in changedFiles:
137 results['calc']['format'][bugId] = infoList
139 # Keep the following if statements at the end
141 elif 'sc/source/core/' in changedFiles:
142 results['calc']['others'][bugId] = infoList
144 elif 'sw/source/core/' in changedFiles:
145 results['writer']['others'][bugId] = infoList
147 elif 'sd/source/core/' in changedFiles:
148 results['impress']['others'][bugId] = infoList
150 listOfBugIdsWithoutTest = []
151 for k,v in results.items():
152 for k1, v1 in v.items():
153 for bugId, info in v1.items():
154 if bugId not in hasTestSet:
155 listOfBugIdsWithoutTest.append(bugId)
157 bugzillaJson = []
158 #Split the list into different chunks for the requests, otherwise it fails
159 for chunk in splitList(listOfBugIdsWithoutTest, 50):
160 urlGet = 'https://bugs.documentfoundation.org/rest/bug?id=' + ','.join(chunk)
161 rGet = requests.get(urlGet)
162 rawData = json.loads(rGet.text)
163 rGet.close()
164 bugzillaJson.extend(rawData['bugs'])
166 print()
167 print('{{TopMenu}}')
168 print('{{Menu}}')
169 print('{{Menu.Development}}')
170 print()
171 print('This report is generated by ' + os.path.basename(sys.argv[0]))
172 print()
173 print('Date: ' + str(datetime.datetime.now()))
174 print()
175 print('Commits: ' + str(len(commits)))
176 print()
177 print('Branch: ' + branch.decode().strip())
178 print()
179 print('Hash: ' + str(last_hash.decode().strip()))
181 for k,v in results.items():
182 print('\n== ' + k + ' ==')
183 for k1, v1 in v.items():
184 print('\n=== ' + k1 + ' ===')
185 for bugId, info in v1.items():
187 resolution = ''
188 keywords = []
189 priority = ''
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 break
197 # Only care about FIXED bugs
198 # Ignore performance bugs and accessibility bugs
199 if resolution and resolution == 'FIXED' and 'perf' not in keywords \
200 and 'accessibility' not in keywords:
201 print(
202 "# {} - [{}] {} - [https://bugs.documentfoundation.org/show_bug.cgi?id={} tdf#{}]".format(
203 info[0], priority.upper(), info[1], bugId, bugId))
205 print('\n== ignored bugs ==')
206 print(' '.join(ignoredBugs))
207 print()
208 print('[[Category:QA]][[Category:Development]]')
210 def usage():
211 message = """usage: {program} [bugs to ignore (each one is one argument)]
213 Sample: {program} 10000 10001 10002"""
214 print(message.format(program = os.path.basename(sys.argv[0])))
216 if __name__ == '__main__':
218 args = set()
219 if len(sys.argv) > 1:
220 arg1 = sys.argv[1]
221 if arg1 == '-h' or arg1 == "--help":
222 usage()
223 sys.exit(1)
224 for i in sys.argv:
225 if i.isdigit():
226 args.add(i)
228 main(sorted(args))