@plune-ai/cli 0.30.2 → 0.32.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +71 -10
- package/dist/cli.cjs +279 -175
- package/dist/index.cjs +90 -66
- package/dist/index.d.cts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +90 -66
- package/dist/reporter-core.cjs +31 -4
- package/dist/reporter-core.d.cts +13 -0
- package/dist/reporter-core.d.ts +13 -0
- package/dist/reporter-core.js +31 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -122,13 +122,13 @@ the last resort, used only when `PLUNE_TOKEN` is set nowhere else. Nothing write
|
|
|
122
122
|
| `plune login` | Save a [Plune platform](https://plune.ai/platform) API token so `sync` and `ingest` can reach it. The token is **checked against the API before it is saved**, so a wrong one fails here rather than two commands later. Get one at `https://beta.plune.ai` → Account → API tokens. Flags: `--token <token>` (omit to paste it or pipe it via stdin), `--skip-verify` (save without checking, for offline setup). In CI, skip this step: every platform command reads `PLUNE_TOKEN` from the environment first, and the saved login only when it is not set. |
|
|
123
123
|
| `plune logout` | Remove the saved token. |
|
|
124
124
|
| `plune sync` | Upload the latest local run to the platform. Flags: `--file <path>` to send a specific run JSON, `--fail-on-failures` to read the run's summary back once after the upload and exit with [the gate](#a-release-gate---fail-on-failures)'s code. Each upload carries an `Idempotency-Key` (SHA-256 of the body), so sending the same run again returns the same run rather than creating a second one. Against a platform with `POST /v1/jobs` the upload is also reported as a job (kind `sync`, counting the run's rows) that ends completed, or failed with the error text if the sync fails; an older platform without the route is not told, and a job report never fails the sync: when the sync goes through, one the platform did not take is said in one line on stderr. |
|
|
125
|
-
| `plune run import <file>` | Turn a **JUnit XML** or **Playwright JSON** report, or an **Allure `allure-results` folder**, into a run in Plune. Needs no provider key — nothing is generated. Flags: `--format junit\|playwright-json\|allure` (detected
|
|
125
|
+
| `plune run import <file \| folder>` | Turn a **JUnit XML** or **Playwright JSON** report, a **folder of JUnit XML files** (Maven Surefire's `target/surefire-reports`, Gradle's `build/test-results/test`), or an **Allure `allure-results` folder**, into a run in Plune. Needs no provider key — nothing is generated. Flags: `--format junit\|playwright-json\|allure` (detected when omitted: a folder with a `*-result.json` is Allure, any other folder is read as the JUnit `*.xml` files in it), `--name <text>` to call the run something other than the [folder-based default](#what-the-run-is-called), `--key <externalKey>` to land several reports in one run (with `PLUNE_SHARED_RUN=1` — see below), `--create` to offer unmatched tests to the review queue, `--fail-on-missing-attachments` to exit 1 when a file a JUnit report names with `[[ATTACHMENT\|path]]`, or an Allure result names as a `source`, is not there (the results are sent either way), `--upload-concurrency <n>` for files uploaded at once ([1 to 32, default 16](#many-screenshots-upload-concurrency-and-retries)), `--fail-on-failures` to exit with [the gate](#a-release-gate---fail-on-failures)'s code on the summary the platform froze when this import finished the run. |
|
|
126
126
|
| `plune run start` | Open a platform run — or join the one already carrying `--key` — and print its id. Flags: `--key <externalKey>` (generated when absent), `--name <text>` to call the run something other than the [default](#what-the-run-is-called), `--json` for one machine-readable line. |
|
|
127
127
|
| `plune run finish <id>` | Close a platform run. This is what the reporter tells you to do for a run it had to leave open. Flags: `--terminate` to record it as cut short, `--reason <text>`, `--fail-on-failures` to exit with [the gate](#a-release-gate---fail-on-failures)'s code on the summary the platform froze. |
|
|
128
128
|
| `plune run exec -- <command>` | Open a run, run the command inside it, close the run — and exit with whatever the command returned. Sets `PLUNE_SHARED_RUN` for you, so anything reporting inside joins that run. Flags: `--key <externalKey>`, `--name <text>` (as on `run start`), `--fail-on-failures` to exit with [the gate](#a-release-gate---fail-on-failures)'s code instead — or with the command's own when no result reached the run. |
|
|
129
129
|
| `plune run delete <id>` | Delete a run and everything it produced — its results and the review-queue entries it raised. Approved test cases and the audit log stay. **Recoverable for 30 days** (an owner of the project can put it back from Settings → Bin), then gone for good. No prompt: it is your data, and this command belongs in scripts. |
|
|
130
130
|
| `plune run report` | Replay `.plune/pending-results.jsonl` — send what the reporter could not. The lines of one reporter run go back as one run, with the commit and branch the reporter recorded. Once every result has gone the file is renamed to `pending-results.<time>.sent.jsonl`; if anything did not go, it stays as it was. Flags: `--file <path>`. |
|
|
131
|
-
| `plune ingest [dir]` | Record a [Cairn](https://github.com/plune-ai/cairn) run in Plune. Omit `[dir]` for the newest run under `./runs`, or name the directory holding `report.json`. Generated cases arrive as **review proposals** — nothing is created until a person approves it. |
|
|
131
|
+
| `plune ingest [dir]` | Record a [Cairn](https://github.com/plune-ai/cairn) run in Plune. Omit `[dir]` for the newest run under `./runs`, or name the directory holding `report.json`. Generated cases arrive as **review proposals** — nothing is created until a person approves it. Against a platform with `POST /v1/jobs` the ingest is also reported as a job (kind `ingest`, counting the cases sent, linked to the run it landed in) that ends completed, or failed with the error text if the ingest fails; as with `sync`, an older platform is not told and a job report never fails the ingest or changes its exit code. |
|
|
132
132
|
| `plune pull [file]` | Write the project's test cases as **one Markdown document** — Testomat's classical format, plus Plune's own columns — to `plune/cases.md` (or `[file]`). Refuses to overwrite a file git sees as modified; `--force` overrides, `--suite <id>` takes one suite or folder and what is under it. |
|
|
133
133
|
| `plune push [file] [--dry-run]` | Send the document back. Cases are matched by `id`; a block without one becomes a draft; an unknown id is refused by line; **nothing is deleted**. Prints the report — created, updated, unchanged, refused, warnings — and with `--dry-run` writes nothing. Exit `4` when anything was refused. |
|
|
134
134
|
| `plune requirements import <file.md>` | Import requirements from a **Markdown file** (an SRS, a PRD, a page exported from a wiki). With no mapping flags it lists the tables and sections the file has and exits `0`; with `--table` or `--sections` it is a **dry run** that writes nothing until you add `--yes`. See [Requirements from a Markdown file](#requirements-from-a-markdown-file). Needs a Plune platform that serves `POST /v1/projects/:id/requirements/import` (plune-ai/plune#1621). |
|
|
@@ -239,6 +239,7 @@ costs nothing beyond a Plune token.
|
|
|
239
239
|
```bash
|
|
240
240
|
plune login # once, on your machine; in CI export PLUNE_TOKEN instead
|
|
241
241
|
plune run import ./junit.xml # Jest, Vitest, pytest, PHPUnit, Surefire, Cypress, …
|
|
242
|
+
plune run import target/surefire-reports # or a folder of JUnit files: Maven, Gradle — see Java below
|
|
242
243
|
plune run import ./playwright.json # or Playwright's own JSON report
|
|
243
244
|
plune run import ./allure-results # or the folder an Allure adapter wrote — see below
|
|
244
245
|
```
|
|
@@ -301,13 +302,15 @@ pytest --junitxml=report.xml -o junit_logging=system-out
|
|
|
301
302
|
plune run import report.xml
|
|
302
303
|
```
|
|
303
304
|
|
|
304
|
-
Java, JUnit 5 (Maven Surefire writes the test's output into its testcase
|
|
305
|
+
Java, JUnit 5 (Maven Surefire writes the test's output into its testcase; Gradle only with
|
|
306
|
+
`reports.junitXml.outputPerTestCase = true`). The path counts from the folder the XML file is in
|
|
307
|
+
(`target/surefire-reports`, `build/test-results/test`), so the file has to be below it:
|
|
305
308
|
|
|
306
309
|
```java
|
|
307
310
|
@Test
|
|
308
311
|
void checkout() {
|
|
309
|
-
// ...
|
|
310
|
-
System.out.println("[[ATTACHMENT|
|
|
312
|
+
// ... save the screenshot as target/surefire-reports/artifacts/checkout.png
|
|
313
|
+
System.out.println("[[ATTACHMENT|artifacts/checkout.png]]");
|
|
311
314
|
}
|
|
312
315
|
```
|
|
313
316
|
|
|
@@ -330,7 +333,7 @@ For Jest, use Allure below.
|
|
|
330
333
|
|
|
331
334
|
Every Allure adapter (pytest, JUnit 5, TestNG, Playwright, Cypress, Jest, Vitest, WebdriverIO, .NET) writes
|
|
332
335
|
the same folder: a `*-result.json` per test, a `*-container.json` per suite, and the files the tests attached.
|
|
333
|
-
Point `plune run import` at the folder (a folder is read as Allure, no flag needed). Each test arrives with its
|
|
336
|
+
Point `plune run import` at the folder (a folder with a `*-result.json` in it is read as Allure, no flag needed). Each test arrives with its
|
|
334
337
|
name, its status as Allure shows it (`passed`, `failed`, `broken`, `skipped`), its time, the failure message and
|
|
335
338
|
trace, and its steps; a test run again (same `historyId`) is one test with attempts, the last one counting.
|
|
336
339
|
The files come from the test, from its steps and from its fixtures (`befores`, `afters`), each with the
|
|
@@ -354,11 +357,36 @@ def test_checkout(page):
|
|
|
354
357
|
allure.attach.file("artifacts/checkout.png", name="checkout", attachment_type=allure.attachment_type.PNG)
|
|
355
358
|
```
|
|
356
359
|
|
|
357
|
-
Java
|
|
358
|
-
|
|
360
|
+
Java. Maven Surefire and Gradle write JUnit XML on their own, a `TEST-<class>.xml` per class, so a Java suite
|
|
361
|
+
needs no Allure: point the import at the folder.
|
|
359
362
|
|
|
360
363
|
```bash
|
|
361
364
|
mvn test
|
|
365
|
+
plune run import target/surefire-reports
|
|
366
|
+
|
|
367
|
+
./gradlew test
|
|
368
|
+
plune run import build/test-results/test
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
Every `*.xml` in the folder that is a JUnit report is read, in the order of the file names, and together they make
|
|
372
|
+
one run. The folder's other files and its subfolders (Gradle's `binary/`) are not opened; an `*.xml` that is not a
|
|
373
|
+
JUnit report is skipped with a line in the output. Each test arrives with its class and name as the key
|
|
374
|
+
(`cart.CartTest#addsAnItem` from Surefire; Gradle keeps the brackets, `cart.CartTest#addsAnItem()`), its status
|
|
375
|
+
(`pass`, `failure`, `error`, `skipped`), the failure's message, type and stack trace, and its duration when the suite
|
|
376
|
+
has a `timestamp`. Gradle writes one; Surefire's report has none, so Maven tests arrive without a duration for now
|
|
377
|
+
(plune-ai/plune#2310). A file reaches a test only
|
|
378
|
+
through a `[[ATTACHMENT|path]]` line in its own output, [as above](#files-from-a-junit-report), the path counted from
|
|
379
|
+
the folder the XML file is in. Gradle puts that output in the test's testcase only with
|
|
380
|
+
`reports.junitXml.outputPerTestCase = true` (by default it writes it once per suite).
|
|
381
|
+
|
|
382
|
+
Allure adds the steps, and files attached without printing a line. The JUnit 5 adapter is
|
|
383
|
+
`io.qameta.allure:allure-jupiter` (from 2.35.1, `allure-junit5` is only a relocation to it, with no jar), with the
|
|
384
|
+
AspectJ agent from Allure's setup. It writes `allure-results` in the working folder; to have it in the build's
|
|
385
|
+
output, set `allure.results.directory` (in `src/test/resources/allure.properties`, or as a system property) to
|
|
386
|
+
`target/allure-results` for Maven or `build/allure-results` for Gradle:
|
|
387
|
+
|
|
388
|
+
```bash
|
|
389
|
+
mvn test # with allure.results.directory=target/allure-results
|
|
362
390
|
plune run import target/allure-results
|
|
363
391
|
```
|
|
364
392
|
|
|
@@ -372,11 +400,13 @@ void checkout() {
|
|
|
372
400
|
Jest has no per-test output in JUnit; `allure-jest` gives it one (`allure.attachment(...)` in a test or a step).
|
|
373
401
|
Tests are matched to Plune cases by the same key as a JUnit report's, `classname#name`, where the adapter's
|
|
374
402
|
names allow it (pytest, JUnit 5, Playwright); for Vitest, Jest and Cypress the key is the runner, the file and the
|
|
375
|
-
test's full name (`vt:test/cart.test.js#cart adds an item`, `jest:…`, `cy:…`).
|
|
403
|
+
test's full name (`vt:test/cart.test.js#cart adds an item`, `jest:…`, `cy:…`). For JUnit 5 the name carries the
|
|
404
|
+
method's parentheses in Allure and in Gradle's JUnit XML (`shop.CartTest#coupon()`) but not in Surefire's
|
|
405
|
+
(`shop.CartTest#coupon`), so a project that moves between Allure and Surefire meets its cases under other keys. A file whose name starts with `_`
|
|
376
406
|
is not sent: the core hides it as Playwright's own reports do, and Allure has no such convention, so name
|
|
377
407
|
attachments without a leading underscore.
|
|
378
408
|
|
|
379
|
-
|
|
409
|
+
For a JUnit report, check that the output reaches the report: Gradle writes it only with `reports.junitXml.outputPerTestCase = true`,
|
|
380
410
|
and Maven Surefire moves it out of the XML when `redirectTestOutputToFile` is `true`. As in the Playwright
|
|
381
411
|
reporter, a file whose name starts with an underscore is skipped, and a file several tests name is uploaded once per test.
|
|
382
412
|
|
|
@@ -424,6 +454,37 @@ The shard that is the Nth also prints `plune: run closed` just above that line,
|
|
|
424
454
|
and leaves the run open, as `PLUNE_SHARED_RUN` does: close it with `plune run finish`.
|
|
425
455
|
- With `--fail-on-failures`, the shard that closes the run gates on its summary; the others have no verdict yet.
|
|
426
456
|
|
|
457
|
+
#### A combination per job of a matrix: `PLUNE_CONFIGURATION`
|
|
458
|
+
|
|
459
|
+
The jobs of a matrix of browsers and systems report into one run, each under its own combination of
|
|
460
|
+
configuration values (plune-ai/plune#1251):
|
|
461
|
+
|
|
462
|
+
```yaml
|
|
463
|
+
strategy:
|
|
464
|
+
matrix:
|
|
465
|
+
browser: [Chrome, Firefox]
|
|
466
|
+
os: [Windows, macOS]
|
|
467
|
+
env:
|
|
468
|
+
PLUNE_RUN: ${{ github.run_id }}-${{ github.run_attempt }}
|
|
469
|
+
PLUNE_SHARED_RUN: 1
|
|
470
|
+
PLUNE_CONFIGURATION: "Browser=${{ matrix.browser }};Operating system=${{ matrix.os }}"
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
`PLUNE_CONFIGURATION` is `Group=Value` pairs split by `;`, with the names of the groups and values as in
|
|
474
|
+
Settings → Configurations. Case does not matter, spaces around a name or a value are dropped, and so is an
|
|
475
|
+
empty pair (`;;`, a `;` at the end); a value may hold `=`, since a pair splits at its first one. Every results
|
|
476
|
+
batch of `plune run import` and of the Playwright reporter carries it, and Plune files the results under that
|
|
477
|
+
combination of the run: one the run already has (a run launched from the dashboard with configurations, joined
|
|
478
|
+
by its key), or one it adds. A value that is not in Settings is taken as sent, marked "not in the list". Unset
|
|
479
|
+
or blank, the batch is sent as before. The run is closed once at the end, as above.
|
|
480
|
+
|
|
481
|
+
- A pair without `=`, without a group or without a value, or one group named twice, is a configuration error:
|
|
482
|
+
nothing is sent and the command fails.
|
|
483
|
+
- Every job of a run names the same groups. Plune refuses with 422 a batch that names other groups, or one that
|
|
484
|
+
would take the run past its limits (25 combinations, 40 000 results to expect); its message is printed as it
|
|
485
|
+
came, and the batch goes to the fallback file like any other refused batch.
|
|
486
|
+
- The fallback file keeps the combination, and `plune run report` sends the batch back into it.
|
|
487
|
+
|
|
427
488
|
### A time limit for the import
|
|
428
489
|
|
|
429
490
|
The whole `plune run import` stops after 600 seconds by default, so a platform that stops answering cannot hold a CI job until its own timeout kills it. Raise it for a very large report, or turn it off with `0`:
|