Repository navigation
Added
- A CI-onboarding skill,
testsprite-ci.agent install(andsetup) now installs a third skill by default, which walks a coding agent through putting TestSprite on every pull request: how the repo deploys previews (platform-deployed →on: deployment_status, deployed in the workflow →on: pull_request, read from the repo andgh api …/deployments), which environment the gate signs in with,ci init githubplus the placeholder edit, theTESTSPRITE_API_KEYsecret, and proving the gate on one real, non-draft pull request — with the pitfalls that cost real time (draft and conflicting pull requests never run, shape A is per commit, cancelling the job does not stop the execution, a shell-exportedTESTSPRITE_API_URLbeats--profile).--skill testsprite-ciinstalls it alone;agent list/agent statusshow it. The docs gain complete shape-A and shape-B workflow examples. ci run: the CI gate, in one command.testsprite ci run --project <id> --env <name> [--target-url <url>]runs the project's tests, waits, and decides the exit code with CI defaults: failed/blocked tests exit 1, a timed-out run 7, missing test ids 4, nothing dispatched 5 (--allow-emptyaccepts an empty selection, never a refused batch), and everything that did not dispatch shares oneskippedcount that warns unless--fail-on-skipped. The JSON envelope,--summary-file, the GitHub job summary, annotations andGITHUB_OUTPUTstep outputs all come from one summary, written before the exit code. Opt-in JUnit (--report junit) carries the same rows, skipped tests included.- A CI run is one execution, like a GitHub App run.
ci runasks the backend to seed every selected test into one execution and pace dispatch itself (admission: 'all'), so a CI run is one row in the Portal instead of a first batch plus a rate-deferred retry. A backend that cannot honor this is refused with exit 7 (admission-not-honored), never silently cut to the per-key budget. Needs backend v0.21.0. - In a pull request,
ci runtests that pull request's preview the way the GitHub App does. Under GitHub Actions the pull request is read from the job (adeployment_statusevent is looked up by commit withGITHUB_TOKEN); with--env X --target-url Uthe run happens in a temporary clone of X at U namedgithub-pr-<N>, is stamped with the PR so the Portal links back to it, and the environment is released when the run finishes. A recorded-session (SSO) template is refused before charging. Draft pull requests and deployments with no open pull request are skipped with a::notice::, zero-valued step outputs and exit 0.ci runreads only the deployment's commit, never itsstateorenvironment— the workflow'sif:selects whichdeployment_statusevents to gate (see the documentation). Outside a pull request the run keepstest run's semantics. ci run --env <unknown>is refused before anything dispatches, listing the project's environment names — even with--allow-empty, so a typo can never be a permanently green check. The check fails closed: an environment list that cannot be read is that error (bad key → exit 3, backend down → 10, interrupted → the signal), never a run that dispatches unchecked; a backend with no environment surface for the project (V2, or an older route-less backend) leaves the name to the batch's own validation.--priorityacceptshigh,mediumandlow(any case) alongsidep0..p3, intest create,test update, plan files andcreate-batch. They map to p0, p1 and p2 (p3is treated as low), which is how the Portal's High/Medium/Low are stored.test plan putprotects structured steps.test getmarks steps that carry structured fields with*. A backend that refuses to drop structured fields (412structured_loss) now names the affected steps, and the new--forceoverrides it;--expected-step-countworks as before. Older backends ignore the extra field and keep working.test run --allon a backend project names the integration phase. One line says how many existing integration tests run after the wave (0.2 credits each) and whether a first run may generate new ones;--output jsoncarries the sameintegrationobject.test listshowsbackend/intin the TYPE column for assembled integration tests.- A run blocked because its stored code could not be replayed shows
replay refused (<reason>)in the text run card. - The CI job summary is the execution report — the GitHub App comment, in Actions. On a backend that serves execution reports,
ci runfetches the report for the batch's execution (polling up to--execution-report-timeout, default 60s) and writes its Markdown to the job summary: verdict, AI narrative, per-test error details, suggested fix prompts, screenshots, evaluation notes. The structured report rides along assummary.executionReport(JSON envelope and--summary-file), and the step outputsexecution-report-file/execution-report-markdown-filename its JSON and Markdown under$RUNNER_TEMPfor later steps. Older backends, or a report that is not ready in time, keep the results table. When the CLI's own verdict disagrees with the report (a run it could not read or that timed out, a refused test, a retry error), the summary opens with a one-line CI gate warning and appends the rows the report cannot carry, so it never reads "all passed" under a red check.--no-execution-reportkeeps the local table and reads nothing; no report is read after a run timed out; the report files are written0600; an interrupt while waiting for the report (request or retry sleep) falls back to the table instead of dropping the finished batch's summary and outputs, then exits with the signal's code (130/143). A red run whose failures the report also shows keeps the report as is — the CI gate warning appears only when the counts differ.
Changed
-
ci runtelemetry names its outcome. The one command-outcome event now carriesciRunOutcome(gated,skipped_draft,skipped_no_pr,refused_admission,refused_env,refused_preview_name,refused_loopback,refused_billing,refused_other,empty), the execution's UUID (executionId) when the gated batch names exactly one, andreportReady(the execution report reached the job summary, or the local table did). Before, a draft-PR skip and a green gate were the samesuccessevent, and the event could not be joined to the execution. Still no URLs, names or messages — see "Telemetry" in the documentation for the full field list. -
test run --all --waitno longer adopts another environment's in-flight run. When the backend refuses a case as already in flight, the batch used to attach to that run and report its verdict as its own, whatever environment or target URL it was testing — routine once a CI gate runs the whole project on every push in agithub-pr-<N>clone. The batch now applies the same gate the single run has had since 0.14.0: it reads the in-flight run, compares its environment id with the requested--env(or the project default) and its target with--target-url, and attaches only on a match; anything else stays a hard conflict, named on stderr with thetest waitcommand to follow it. Runs that record no environment (V2, older backends) still attach when no--envwas asked for. -
test run --allkeeps the skipped tests of a retried batch. When a rate-deferred retry answered with its ownskippedFrontend/skippedIntegrationbuckets, only the first batch's were reported; the retry's are now folded into the sameskippedcount, output, summary and JUnit rows. The exit code is unchanged (skipped tests warn unless--fail-on-skipped). -
ci init githubwrites a PR gate that tests the pull request's preview, calling the CLI directly. The generated workflow no longer usesTestSprite/testsprite-actionor tests the project's configured environment onpush/pull_request. It runstestsprite ci run --project <id> --env <name> --target-url <preview>after one placeholder step that you replace with where the preview URL comes from: delete it and switch the trigger todeployment_statuswhen your platform deploys every PR, or put your deploy commands in it. The workflow installs@testsprite/testsprite-cli@latest, skips fork and draft PRs, ignores production deployments, passesGITHUB_TOKEN, and always uploads the summary file. New--env <name>picks the environment whose sign-in each PR run uses; an unknown name is refused, an SSO (recorded-session) environment gets a warning because it cannot sign in on a preview, and without it the project's default is written by name.--timeoutis written only when given.--pathmust be a.yml/.yamlfile directly under.github/workflows/.ci initwarns when another workflow already runs TestSprite. Removed:--filter(add it to theci runline yourself). JSON summary: addsenvironmentandotherTestspriteWorkflows,timeoutSecondsisnullwhen not given; dropsactionandfilter. Requires theci runcommand. The generated gate passes--fail-on-skipped; its concurrency group is declared on the job and keyed on the pull request (shape B) or the commit (shape A — Vercel's deploymentrefis the commit SHA), so a new pull-request push cancels the previous job (shape B only) while dropped deployment events never cancel a running gate; cancelling only stops the job's CLI, the run it started keeps executing.--forcekeeps the previous file as.bakand names it asbackupPath, since the preview step is hand-edited. The job is namedtestsprite-tests, which is the name to require in branch protection; GitHub matches required status checks by job name across all workflows, so it must not collide with your owntestore2ejob. -
A new project no longer dead-ends. Someone who creates a project without a coding agent was never told that TestSprite can propose the first tests:
project createprinted the record and stopped,setup's next steps said to write a test by hand, and an empty project answeredtest listwith "No tests." andtest run --allwith a bare exit 5. Each of those moments now names the way in —test plan generate --project <id>thentest plan accept(withproject docs uploadfirst for a backend project), andtest create --plan-templatefor anyone who prefers to write the plan themselves. The hints print only in text mode, on stderr, so--output jsonoutput is unchanged, including its error envelope. Printing a hint runs and charges nothing; generating a plan uses credits.test run --all --local <port>on an empty project is pointed at the hand-written plan instead, since generation cannot reach an app on your machine, and the suggested run command keeps the target that run used (--env <name>for a saved local environment,--target-url, or--local <port>with a non-default--local-host), so it does not fall back to the project's default environment;project create --localgets no second hint: its record's own next steps now start fromtest create --plan-templateand setprojectIdin the plan file instead of passing--project, which--plan-fromignores. The always-ontestsprite-onboardskill description and its codex one-liner now say the suite can be generated, matching the skill body.
Deprecated
ci doctorandci connectare hidden and deprecated. Platform checks and linking belong to the coding agent, not to CLI commands: thetestsprite-ciskill reads the same deployment history (gh api repos/<owner>/<repo>/deployments) and runs the platform's own CLI (npx vercel link --project <name> --non-interactive,npx vercel git connect --non-interactive), andci doctor's name-based preview check misjudged custom environment names. Both commands still run with the same behaviour and exit codes; each run prints one stderr line naming the equivalent commands. They are removed in the release after this one, together withsrc/lib/ci-linkage.ts.
Fixed
- Replacing the credentials file retries a transient Windows lock. On Windows, renaming the temp file over
~/.testsprite/credentialscan fail withEPERM,EBUSYorEACCESwhile another program briefly holds the file open; the CLI now retries for up to two seconds before failing. Persistent errors, other error codes and non-Windows hosts behave as before. - Reading the credentials file no longer fails with
EPERMon Windows. Hardening the file's permissions removed ACL inheritance in a way that could lock the owner out of their own credentials, so every later read failed. Inheritance is restored,doctorrepairs a file already locked that way, and the connectivity and tunnel checks no longer re-read an unreadable file. Community fix by @aythin and @jangjos-128 (#356). - Replay routing records with
nullfields are accepted. A normal replay reportsnullreason and caveat, which the response schema rejected.plan putalso no longer reads the test before writing, so write-only API keys keep working;--expected-step-countbehaves as before.