# IssueReporter 1.0.1 > IssueReporter is out on Packagist. It reads the reports of the static analysis tools you already run, merges them into a single tree of issues, and writes the result as Markdown, HTML, ANSI text, JSON, XML or SARIF. One extra command in a pipeline replaces the pile of artifacts nobody opens. IssueReporter is our PHP library for static code analysis reports: it reads what the other tools produce, turns it into a single report, and renders that report in the shape you need. Version 1.0.1 is the first public release, and it is on Packagist: ``` composer require tuchsoft/issue-reporter ``` The same code is a library and a command line tool. The CLI is the narrow end of it: it reads files, merges them, runs the transformers and writes out one report. ## What it does - **Reads ten report formats.** PHP_CodeSniffer, Checkstyle, JUnit, GitLab, SonarQube, SARIF, LSP, Emacs, plus the library's own JSON and its XML twin. Every one of them can also be written back out, so a pipeline can start in one format and end in another. - **Merges several reports into one tree.** The root is the run, its children are the parts of the run (a plugin, a package, a configuration) and the leaves are the issues. Two reports of different formats merge into a single document, with each part keeping its own name and base path. - **Transforms the issues.** A transformer pipeline runs between reading and writing. The one shipped in 1.0 is `messagereplacer`: it fills Mustache placeholders in the message and help fields from the issue's own extra data, which is how you turn a generic rule message into a sentence with the actual value in it. - **Renders thirteen output formats.** Three are built for humans: `infomd` (Markdown tables), `infohtml` (HTML) and `info` (ANSI text with colour and emoji, for the terminal). Ten are machine formats: the ones above plus the raw JSON, which is the library's complete representation and round-trips everything. - **One JSON recipe for a complex run.** When the flags get long, a single recipe file describes inputs, tree, options, output and extra class registration. Pass the file, or pipe it in. The recipe is the single source of truth for that run. - **Extensible at runtime.** Your own format or transformer is a class implementing one interface; register it by class name or by namespace, and it shows up in `list-format` like the bundled ones. ## What it reads and what it writes | Format | Kind | Reads | Writes | | --- | --- | :---: | :---: | | `phpcs` | JSON | yes | yes | | `checkstyle` | XML | yes | yes | | `junit` | XML | yes | yes | | `gitlab` | JSON | yes | yes | | `sonarqube` | JSON | yes | yes | | `sarif` | JSON | yes | yes | | `lsp` | JSON | yes | yes | | `emacs` | text | yes | yes | | `raw` | JSON | yes | yes | | `rawxml` | XML | yes | yes | | `infomd` | Markdown | no | yes | | `infohtml` | HTML | no | yes | | `info` | ANSI text | no | yes | The three reader-less formats are the readable renderers: they are for the end of a pipeline, where a person looks at the output. ## Using it One report in, a readable summary out: ```bash bin/console convert phpcs:phpcs.json --to infomd -o report.md ``` The Markdown it writes opens with a summary table and then lists the issues grouped by file: ``` |Report|Files|Errors|Warnings|Tips|Time| |:-|:-|:-|:-|:-|:-| |Parsed phpcs report|1|1|1|0|0 ms| ``` Merging two different inputs into one machine format, which is the case this library was built for: ```bash bin/console convert checkstyle:checkstyle.xml raw:junit.json --to sarif --pretty -o merged.sarif ``` Anything on STDIN, anything on STDOUT, diagnostics on STDERR, so it drops into a shell pipeline: ```bash cat report.json | bin/console convert - --from raw --to emacs ``` And the same run described by a recipe: ```json { "name": "Nightly", "from": "phpcs", "to": "infomd", "output": "nightly.md", "inputs": [ { "type": "phpcs", "path": "phpcs.json" }, { "name": "backend", "basePath": "/srv/app/backend", "inputs": [ { "type": "checkstyle", "path": "backend/checkstyle.xml" } ] } ] } ``` ```bash bin/console convert --config recipe.json ``` As a library, the model is built directly and rendered in any format: ```php use Tuchsoft\IssueReporter\Report; use Tuchsoft\IssueReporter\Reporter; $report = (new Report('Nightly lint', '/srv/app'))->start(); $report->error('E101', 'Undefined variable $cart', 'src/Cart.php', 42, 9); $report->warning('W201', 'Line exceeds 120 characters', 'src/Cart.php', 3, 121); $report->tip('T301', 'Could use a guard clause', 'src/Cart.php', 88); $report->complete(); Reporter::printReport($report, 'infomd', 'report.md'); ``` `bin/console list-format` prints every format with its own options, and `list-transformer` does the same for the transformers. Every format option is available twice: unprefixed for the run, and prefixed with the format name when a single stage needs a different value. ## How it is tested The suite is six test suites (Format, Command, Recipe, Factory, Utils, Model) and 22 test classes on top of four shared base classes. The formats are not covered by a handful of hand-written examples: every parsable format is exercised in both directions against a generated option matrix, so the full run is 415,217 cases, just under five minutes on the machine that cut the release. That is what catches the boring failures, a writer that dies on an empty report, a parser that loses the base path, an escaping bug that only shows up in the Unicode column. The three readable renderers carry their own tests, including the escaping that keeps a message with a pipe or a tag from breaking the table or the HTML. ## What it does not do - It is not a linter. It never looks at your code: it reads what your tools found and reshapes it. There are no rules and no fixes in it. - Options are global to a run. The same option value applies to every stage; per-input and per-node overrides in the recipe are on the roadmap, not in 1.0. - `codeclimate` is not among the supported formats yet. - The `Report::error()`, `Report::warning()` and `Report::tip()` shorthands swap the `help` and `ref` arguments (the constructor takes them in the other order). Use `Report::issue()`, which is consistent, until this is fixed in the next release. - The SARIF and LSP writers emit the help and reference fields unconditionally, so those two formats cannot yet advertise the corresponding features, and the option to hide them has no effect there. ## Install ``` composer require tuchsoft/issue-reporter ``` Package: [`tuchsoft/issue-reporter`](https://packagist.org/packages/tuchsoft/issue-reporter) · Source: [github.com/TuchSoft/issue-reporter](https://github.com/TuchSoft/issue-reporter) · Licence: Apache-2.0 · PHP 8.0 or newer, with `ext-dom`, `ext-simplexml` and `ext-libxml`. The reference documentation lives in the `docs/` folder of the repository. > HTML version of this page: https://tuchsoft.com/guides-and-articles/issue-reporter-1-0-1/