Merge ~pieq/oem-qa-autosummary:fix-1930349-ignore-non-url-text into oem-qa-autosummary:master

Proposed by Pierre Equoy
Status: Merged
Approved by: Pierre Equoy
Approved revision: bd8c0385dd549d5f2ebbe92bc975c43e3b037347
Merged at revision: 6327e7ff7aacdc70723836a4395b1d1de9508379
Proposed branch: ~pieq/oem-qa-autosummary:fix-1930349-ignore-non-url-text
Merge into: oem-qa-autosummary:master
Diff against target: 285 lines (+100/-51)
5 files modified
autosummary/summary.py (+20/-11)
logging_conf.py (+18/-18)
tests/test_webapp.py (+30/-6)
webapp/__init__.py (+27/-11)
webapp/templates/index.html (+5/-5)
Reviewer Review Type Date Requested Status
StanleyHuang Approve
Review via email: mp+415496@code.launchpad.net

Description of the change

Now, when generating the summary:

- Full Test Reports and Stress Test Reports text fields from the HTML form are parsed to extract C3 submission URLs and nothing else. If user includes additional information, it will be discarded.
- HTML Report is now parsed to only return a URL and nothing else. If user has entered something like "blabla https://link.to/my-html-report useless text", all the text is trimmed apart from "https://link.to/my-html-report"

Tests:

- unit test (run $ python -m unittest discover -s tests -v)
- generated report using the carlsbad project with different content for the full, stress and HTML reports.

Note:
Please check commits individually, as one of them is a Black code formatting commit that is not related to this modification...

To post a comment you must log in.
Revision history for this message
StanleyHuang (stanley31) wrote :

just a small suggestion about the regular expression pattern.

Revision history for this message
Pierre Equoy (pieq) wrote :

Answered inline.

Revision history for this message
StanleyHuang (stanley31) wrote :

