Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for TRX files #287

Merged
merged 32 commits into from Jun 21, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
e738dc1
Allow to specify TRX files glob
EnricoMi May 23, 2022
6fbc70c
Parse TRX files
EnricoMi May 23, 2022
2ac64d0
Remove useage of pkg_resources
EnricoMi May 23, 2022
78e8387
Fix tests for Windows
EnricoMi May 23, 2022
a956ab0
Add credits for xslt and example trx files
EnricoMi May 23, 2022
7f84b6c
More README.md and actions.yml changes
EnricoMi May 24, 2022
b480292
Add TRX test
EnricoMi May 24, 2022
e516c7d
Add trx files to publish-test-files
EnricoMi May 24, 2022
90aa3ec
Move test files into sub-directories
EnricoMi May 23, 2022
e896c0a
Parse all example files and compare to expectations
EnricoMi May 26, 2022
82a4129
Run tests on all example test result files
EnricoMi May 26, 2022
9c533d7
Add missing results file
EnricoMi May 26, 2022
c43424a
Fix automated example file tests on Windows
EnricoMi May 26, 2022
6c978a9
Make exception string work for 3.6
EnricoMi May 26, 2022
72f702d
Test parse and process example files with locales
EnricoMi May 27, 2022
2220626
Fixing duration number format in trx xslt
EnricoMi May 27, 2022
5a04a32
Remove MESSAGE and STACK TRACE from xslt
EnricoMi May 27, 2022
519a09a
Use failure template in trx-to-junit.xslt
EnricoMi May 27, 2022
23852ba
Automated example file test supersedes transformation test
EnricoMi May 26, 2022
9ecb571
Make test_files_path private so it is not considered a test
EnricoMi May 26, 2022
1a33f55
Allow for NaN time values
EnricoMi Jun 5, 2022
1a48953
Add skipped results
EnricoMi Jun 5, 2022
69ff412
Extract class name when there is no comma, remove class name from tes…
EnricoMi Jun 5, 2022
9ceb86e
Do not produce NaN times
EnricoMi Jun 5, 2022
c66c896
Push UnitTest selection by id into xpath select
EnricoMi Jun 5, 2022
9e06502
Update stats over all test example files
EnricoMi Jun 5, 2022
e1fe3d1
Make duration from timestamps work with date boundaries and daylight …
EnricoMi Jun 6, 2022
f4b1f39
Make duration from timestamps work beyond 2038 (32-bit seconds)
EnricoMi Jun 6, 2022
a9af6a2
Guard against NaN suite times
EnricoMi Jun 6, 2022
e9d990a
Fix single file publish
EnricoMi Jun 6, 2022
0bcc218
Some changes in README.md got lost, added again
EnricoMi Jun 6, 2022
7067fa3
Introduce JUnitTreeOrException and ParsedJUnitFile
EnricoMi Jun 14, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
17 changes: 7 additions & 10 deletions .github/workflows/ci-cd.yml
Expand Up @@ -202,7 +202,7 @@ jobs:
id: test-results
if: always()
run: |
docker run --workdir $GITHUB_WORKSPACE --rm -e INPUT_CHECK_NAME -e INPUT_JUNIT_FILES -e INPUT_TIME_UNIT -e INPUT_GITHUB_TOKEN -e INPUT_GITHUB_RETRIES -e INPUT_COMMIT -e INPUT_COMMENT_TITLE -e INPUT_FAIL_ON -e INPUT_REPORT_INDIVIDUAL_RUNS -e INPUT_DEDUPLICATE_CLASSES_BY_FILE_NAME -e INPUT_IGNORE_RUNS -e INPUT_HIDE_COMMENTS -e INPUT_COMMENT_ON_PR -e INPUT_COMMENT_MODE -e INPUT_COMPARE_TO_EARLIER_COMMIT -e INPUT_PULL_REQUEST_BUILD -e INPUT_EVENT_FILE -e INPUT_EVENT_NAME -e INPUT_TEST_CHANGES_LIMIT -e INPUT_CHECK_RUN_ANNOTATIONS -e INPUT_CHECK_RUN_ANNOTATIONS_BRANCH -e INPUT_SECONDS_BETWEEN_GITHUB_READS -e INPUT_SECONDS_BETWEEN_GITHUB_WRITES -e INPUT_JSON_FILE -e INPUT_JSON_THOUSANDS_SEPARATOR -e INPUT_JOB_SUMMARY -e HOME -e GITHUB_JOB -e GITHUB_REF -e GITHUB_SHA -e GITHUB_REPOSITORY -e GITHUB_REPOSITORY_OWNER -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RETENTION_DAYS -e GITHUB_ACTOR -e GITHUB_WORKFLOW -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GITHUB_EVENT_NAME -e GITHUB_SERVER_URL -e GITHUB_API_URL -e GITHUB_GRAPHQL_URL -e GITHUB_WORKSPACE -e GITHUB_ACTION -e GITHUB_EVENT_PATH -e GITHUB_ACTION_REPOSITORY -e GITHUB_ACTION_REF -e GITHUB_PATH -e GITHUB_ENV -e GITHUB_STEP_SUMMARY -e RUNNER_OS -e RUNNER_TOOL_CACHE -e RUNNER_TEMP -e RUNNER_WORKSPACE -e ACTIONS_RUNTIME_URL -e ACTIONS_RUNTIME_TOKEN -e ACTIONS_CACHE_URL -e GITHUB_ACTIONS=true -e CI=true -v "/var/run/docker.sock":"/var/run/docker.sock" -v "$RUNNER_TEMP":"$RUNNER_TEMP" -v "$GITHUB_WORKSPACE":"$GITHUB_WORKSPACE" enricomi/publish-unit-test-result-action:latest
docker run --workdir $GITHUB_WORKSPACE --rm -e INPUT_CHECK_NAME -e INPUT_JUNIT_FILES -e INPUT_TRX_FILES -e INPUT_TIME_UNIT -e INPUT_GITHUB_TOKEN -e INPUT_GITHUB_RETRIES -e INPUT_COMMIT -e INPUT_COMMENT_TITLE -e INPUT_FAIL_ON -e INPUT_REPORT_INDIVIDUAL_RUNS -e INPUT_DEDUPLICATE_CLASSES_BY_FILE_NAME -e INPUT_IGNORE_RUNS -e INPUT_HIDE_COMMENTS -e INPUT_COMMENT_ON_PR -e INPUT_COMMENT_MODE -e INPUT_COMPARE_TO_EARLIER_COMMIT -e INPUT_PULL_REQUEST_BUILD -e INPUT_EVENT_FILE -e INPUT_EVENT_NAME -e INPUT_TEST_CHANGES_LIMIT -e INPUT_CHECK_RUN_ANNOTATIONS -e INPUT_CHECK_RUN_ANNOTATIONS_BRANCH -e INPUT_SECONDS_BETWEEN_GITHUB_READS -e INPUT_SECONDS_BETWEEN_GITHUB_WRITES -e INPUT_JSON_FILE -e INPUT_JSON_THOUSANDS_SEPARATOR -e INPUT_JOB_SUMMARY -e HOME -e GITHUB_JOB -e GITHUB_REF -e GITHUB_SHA -e GITHUB_REPOSITORY -e GITHUB_REPOSITORY_OWNER -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RETENTION_DAYS -e GITHUB_ACTOR -e GITHUB_WORKFLOW -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GITHUB_EVENT_NAME -e GITHUB_SERVER_URL -e GITHUB_API_URL -e GITHUB_GRAPHQL_URL -e GITHUB_WORKSPACE -e GITHUB_ACTION -e GITHUB_EVENT_PATH -e GITHUB_ACTION_REPOSITORY -e GITHUB_ACTION_REF -e GITHUB_PATH -e GITHUB_ENV -e GITHUB_STEP_SUMMARY -e RUNNER_OS -e RUNNER_TOOL_CACHE -e RUNNER_TEMP -e RUNNER_WORKSPACE -e ACTIONS_RUNTIME_URL -e ACTIONS_RUNTIME_TOKEN -e ACTIONS_CACHE_URL -e GITHUB_ACTIONS=true -e CI=true -v "/var/run/docker.sock":"/var/run/docker.sock" -v "$RUNNER_TEMP":"$RUNNER_TEMP" -v "$GITHUB_WORKSPACE":"$GITHUB_WORKSPACE" enricomi/publish-unit-test-result-action:latest
env:
INPUT_GITHUB_TOKEN: ${{ github.token }}
INPUT_CHECK_NAME: Test Results (Docker Image)
Expand Down Expand Up @@ -409,10 +409,8 @@ jobs:
- name: Checkout
uses: actions/checkout@v3

- name: Copy test junit xml files
run: |
mkdir -p test-files
cp -v python/test/files/*.xml test-files/
- name: Copy test files
run: cp -rv python/test/files test-files

- name: Prepare publish action from this branch
run: |
Expand All @@ -424,7 +422,8 @@ jobs:
with:
check_name: Test Results (Test Files)
fail_on: nothing
junit_files: "test-files/**.xml"
junit_files: "test-files/junit-xml/**/*.xml"
trx_files: "test-files/trx/**/*.trx"
json_file: "tests.json"
log_level: DEBUG

Expand Down Expand Up @@ -453,9 +452,7 @@ jobs:
uses: actions/checkout@v3

- name: Copy test junit xml files
run: |
mkdir -p test-files
cp -v python/test/files/*.xml test-files/
run: cp -rv python/test/files/junit-xml test-files

- name: Prepare publish action from this branch
run: |
Expand All @@ -467,7 +464,7 @@ jobs:
with:
check_name: Test Results (Test File)
fail_on: nothing
files: "test-files/junit.gloo.standalone.xml"
files: "test-files/pytest/junit.gloo.standalone.xml"
json_file: "tests.json"
log_level: DEBUG

Expand Down
16 changes: 10 additions & 6 deletions README.md
Expand Up @@ -13,7 +13,7 @@
[![Test Results](https://gist.githubusercontent.com/EnricoMi/612cb538c14731f1a8fefe504f519395/raw/badge.svg)](https://gist.githubusercontent.com/EnricoMi/612cb538c14731f1a8fefe504f519395/raw/badge.svg)

This [GitHub Action](https://github.com/actions) analyses test result files and
publishes the results on GitHub. It supports the JUnit XML file format and runs on Linux, macOS and Windows.
publishes the results on GitHub. It supports the JUnit XML and TRX file formats, and runs on Linux, macOS and Windows.

You can add this action to your GitHub workflow for ![Ubuntu Linux](https://badgen.net/badge/icon/Ubuntu?icon=terminal&label) (e.g. `runs-on: ubuntu-latest`) runners:

Expand All @@ -23,6 +23,7 @@ You can add this action to your GitHub workflow for ![Ubuntu Linux](https://badg
if: always()
with:
junit_files: "test-results/**/*.xml"
trx_files: "test-results/**/*.trx"
```

Use this for ![macOS](https://badgen.net/badge/icon/macOS?icon=apple&label) (e.g. `runs-on: macos-latest`)
Expand All @@ -34,6 +35,7 @@ and ![Windows](https://badgen.net/badge/icon/Windows?icon=windows&label) (e.g. `
if: always()
with:
junit_files: "test-results/**/*.xml"
trx_files: "test-results/**/*.trx"
```

See the [notes on running this action as a composite action](#running-as-a-composite-action) if you run it on Windows or macOS.
Expand Down Expand Up @@ -180,10 +182,12 @@ With `comment_mode: off`, the `pull-requests: write` permission is not needed.

## Configuration

Files can be selected via the `files` option, which is optional and defaults to `*.xml` in the current working directory.
[It supports wildcards](https://docs.python.org/3/library/glob.html#glob.glob) like `*`, `**`, `?` and `[]`.
Files can be selected via the `junit_files` and `trx_files` options.
They support [glob wildcards](https://docs.python.org/3/library/glob.html#glob.glob) like `*`, `**`, `?` and `[]`.
The `**` wildcard matches all files and directories recursively: `./`, `./*/`, `./*/*/`, etc.

At least one of `junit_files` and `trx_files` options have to be set.

You can provide multiple file patterns, one pattern per line. Patterns starting with `!` exclude the matching files.
There have to be at least one pattern starting without a `!`:

Expand All @@ -198,11 +202,11 @@ The list of most notable options:

|Option|Default Value|Description|
|:-----|:-----:|:----------|
|`junit_files`|`*.xml`|File patterns of JUnit XML test result files. Supports `*`, `**`, `?`, and `[]`. Use multiline string for multiple patterns. Patterns starting with `!` exclude the matching files. There have to be at least one pattern starting without a `!`.|
|`junit_files`<br/>`trx_files`|At least one of these `*_files` must be set.|File patterns of JUnit XML and TRX test result files, respectively. Supports `*`, `**`, `?`, and `[]`. Use multiline string for multiple patterns. Patterns starting with `!` exclude the matching files. There have to be at least one pattern starting without a `!`.|
|`check_name`|`"Test Results"`|An alternative name for the check result.|
|`comment_title`|same as `check_name`|An alternative name for the pull request comment.|
|`comment_mode`|`always`|The action posts comments to pull requests that are associated with the commit. Set to:<br/>`always` - always comment<br/>`changes` - comment when changes w.r.t. the target branch exist<br/>`changes in failures` - when changes in the number of failures and errors exist<br/>`changes in errors` - when changes in the number of (only) errors exist<br/>`failures` - when failures or errors exist<br/>`errors` - when (only) errors exist<br/>`off` - to not create pull request comments.|
|`ignore_runs`|`false`|Does not process test run information by ignoring `<testcase>` elements in the XML files, which is useful for very large XML files. This disables any check run annotations.|
|`ignore_runs`|`false`|Does not collect test run information from the test result files, which is useful for very large files. This disables any check run annotations.|

<details>
<summary>Options related to Git and GitHub</summary>
Expand Down Expand Up @@ -651,7 +655,7 @@ If this conflicts with actions that later run Python in the same workflow (which
it is recommended to run this action as the last step in your workflow, or to run it in an isolated workflow.
Running it in an isolated workflow is similar to the workflows shown in [Use with matrix strategy](#use-with-matrix-strategy).

To run the composite action in an isolated workflow, your CI workflow should upload all test result XML files:
To run the composite action in an isolated workflow, your CI workflow should upload all test result files:

```yaml
build-and-test:
Expand Down
7 changes: 5 additions & 2 deletions action.yml
Expand Up @@ -32,8 +32,11 @@ inputs:
junit_files:
description: 'File patterns of JUnit XML test result files. Supports *, **, ?, and []. Use multiline string for multiple patterns. Patterns starting with ! exclude the matching files. There have to be at least one pattern starting without a `!`.'
required: false
trx_files:
description: 'File patterns of TRX test result files. Supports *, **, ?, and []. Use multiline string for multiple patterns. Patterns starting with ! exclude the matching files. There have to be at least one pattern starting without a `!`.'
required: false
time_unit:
description: 'Time values in the XML files have this unit. Supports "seconds" and "milliseconds".'
description: 'Time values in the test result files have this unit. Supports "seconds" and "milliseconds".'
default: 'seconds'
required: false
report_individual_runs:
Expand All @@ -43,7 +46,7 @@ inputs:
description: 'De-duplicates classes with same name by their file name when set "true", combines test results for those classes otherwise'
required: false
ignore_runs:
description: 'Does not process test run information by ignoring <testcase> elements in the XML files, which is useful for very large XML files. This disables any check run annotations'
description: 'Does not collect test run information from the test result files, which is useful for very large files. This disables any check run annotations'
default: 'false'
required: false
hide_comments:
Expand Down
8 changes: 6 additions & 2 deletions composite/action.yml
Expand Up @@ -32,8 +32,11 @@ inputs:
junit_files:
description: 'File patterns of JUnit XML test result files. Supports *, **, ?, and []. Use multiline string for multiple patterns. Patterns starting with ! exclude the matching files. There have to be at least one pattern starting without a `!`.'
required: false
trx_files:
description: 'File patterns of TRX test result files. Supports *, **, ?, and []. Use multiline string for multiple patterns. Patterns starting with ! exclude the matching files. There have to be at least one pattern starting without a `!`.'
required: false
time_unit:
description: 'Time values in the XML files have this unit. Supports "seconds" and "milliseconds".'
description: 'Time values in the test result files have this unit. Supports "seconds" and "milliseconds".'
default: 'seconds'
required: false
report_individual_runs:
Expand All @@ -43,7 +46,7 @@ inputs:
description: 'De-duplicates classes with same name by their file name when set "true", combines test results for those classes otherwise'
required: false
ignore_runs:
description: 'Does not process test run information by ignoring <testcase> elements in the XML files, which is useful for very large XML files. This disables any check run annotations'
description: 'Does not collect test run information from the test result files, which is useful for very large files. This disables any check run annotations'
default: 'false'
required: false
hide_comments:
Expand Down Expand Up @@ -154,6 +157,7 @@ runs:
# deprecated
FILES: ${{ inputs.files }}
JUNIT_FILES: ${{ inputs.junit_files }}
TRX_FILES: ${{ inputs.trx_files }}
TIME_UNIT: ${{ inputs.time_unit }}
REPORT_INDIVIDUAL_RUNS: ${{ inputs.report_individual_runs }}
DEDUPLICATE_CLASSES_BY_FILE_NAME: ${{ inputs.deduplicate_classes_by_file_name }}
Expand Down
50 changes: 37 additions & 13 deletions python/publish/junit.py
@@ -1,9 +1,10 @@
import math
import os
from collections import defaultdict
from typing import Optional, Iterable, Union, Any, List, Dict, Callable, Tuple
from typing import Optional, Iterable, Union, List, Dict, Callable, Tuple

import junitparser
from junitparser import Element, JUnitXml, TestCase, TestSuite, Skipped
from junitparser import Element, JUnitXml, JUnitXmlError, TestCase, TestSuite, Skipped
from junitparser.junitparser import etree

from publish.unittestresults import ParsedUnitTestResults, UnitTestCase, ParseError
Expand Down Expand Up @@ -118,12 +119,16 @@ def close(self) -> Element:
return super().close()


JUnitTree = etree.ElementTree
JUnitTreeOrException = Union[JUnitTree, BaseException]
ParsedJUnitFile = Tuple[str, JUnitTreeOrException]


def parse_junit_xml_files(files: Iterable[str],
time_factor: float = 1.0,
drop_testcases: bool = False,
progress: Callable[[Tuple[str, Union[JUnitXml, BaseException]]], Tuple[str, Union[JUnitXml, BaseException]]] = lambda x: x) -> ParsedUnitTestResults:
"""Parses junit xml files and returns aggregated statistics as a ParsedUnitTestResults."""
def parse(path: str) -> Union[JUnitXml, BaseException]:
progress: Callable[[ParsedJUnitFile], ParsedJUnitFile] = lambda x: x) -> Iterable[ParsedJUnitFile]:
def parse(path: str) -> JUnitTreeOrException:
"""Parses a junit xml file and returns either a JUnitTree or an Exception."""
if not os.path.exists(path):
return FileNotFoundError(f'File does not exist.')
if os.stat(path).st_size == 0:
Expand All @@ -132,27 +137,46 @@ def parse(path: str) -> Union[JUnitXml, BaseException]:
try:
if drop_testcases:
builder = DropTestCaseBuilder()
return JUnitXml.fromfile(path, parse_func=builder.parse)
return JUnitXml.fromfile(path)
return etree.parse(path, parser=etree.XMLParser(target=builder, encoding='utf-8'))
return etree.parse(path)
except BaseException as e:
return e

