Skip to content

CLI reference

pr-baseline <command> [options]

Commands: refresh-pr-status, refresh-pr-statuses, move-baseline, report. The repository, token, API, GraphQL and server URLs have environment fallbacks; every other option is a flag, and the action maps its inputs onto them. A flag always wins over the environment.

Option Env Default Meaning
--repo <owner/name> GITHUB_REPOSITORY required Repository.
--token <token> GITHUB_TOKEN none Token; required for everything except usage and refresh-pr-status --offline.
--api-url <url> GITHUB_API_URL https://api.github.com REST root; set it for GitHub Enterprise Server (https://HOST/api/v3).
--graphql-url <url> GITHUB_GRAPHQL_URL beside --api-url GraphQL endpoint, used as given apart from trailing slashes; derived as https://HOST/api/graphql from a GHES REST root when unset.
--server-url <url> GITHUB_SERVER_URL host behind --api-url The git server the token may be sent to: an http(s) origin is used only when it is this server’s exact owner/name; ssh and file remotes are matched by path and never receive the token.
--base <branch> repository default branch The base branch one instance serves.
--baselines <json> one default baseline JSON array of { name, label?, scope?, markers? }; @path reads a file. Cannot be combined with the shorthand.
--name <name> pr-baseline Shorthand: the single baseline’s name, under refs/baselines/.
--label <name> Require PR update Shorthand: the single baseline’s label.
--markers <pattern> none Shorthand: auto-move patterns, repeatable.
--baseline <name> all move-baseline only: restrict to one configured baseline; an unknown name is an error.
--context <name> PR baseline Status context.
--description-pass <text> Contains the required {base} changes. {base} and {baselines} placeholders.
--description-fail <text> Merge or rebase {base} to include: {baselines} Lists two missing baselines and counts the rest.
--description-not-applicable <text> Baseline applies to {base} only. Used only with --other-bases pass.
--target-url <url> compare view Link on every status, for example the PR author page. Without it a failing status links to the commits the base branch has that the head lacks; a pass has no link.
--other-bases skip|pass skip PRs against another branch: skip them, or write a not-applicable pass.
--creator <login> resolved Login the token writes statuses as. Required for a GitHub App token and for GITHUB_TOKEN used from the CLI (github-actions[bot]).
--ancestry auto|git|api auto Ancestry source. auto uses git when --git-dir (or the working directory) is a full-history clone whose origin serves the repository over https or a local path, otherwise the API. git fails without such a clone. api also keeps move-baseline off git entirely, so its writes go through the refs API.
--git-dir <path> cwd Local clone for git ancestry and ref resolution; a treeless clone (--filter=tree:0) is enough, but it must carry full history (a shallow clone is never used) and git must be 2.45 or newer.
--offline off refresh-pr-status only, and local only: no token, no --pr, no status write, no fetch; needs git 2.45 or newer; the commit must resolve in the clone, the base is refs/remotes/origin/<base>, and the baseline refs are read from refs/baselines/ in the clone (fetch them with +refs/baselines/*:refs/baselines/* first): an absent one counts as absent, one that is not a commit is an error. Rejected for every other command.
--max-writes-per-run <n> 450 Stop the refresh after this many status writes; a positive integer.
--max-writes-per-minute <n> 60 Pace status writes; a positive integer per minute.
--dry-run off Log every intended write and baseline move instead of making it.
--json off Print the command’s result object as JSON on stdout; logs stay on stderr.

Descriptions are capped by GitHub at 140 characters; a long template or long baseline names are truncated deterministically with an ellipsis, never rejected.

Options listed under a command are rejected with any other command, so a misplaced flag is an error rather than silently ignored.

Evaluates one commit against every configured baseline. The commit is the positional SHA or ref, --pr <n> for a pull request’s head, or HEAD of the local repository. A bare ref is resolved locally first, then through the API.

--report writes the status; --no-report suppresses it. The default is on for --pr, which names a commit GitHub already knows about, and off for any commit given directly, which is a local question. The action passes report explicitly for event SHAs. Before posting, the baseline refs and the base head are re-read together and the verdict recomputed if either moved.

A PR targeting another branch is skipped with a notice, or stamped with the not-applicable pass under --other-bases pass. When any present baseline is not on the base branch, the commit receives the misconfiguration pass whatever its ancestry, so the operator error is visible on every PR without blocking anyone.

Exit codes: 0 pass (including not-applicable and misconfigured), 1 fail, 2 error.

Lists open PRs against the base branch, computes the verdict of the ones --scope selects, and writes only the statuses that differ in state, description, target URL or creator. Writes are paced by --max-writes-per-minute, capped by --max-writes-per-run, and stop when the primary rate limit is within its reserve.

--scope decides which open PRs the run covers:

Scope PRs Why
corrections (default) Status is green A baseline only moves forward, so a green PR is the only one that can have turned red, and the only kind whose missing write can let a wrong merge through.
unstamped No status on the context The adoption backfill. A PR with no status is already blocked, so this only adds the explanation; run it throttled.
all Every in-scope open PR The full sweep. Owed after any change to refs/baselines/ made outside move-baseline, and after any change to the baselines, scope or context configuration.

A PR whose status is error or pending is in neither named bucket and is reached only by all. That is safe, since a required non-success status blocks a merge exactly as a failure does. A forced or non-fast-forward move-baseline and a baseline off the base branch both force all whatever was asked, because either can turn a red PR green. A custom reporter forces it too: the PR listing carries commit statuses the reporter does not own, so bucketing from it would be a guess. Scoping a custom-reporter run explicitly is an error, raised before a move writes anything rather than after.

The summary reports scope, openPulls (the first listing, before the scope and before any PR closed), selected, excluded, written, skipped (already current), cosmetic (differed only in description or link, so no write was spent), closed (gone since listing), deferred (head still moving), outOfScope (left the base branch or became a draft meanwhile), failed, remaining (selected PRs the run never reached) and incomplete with a reason: rate-limit, write-cap, primary-budget, deferred or failed. Any deferred or failed marks the refresh incomplete. paused is an incomplete run that stopped on rate-limit, write-cap or primary-budget having written something, with nothing failed and nothing deferred, which the next run at the same scope continues on its own. closed and deferred only occur with the git adapter, which fetches the selected heads and notices a PR that closed or moved since the listing; the API adapter writes to the listed head.

A permission or authentication failure on the first write stops the refresh, since it would repeat for every PR. A commit that already carries 1,000 statuses for the context fails for that PR only.

Before evaluating anything, the refresh resolves the status creator, which is exit 2 when it fails, and checks that every present baseline is an ancestor of the base branch head. A baseline that is not gets a warning and the misconfiguration pass for every PR, since such a baseline can never be satisfied by merging and a refusal would only leave stale statuses behind.

Exit codes: 0 complete or paused, 1 incomplete and not paused, 2 error.

For each selected baseline decides whether it should move, and to where:

  • --force moves by intent alone and seeds an absent baseline. It is never a ref force.
  • Otherwise a merged PR against the base carrying the baseline’s label moves it when the merge commit is not the current baseline, descends from it, and is an ancestor of the target. Every merged PR with the label is scanned, newest first, with no date cutoff.
  • Otherwise a change to one of the baseline’s markers between the current baseline and the target moves it. When the compare API returns 300 files the answer is indeterminate; the tool warns and does not move automatically.

--to <sha> sets the target instead of the base branch head; it must be reachable from the base branch. The target must descend from the current baseline, unless that baseline is no longer on the base branch, where a forced move is the documented repair. The ref is written with git push --force-with-lease, tried first from the clone with git ancestry, then from a temporary repository, so a concurrent move is refused by the server; when both fail, and always with --ancestry api, the refs API is used and the ref re-read. Each completed move reports via (git or api); a dry run reports none. A lost race re-evaluates the decision once from the ref’s new commit; a rejected write with the ref unmoved is terminal.

--refresh-pr-statuses runs a refresh afterwards, also when nothing moved, so a re-dispatch is a safe retry. In a dry run the refresh is evaluated against the intended, unwritten baseline positions.

The refresh that follows always runs from the CLI, whether or not a baseline moved; only the action suppresses it, and only for the events that fire on every base-branch push.

Exit codes: 0, 1 when the following refresh is incomplete and not paused, 2 error.

Read-only. Prints the base head, the open PR count, and for every baseline its commit, whether that commit is on the base branch, and how many open PRs it binds.

It also breaks the open PRs down by the status they carry on the context: passing, failing, other (error or pending, which blocks a merge and which only --scope all reaches) and unstamped. All four come from the listing, so they cost nothing and are reported whatever the adapter. This is the adoption signal: require the context once unstamped and other are near zero, and it is how a --scope unstamped backfill is watched to completion.

With the git adapter, every baseline on the base branch and a resolvable creator, it adds a verdict per PR: current, stale (differing materially) and cosmetic (differing only in description or link, which the default and unstamped scopes leave alone on purpose, so counting it as stale would mean the number could never reach zero; --scope all does write it). Any of those three conditions failing leaves all three counts out.

Exit codes: 0, 2 when a baseline is not on the base branch (the report is still printed) or on an error.

All fatal before any request: valid JSON array with known fields only, at least one entry, names that pass git check-ref-format under refs/baselines/, unique names, labels non-empty after trimming, scope and markers non-empty arrays of non-empty patterns. An entry without label and without markers moves only by --force. The default label applies only to the shorthand form.