Skip to content

Commit 2c1c245

Browse files
committed
provide for named junit files with distinct suite names
Change-Id: I03c658016fc9d7d8dc81b905d6f31d0d7026127d
1 parent 7930342 commit 2c1c245

3 files changed

Lines changed: 70 additions & 10 deletions

File tree

noxfile.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
if True:
1111
sys.path.insert(0, ".")
1212
from tools.toxnox import tox_parameters
13+
from tools.toxnox import extract_opts
14+
from tools.toxnox import move_junit_file
1315

1416

1517
PYTHON_VERSIONS = [
@@ -220,7 +222,23 @@ def _tests(
220222
case "dbm":
221223
backend_cmd.append("tests/cache/test_dbm_backend.py")
222224

223-
session.run(*pifpaf_cmd, *cmd, *backend_cmd, *session.posargs)
225+
posargs, opts = extract_opts(session.posargs, "generate-junit")
226+
227+
if opts.generate_junit:
228+
cmd.extend(["--junitxml", "junit-tmp.xml"])
229+
230+
session.run(*pifpaf_cmd, *cmd, *backend_cmd, *posargs)
231+
232+
# name the suites distinctly as well. this is so that when they get
233+
# merged we can view each suite distinctly rather than them getting
234+
# overwritten with each other since they are running the same tests
235+
if opts.generate_junit:
236+
# produce individual junit files that are per-database (or as close
237+
# as we can get). jenkins junit plugin will merge all the files...
238+
junitfile = f"junit-{target}.xml"
239+
suite_name = f"pytest-{target}"
240+
241+
move_junit_file("junit-tmp.xml", junitfile, suite_name)
224242

225243

226244
@nox.session(name="pep484")

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ tests = [
6666
"pytest>8",
6767
"pytest-xdist",
6868
"mako",
69+
"junitparser",
6970
]
7071

7172
coverage = [

tools/toxnox.py

Lines changed: 50 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,16 @@
1010

1111
from __future__ import annotations
1212

13+
import collections
14+
import os
1315
import re
1416
import sys
1517
from typing import Any
1618
from typing import Callable
19+
from typing import List
1720
from typing import Optional
1821
from typing import Sequence
22+
from typing import Tuple
1923

2024
import nox
2125

@@ -48,11 +52,12 @@ def tox_parameters(
4852
joined by ``-``, as well as combinations that include a subset of those
4953
values, where the omitted elements of the tag are implicitly considered to
5054
match the "default" value, indicated by them being first in their
51-
collection. Additionally, values that start with an underscore are omitted
52-
from all ids and tags. Values that refer to Python versions wlil be
53-
expanded to the full Python executable name when passed as arguments to
54-
the session function, which is currently a workaround to allow
55-
free-threaded python interpreters to be located.
55+
collection (with the exception of "python", where the current python in
56+
use is the default). Additionally, values that start with an underscore
57+
are omitted from all ids and tags. Values that refer to Python versions
58+
wlil be expanded to the full Python executable name when passed as
59+
arguments to the session function, which is currently a workaround to
60+
allow free-threaded python interpreters to be located.
5661
:param base_tag: optional tag that will be appended to all tags generated,
5762
e.g. if the decorator yields tags like ``python314-x86-windows``, a
5863
``basetag`` value of ``all`` would yield the
@@ -67,7 +72,7 @@ def tox_parameters(
6772
6873
"""
6974

70-
PY_RE = re.compile(r"(?:python)?([234]\.\d+t?)")
75+
PY_RE = re.compile(r"(?:python)?([234]\.\d+(t?))")
7176

7277
def _is_py_version(token):
7378
return bool(PY_RE.match(token))
@@ -80,8 +85,15 @@ def _expand_python_version(token):
8085
name
8186
8287
"""
88+
if sys.platform == "win32":
89+
return token
90+
8391
m = PY_RE.match(token)
84-
if m:
92+
93+
# do this matching minimally so that it only happens for the
94+
# free-threaded versions. on windows, the "pythonx.y" syntax doesn't
95+
# work due to the use of the "py" tool
96+
if m and m.group(2) == "t":
8597
return f"python{m.group(1)}"
8698
else:
8799
return token
@@ -181,7 +193,36 @@ def _recur_param(prevtokens, prevtags, token_lists):
181193
]
182194

183195
# for p in params:
184-
# print(f"PARAM {'-'.join(p.args)} TAGS {p.tags}")
185-
# breakpoint()
196+
# print(f"PARAM {'-'.join(p.args)} TAGS {p.tags}")
186197

187198
return nox.parametrize(names, params)
199+
200+
201+
def extract_opts(posargs: List[str], *args: str) -> Tuple[List[str], Any]:
202+
203+
underscore_args = [arg.replace("-", "_") for arg in args]
204+
return_tuple = collections.namedtuple("options", underscore_args)
205+
206+
look_for_args = {f"--{arg}": idx for idx, arg in enumerate(args)}
207+
return_args = [False for arg in args]
208+
209+
def extract(arg: str):
210+
if arg in look_for_args:
211+
return_args[look_for_args[arg]] = True
212+
return True
213+
else:
214+
return False
215+
216+
return [arg for arg in posargs if not extract(arg)], return_tuple(
217+
*return_args
218+
)
219+
220+
221+
def move_junit_file(tmpfilename: str, newname: str, suite_name: str):
222+
import junitparser
223+
224+
xml = junitparser.JUnitXml.fromfile(tmpfilename)
225+
for suite in xml:
226+
suite.name = suite_name
227+
xml.write(newname)
228+
os.unlink(tmpfilename)

0 commit comments

Comments
 (0)