@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 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 from the file when omitted; a folder is Allure), `--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. |
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|target/artifacts/checkout.png]]");
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, JUnit 5 (`allure-junit5`, with the AspectJ agent from Allure's setup; the results folder is
358
- `target/allure-results` unless `allure.results.directory` says otherwise):
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:…`). A file whose name starts with `_`
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
- Check that the output reaches the report: Gradle writes it only with `reports.junitXml.outputPerTestCase = true`,
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`: