CI and review

CI runs in your IDE

The VS Code extension and the JetBrains plugin list your branch's CI runs in the Saffron panel, show what a run found, and import a run's heals with one click: from a red build to an accepted repair without leaving the editor. Both call the same runner commands, saffron runs --json, saffron report --run <id> --json and saffron import --run <id> --json (§19), so GitHub Actions and Azure Pipelines work the same in both, and neither editor sees a token.

Before you start

  • The pipeline uploads a bundle. A run can be imported when its job ran saffron export and uploaded the result as an artifact named saffron-bundle* (§19, In CI). Importing a run without one says so.
  • The CI's own command-line tool, signed in, on your machine. The GitHub CLI for GitHub Actions (gh auth login); the Azure CLI with its azure-devops extension for Azure Pipelines (az extension add --name azure-devops, then az login, or AZURE_DEVOPS_EXT_PAT). The repository's host picks the service; a GitHub repository built by Azure Pipelines names it in the config (ci, §14).
  • A saffron-ai with saffron runs in the project. With an older one the list says to update it (npm i -D saffron-ai@latest).
  • JetBrains: a trusted project. In a project the IDE does not trust, the tab runs nothing and says so.

Where to find it

  • VS Code: the Saffron icon in the activity bar, view CI runs. A run's row has two inline actions, Import this run's proposals (the cloud icon) and Open the run in the browser. The view's title bar has Refresh CI runs, and the project picker when several projects are open. The view's heading names the project, the CI service and the branch it lists.
  • JetBrains: the Saffron tool window (right side), tab CI Runs. Its toolbar has Import Run, Open in Browser and Refresh. Import and Open act on the selected run, or on the run a selected row belongs to.

Reading the list

One row per run of the current branch, the 20 newest first:

CI #48   failure · 12 min ago · 2 proposals pending here
CI #47   success · 3 h ago
  • Name and number: the workflow (GitHub) or pipeline (Azure), and the run's number in it.
  • Outcome: success, failure, cancelled, partial (Azure's partially succeeded), or queued and in progress while it runs, with a matching icon.
  • When it was started.
  • Proposals pending here: how many proposals in your checkout came from this run and still wait for a decision.

Hover a row for the commit or pull request title, the attempt when the run was re-run, what started it (a push, a pull request, a schedule), and the branch and commit it tested. On Azure Pipelines a pull request build is listed under the branch it validates, and only this repository's builds are listed.

The list loads when the view first shows, when you switch projects and when you press Refresh. VS Code also reloads it when you switch branches; in JetBrains, press Refresh after a checkout. It does not reload as files change: each load asks the CI over the network.

When the list cannot be read, a single row says why:

Row Means What to do
CI tools not set up gh or az is not installed, or az lacks the azure-devops extension Install it; the row's text says how
Not signed in The tool is installed but not signed in gh auth login, or az login or AZURE_DEVOPS_EXT_PAT
Repository not recognized The tool cannot tell the repository, or the Azure DevOps organization and project Open a clone whose remote is the CI's repository, or set ci.organization and ci.project (§14)
CI runs unavailable Anything else, such as a saffron-ai without saffron runs The row's text says what

Viewing a run's results

Open a run's row (expand it in VS Code, select it in JetBrains) to see what it found without importing anything. The IDE runs saffron report --run <id> --json (§19) in the background, which you can cancel, and shows the results under the run:

  • a totals line (green, yellow, red);
  • one row per red or yellow scenario, with the failing step and the first line of its error; hover for what the agent changed;
  • "N proposals: M importable", and under it each proposal, with why it would not import (a scenario changed since the run, say);
  • Open Report, the run's report page in your browser, and Open Trace on a scenario that kept a trace: the replay, view only, with no Accept or Reject.

The results panel (saffron-ai 1.0.0 or later) shows the same run as one page: the totals, then each failed and pending-review scenario as a card with its screenshot (click it to see it whole), failing step, error and what the agent said, then what passed, then the proposals. Its buttons do what the rows do: Open trace, Open scenario (the feature file at that scenario), Open report, Open run page and Import; after an import the page loads again with what is importable now. In VS Code, Show Results (the graph icon on a run, or on its totals line) opens it in an editor tab. In JetBrains it is below the runs in the CI Runs tab, for the selected run. Viewing the run writes the page beside its report, and both editors show that one file (saffron report --run <id> --panel prints it too).

On GitHub the list also says what each run left before you open it: results and their size, summary only, results expired or no results; a run with nothing to view does not expand.

A run with no results says why in one row: still running, expired, or no bundle uploaded (put if: always() on the export and upload steps to keep every run's results). A run whose results are over the size limit asks before downloading (VS Code saffron.ciMaxDownloadMB, and the same setting in JetBrains, default 100 MB). Nothing in your checkout changes until you import; the download is kept in .saffron/ci/ and the import reuses it. Viewing needs saffron-ai 0.9.7 or later.

Importing a run

Import (VS Code: the cloud icon on the run; JetBrains: select the run, then Import Run) runs saffron import --run <id>. It downloads the run's Saffron bundles, every shard of a sharded run, and imports them into this checkout with every check of §19: nothing is written from a bundle that comes from another repository or is damaged, and a proposal that does not fit your files is not imported. VS Code shows the import in a notification you can cancel. Either IDE stops an import that takes over 15 minutes, and says so.

When it finishes, the run opens onto what happened:

  • Warnings first, such as a checkout at another commit than the one the run tested (with how far apart they are), or a pull request build that tested a merge commit.
  • Each proposal: imported (in VS Code, click it to open its diff), already pending here, already accepted here, or not imported with the reason, such as a scenario or recording that changed since the run.
  • No proposals in this run when it filed none. Its report, screenshots and traces are imported all the same.

A message counts what is ready for review; in VS Code, its Show proposals button opens the Proposals view. Importing the same run again changes nothing and says so. In VS Code, Refresh CI runs clears these results once the new list is in.

Reviewing what you imported

An imported proposal is an ordinary pending proposal that says where it came from:

  • Proposals marks it "from run 901". Hover it (VS Code) or select it (JetBrains) for the run and its link, and the branch, commit and shard it was made at. Read its narrative, proof-replay verdict and diff as for a heal of your own (§5).
  • Last run shows the imported run: the scenarios that failed or healed, with the step that failed. Open the screenshot of the page at that moment, or Open Replay to step through the run's trace (§18).

Accept them with Accept selected once you have read them. Accept all leaves imported proposals out and says how many it skipped; in a terminal, saffron accept --all --include-imported takes them. Accept checks each proposal's binding again, so one whose scenario or recording changed since the import is refused rather than accepted unseen. The new recordings are then an ordinary change in your working tree: commit and push them with the IDE's version control (VS Code's Source Control view, the JetBrains Commit window). Nothing is pushed for you, and your next local run replaces the imported one under Last run, as any run does.

With several projects open, the list is the shown project's, the same one the rest of the panel shows, and an import goes into the project it was started in, even if you switch while it runs.