OK, then this MR looks good to me.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/autosummary/summary.py b/autosummary/summary.py
2index 6117361..935f732 100644
3--- a/autosummary/summary.py
4+++ b/autosummary/summary.py
5@@ -26,8 +26,12 @@ class Summary:
6 self.launchpad = launchpad
7 self.image_url = image_url
8
9- logging.info((f"Preparing launchpad API for {self.project_name} "
10- f"- {self.milestone_name}"))
11+ logging.info(
12+ (
13+ f"Preparing launchpad API for {self.project_name} "
14+ f"- {self.milestone_name}"
15+ )
16+ )
17 self.lp_project = self.launchpad.projects[self.project_name]
18 self.lp_milestone = self.lp_project.getMilestone(name=self.milestone_name)
19 self.series_name = self.lp_milestone.series_target.name
20@@ -82,8 +86,12 @@ class Summary:
21 created_before = datetime.today()
22
23 new_bugs = []
24- logging.info((f"Search bugs from {created_since} to {created_before}"
25- f" for {self.project_name} project"))
26+ logging.info(
27+ (
28+ f"Search bugs from {created_since} to {created_before}"
29+ f" for {self.project_name} project"
30+ )
31+ )
32 bugs = self.lp_project.searchTasks(
33 created_since=created_since, created_before=created_before
34 )
35@@ -120,8 +128,7 @@ class Summary:
36 image_sha256 = ""
37 buff = io.BytesIO()
38 uri = os.path.join(self.get_milestone_uri(), "mail.content")
39- logging.info(
40- f"Try to get mail.content file from WebDAV server. URI: {uri}")
41+ logging.info(f"Try to get mail.content file from WebDAV server. URI: {uri}")
42 try:
43 self.webdav_client.download_from(buff, uri)
44 buff.seek(0)
45@@ -135,7 +142,9 @@ class Summary:
46
47 image_name = image_path.strip().split("/")[-1]
48 except Exception:
49- raise MailContentNotFoundError("the mail.content file is not found on the WebDAV server")
50+ raise MailContentNotFoundError(
51+ "the mail.content file is not found on the WebDAV server"
52+ )
53
54 logging.info(f"Image: {image_name}, SHA256: {image_sha256}")
55 return image_name, image_sha256
56@@ -155,7 +164,9 @@ class Summary:
57 content = buff.read()
58 sha256 = content.decode().split()[0]
59 except Exception:
60- raise Sha256FileNotFoundError("sha256sum file for a given image is not found on the WebDAV server")
61+ raise Sha256FileNotFoundError(
62+ "sha256sum file for a given image is not found on the WebDAV server"
63+ )
64
65 return sha256
66
67@@ -174,9 +185,7 @@ class Summary:
68 if self.series_name == "trunk":
69 uri = f"/share/{self.project_name}/releases/{self.milestone_name}/"
70 else:
71- uri = (
72- f"/share/{self.project_name}/{self.series_name}/{self.milestone_name}/"
73- )
74+ uri = f"/share/{self.project_name}/{self.series_name}/{self.milestone_name}/"
75 return uri
76
77
78diff --git a/logging_conf.py b/logging_conf.py
79index 0143717..aa9cafe 100644
80--- a/logging_conf.py
81+++ b/logging_conf.py
82@@ -1,22 +1,22 @@
83 import os
84 from logging.config import dictConfig
85
86-autosummary_logging_conf = dictConfig({
87- 'version': 1,
88- 'formatters': {
89- 'default': {
90- 'format': '[%(asctime)s] [%(filename)s/%(funcName)s] [%(levelname)s] %(message)s',
91- 'datefmt': '%Y-%m-%dT%H:%M:%S'
92+autosummary_logging_conf = dictConfig(
93+ {
94+ "version": 1,
95+ "formatters": {
96+ "default": {
97+ "format": "[%(asctime)s] [%(filename)s/%(funcName)s] [%(levelname)s] %(message)s",
98+ "datefmt": "%Y-%m-%dT%H:%M:%S",
99+ }
100 },
101- },
102- 'handlers': {
103- 'stdout': {
104- 'class': "logging.StreamHandler",
105- 'stream': 'ext://sys.stdout',
106- 'formatter': 'default'
107- }
108- },
109- 'root': {
110- 'handlers': ['stdout'],
111- 'level': os.getenv('APP_LOG_LEVEL', 'INFO')},
112-})
113\ No newline at end of file
114+ "handlers": {
115+ "stdout": {
116+ "class": "logging.StreamHandler",
117+ "stream": "ext://sys.stdout",
118+ "formatter": "default",
119+ }
120+ },
121+ "root": {"handlers": ["stdout"], "level": os.getenv("APP_LOG_LEVEL", "INFO")},
122+ }
123+)
124diff --git a/tests/test_webapp.py b/tests/test_webapp.py
125index d63af1c..e81949f 100644
126--- a/tests/test_webapp.py
127+++ b/tests/test_webapp.py
128@@ -9,8 +9,10 @@ class TestWebapp(unittest.TestCase):
129 Test bug links can be generated as expected
130 """
131 test_data = [
132- ("https://bugs.launchpad.net/project/+bug/1955391",
133- '<a href="https://bugs.launchpad.net/project/+bug/1955391/">#1955391</a>'),
134+ (
135+ "https://bugs.launchpad.net/project/+bug/1955391",
136+ '<a href="https://bugs.launchpad.net/project/+bug/1955391/">#1955391</a>',
137+ )
138 ]
139 for web_link, html_link in test_data:
140 with self.subTest():
141@@ -21,15 +23,37 @@ class TestWebapp(unittest.TestCase):
142 Test bug title can be generated as expected
143 """
144 test_data = [
145- ('Bug #123456 in The Given project: "Actual title of the bug"',
146- "Actual title of the bug"),
147- ('Bug #123456 in The Given project: "Actual \"title\" of the bug"',
148- 'Actual "title" of the bug'),
149+ (
150+ 'Bug #123456 in The Given project: "Actual title of the bug"',
151+ "Actual title of the bug",
152+ ),
153+ (
154+ 'Bug #123456 in The Given project: "Actual "title" of the bug"',
155+ 'Actual "title" of the bug',
156+ ),
157 ]
158 for full_title, expected_title in test_data:
159 with self.subTest():
160 self.assertEqual(webapp.bug_title(full_title), expected_title)
161
162+ def test_generate_reports_list(self):
163+ """
164+ Test raw string of C3 submissions can be turned into a list of URLs
165+ """
166+ test_data = (
167+ "https://certification.canonical.com/hardware/202109-29496/submission/239150/\r\nhttps"
168+ "://certification.canonical.com/hardware/202109-29496/submission/238308/\r\nand another "
169+ "one:\r\nhttps://certification.canonical.com/hardware/202109-29496/submission/237433/\r\nlast: "
170+ "https://certification.canonical.com/hardware/202109-29496/submission/237433/ "
171+ )
172+ expected_list = [
173+ "https://certification.canonical.com/hardware/202109-29496/submission/239150/",
174+ "https://certification.canonical.com/hardware/202109-29496/submission/238308/",
175+ "https://certification.canonical.com/hardware/202109-29496/submission/237433/",
176+ "https://certification.canonical.com/hardware/202109-29496/submission/237433/",
177+ ]
178+ self.assertEqual(webapp.generate_reports_list(test_data), expected_list)
179+
180
181 if __name__ == "__main__":
182 unittest.main()
183diff --git a/webapp/__init__.py b/webapp/__init__.py
184index 5eec28f..88a3941 100644
185--- a/webapp/__init__.py
186+++ b/webapp/__init__.py
187@@ -46,6 +46,19 @@ launchpad = Launchpad.login_with(
188 )
189
190
191+def generate_reports_list(reports):
192+ """
193+ Take raw reports string from HTML textarea and generate a list of C3 submission URLs.
194+ """
195+ # C3 submission URL such as:
196+ # https://certification.canonical.com/hardware/202109-29496/submission/239150/
197+ reports_list = re.findall(
198+ r"http?s://[\w.]*/hardware/[\d-]*/submission/[\d-]*/?", reports
199+ )
200+
201+ return reports_list
202+
203+
204 @app.template_filter("cid_to_html")
205 def cid_to_html(hardware):
206 rexp = r".*(?P<cid>20\d{4}-\d{5,6}).*"
207@@ -78,7 +91,7 @@ def bug_link(web_link):
208 # https://bugs.launchpad.net/project/+bug/123456
209 bug_id = web_link.split("/")[-1]
210
211- bug_link = f"<a href=\"{web_link}/\">#{bug_id}</a>"
212+ bug_link = f'<a href="{web_link}/">#{bug_id}</a>'
213 return bug_link
214
215
216@@ -89,8 +102,8 @@ def bug_title(title):
217 """
218 # `title` comes from `bug_task.title` and looks like
219 # Bug #123456 in The Given project: "Actual title of the bug"
220- idx = title.find("\"")
221- bug_title = title[idx+1:-1]
222+ idx = title.find('"')
223+ bug_title = title[idx + 1 : -1]
224 return bug_title
225
226
227@@ -177,12 +190,14 @@ def generate_summary():
228 # Splitting each line, removing empty lines or lines with only spaces and
229 # stripping non-empty lines to remove spaces at the beginning/end.
230 hardware_list = [line.strip() for line in hardware.splitlines() if line.strip()]
231- full_test_reports_list = [
232- line.strip() for line in full_test_reports.splitlines() if line.strip()
233- ]
234- stress_test_reports_list = [
235- line.strip() for line in stress_test_reports.splitlines() if line.strip()
236- ]
237+
238+ if html_report:
239+ # Split the string and return the item starting with `http` (our HTML report URL)
240+ html_report = [txt for txt in html_report.split() if txt.startswith("http")][0]
241+
242+ full_test_reports_list = generate_reports_list(full_test_reports)
243+ stress_test_reports_list = generate_reports_list(stress_test_reports)
244+
245 return render_template(
246 "summary.html",
247 report=report,
248@@ -214,8 +229,9 @@ def add_test_status():
249 )
250 response = res.json()
251 status_code = res.status_code
252- logging.info((f"Add status status code: {status_code},"
253- f" response: {response}"))
254+ logging.info(
255+ (f"Add status status code: {status_code}," f" response: {response}")
256+ )
257 except requests.exceptions.ConnectionError:
258 response = None
259 logging.exception("Cannot connect to Auto Test Status Tracker Web Service")
260diff --git a/webapp/templates/index.html b/webapp/templates/index.html
261index d220caa..f160c65 100644
262--- a/webapp/templates/index.html
263+++ b/webapp/templates/index.html
264@@ -49,16 +49,16 @@
265 <textarea id="hardware" name="hardware" placeholder="E.ON smart speaker PVT and PVT w/ new emmc (CID: 201912-27580)"></textarea>
266 </li>
267 <li>
268- <label for="full_test_reports">C3 Full Test Report(s):</label>
269- <textarea id="full_test_reports" name="full_test_reports" placeholder="Link(s) to the C3 submission(s), e.g. https://certification.canonical.com/hardware/201712-26014/submission/136315/"></textarea>
270+ <label for="full_test_reports">C3 Full Test Reports (one link per line):</label>
271+ <textarea id="full_test_reports" name="full_test_reports" placeholder="https://certification.canonical.com/hardware/201712-26014/submission/136315/"></textarea>
272 </li>
273 <li>
274- <label for="stress_test_reports">C3 Stress Test Report(s):</label>
275- <textarea id="stress_test_reports" name="stress_test_reports" placeholder="Link(s) to the C3 submission(s), e.g. https://certification.canonical.com/hardware/201712-26014/submission/136315/"></textarea>
276+ <label for="stress_test_reports">C3 Stress Test Reports (one link per line):</label>
277+ <textarea id="stress_test_reports" name="stress_test_reports" placeholder="https://certification.canonical.com/hardware/201712-26014/submission/136315/"></textarea>
278 </li>
279 <li>
280 <label for="html_report">HTML Report:</label>
281- <input type="text" id="html_report" name="html_report" placeholder="e.g. https://drive.google.com/file/d/1AbtuH-Q0a6kPcup4VWluz8RbZu64oOQB">
282+ <input type="text" id="html_report" name="html_report" placeholder="https://drive.google.com/file/d/1AbtuH-Q0a6kPcup4VWluz8RbZu64oOQB">
283 </li>
284 <li>
285 <label for="scope">Scope:</label>

Subscribers

People subscribed via source and target branches

to all changes: