Metadata-Version: 2.4
Name: ansible-lint2junit
Version: 1.0.0
Summary: ansible-lint to JUnit converter.
License: MIT
Project-URL: Homepage, https://gitlab.surrey.ac.uk/sm0049/ansible-lint2junit
Project-URL: Original, https://github.com/wasilak/ansible-lint-junit
Keywords: ansible,junit,gitlab
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.13
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Requires-Python: >=3.13
Description-Content-Type: text/markdown
License-File: LICENSE.txt
Requires-Dist: defusedxml>=0.7.1
Provides-Extra: test
Requires-Dist: pytest>=8; extra == "test"
Dynamic: license-file

# ansible-lint2junit

Converts [ansible-lint](https://github.com/ansible/ansible-lint) output into JUnit XML,
so lint findings show up as test results in CI — in particular in
[GitLab's test report UI](https://docs.gitlab.com/ee/ci/testing/unit_test_reports.html).

This is a fork of [wasilak/ansible-lint-junit](https://github.com/wasilak/ansible-lint-junit)
(MIT licensed), renamed and modernised for Python 3.13+ and GitLab:

- Testcases carry a stable identity (`classname` = ansible-lint rule ID, `name` = `file:line message`),
  so GitLab can track newly-failed/resolved findings between pipeline runs.
- Testcases carry a `file` attribute, so GitLab links each finding to the source file.
- Suite `tests`/`failures` counts reflect the actual findings (summary lines and blanks are ignored).
- No longer depends on `ansible-lint` itself — only its text output — so it installs
  cleanly alongside any ansible-lint version (the only dependency is `defusedxml`).

## Installation

From this project's [GitLab package registry](https://gitlab.surrey.ac.uk/sm0049/ansible-lint2junit/-/packages):

```shell
pip install ansible-lint2junit --index-url https://gitlab.surrey.ac.uk/api/v4/projects/sm0049%2Fansible-lint2junit/packages/pypi/simple
```

## Usage

Pipe `ansible-lint -p` output in:

```shell
ansible-lint playbook.yml -p --nocolor | ansible-lint2junit -o ansible-lint.xml
```

or go via a file (multiple input files are concatenated):

```shell
ansible-lint -p --nocolor playbook.yml > ansible-lint.txt
ansible-lint2junit ansible-lint.txt -o ansible-lint.xml
```

Options:

| Option | Description |
| --- | --- |
| `-o FILE` | output file (default `ansible-lint2junit.xml`) |
| `-v` | also print the XML to stdout |
| `-d` | emit a single dummy testcase when there are no findings, for CI parsers that reject empty suites |
| `--version` | print version |

## GitLab CI example

```yaml
ansible-lint:
  image: python:3.13
  script:
    - pip install ansible-lint
    - pip install ansible-lint2junit --index-url https://gitlab.surrey.ac.uk/api/v4/projects/sm0049%2Fansible-lint2junit/packages/pypi/simple
    - ansible-lint -p --nocolor . > ansible-lint.txt || true
    - ansible-lint2junit ansible-lint.txt -o ansible-lint.xml
    - "! grep -q '<failure' ansible-lint.xml"
  artifacts:
    when: always
    reports:
      junit: ansible-lint.xml
```

The `|| true` keeps the job running so the report is always generated; the final `grep`
fails the job when there are findings, after the report exists. Drop it if lint findings
should not fail the pipeline.

## Output

- Findings become JUnit `<failure>` testcases, grouped by ansible-lint rule.
- Clean input still produces a valid (empty) JUnit XML file, so JUnit parsers that
  fail on a missing report (e.g. Bamboo) keep working. Use `-d` for parsers that
  also reject suites with zero tests.
- Both modern ansible-lint (`rule-id[subrule] message`) and legacy (`[E301] message`)
  output formats are recognised; unrecognised lines that still look like
  `file:line: message` are kept with a generic `ansible-lint` classname.

## Development

```shell
pip install -e .[test]
pytest
```

## License

Distributed under the MIT license, as is the
[original project](https://github.com/wasilak/ansible-lint-junit) by Piotr Boruc.