parsed_files = [progress((result_file, parse(result_file))) for result_file in files]
return [progress((result_file, parse(result_file))) for result_file in files]


def process_junit_xml_elems(trees: Iterable[ParsedJUnitFile], time_factor: float = 1.0) -> ParsedUnitTestResults:
# TODO: move upstream into JUnitTree
def create_junitxml(filepath: str, tree: JUnitTree) -> Union[JUnitXml, JUnitXmlError]:
root_elem = tree.getroot()
if root_elem.tag == "testsuites":
instance = JUnitXml()
elif root_elem.tag == "testsuite":
instance = TestSuite()
else:
return JUnitXmlError("Invalid format.")
instance._elem = root_elem
instance.filepath = filepath
return instance

processed = [(result_file, create_junitxml(result_file, tree) if not isinstance(tree, BaseException) else tree)
for result_file, tree in trees]
junits = [(result_file, junit)
for result_file, junit in parsed_files
for result_file, junit in processed
if not isinstance(junit, BaseException)]
errors = [ParseError.from_exception(result_file, exception)
for result_file, exception in parsed_files
for result_file, exception in processed
if isinstance(exception, BaseException)]

suites = [(result_file, suite)
for result_file, junit in junits
for suite in (junit if junit._tag == "testsuites" else [junit])]

suite_tests = sum([suite.tests for result_file, suite in suites])
suite_skipped = sum([suite.skipped + suite.disabled for result_file, suite in suites])
suite_failures = sum([suite.failures for result_file, suite in suites])
suite_errors = sum([suite.errors for result_file, suite in suites])
suite_time = int(sum([suite.time for result_file, suite in suites]) * time_factor)
suite_time = int(sum([suite.time for result_file, suite in suites if not math.isnan(suite.time)]) * time_factor)

def int_opt(string: Optional[str]) -> Optional[int]:
try:
Expand Down Expand Up @@ -192,7 +216,7 @@ def get_cases(suite: TestSuite) -> List[TestCase]:
]

return ParsedUnitTestResults(
files=len(parsed_files),
files=len(list(trees)),
errors=errors,
# test state counts from suites
suites=len(suites),
Expand Down
4 changes: 3 additions & 1 deletion python/publish/publisher.py
Expand Up @@ -43,7 +43,9 @@ class Settings:
json_thousands_separator: str
fail_on_errors: bool
fail_on_failures: bool
junit_files_glob: str
# one of these *_files_glob must be set
junit_files_glob: Optional[str]
trx_files_glob: Optional[str]
time_factor: float
check_name: str
comment_title: str
Expand Down
28 changes: 28 additions & 0 deletions python/publish/trx.py
@@ -0,0 +1,28 @@
import os
import pathlib
from typing import Iterable, Callable

from lxml import etree
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

blacklist: Using etree to parse untrusted XML data is known to be vulnerable to XML attacks. Replace etree with the equivalent defusedxml package.

(at-me in a reply with help or ignore)


Was this a good recommendation?
[ 🙁 Not relevant ] - [ 😕 Won't fix ] - [ 😑 Not critical, will fix ] - [ 🙂 Critical, will fix ] - [ 😊 Critical, fixing now ]

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

opt.semgrep.python.lang.security.use-defused-xml.use-defused-xml: Found use of the native Python XML libraries, which is vulnerable to XML external entity (XXE)
attacks. The Python documentation recommends the 'defusedxml' library instead if the XML being
loaded is untrusted.

(at-me in a reply with help or ignore)


Was this a good recommendation?
[ 🙁 Not relevant ] - [ 😕 Won't fix ] - [ 😑 Not critical, will fix ] - [ 🙂 Critical, will fix ] - [ 😊 Critical, fixing now ]


from publish.junit import JUnitTreeOrException, ParsedJUnitFile

with (pathlib.Path(__file__).parent / 'xslt' / 'trx-to-junit.xslt').open('r', encoding='utf-8') as r:
transform_trx_to_junit = etree.XSLT(etree.parse(r))
EnricoMi marked this conversation as resolved.
Show resolved Hide resolved


def parse_trx_files(files: Iterable[str],
progress: Callable[[ParsedJUnitFile], ParsedJUnitFile] = lambda x: x) -> Iterable[ParsedJUnitFile]:
def parse(path: str) -> JUnitTreeOrException:
"""Parses a trx file and returns either a JUnitTree or an Exception."""
if not os.path.exists(path):
return FileNotFoundError(f'File does not exist.')
if os.stat(path).st_size == 0:
return Exception(f'File is empty.')

try:
trx = etree.parse(path)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

blacklist: Using lxml.etree.parse to parse untrusted XML data is known to be vulnerable to XML attacks. Replace lxml.etree.parse with its defusedxml equivalent function.

(at-me in a reply with help or ignore)


Was this a good recommendation?
[ 🙁 Not relevant ] - [ 😕 Won't fix ] - [ 😑 Not critical, will fix ] - [ 🙂 Critical, will fix ] - [ 😊 Critical, fixing now ]

return transform_trx_to_junit(trx)
except BaseException as e:
return e

return [progress((result_file, parse(result_file))) for result_file in files]