Report LocalCI results to GitHub

This guide adds a LocalCI status to a commit so pull requests containing that commit show whether your local checks passed. Check output remains in your terminal.

1. Install and configure LocalCI

Follow the installation and first-run instructions. Before enabling GitHub reporting, make sure your configured check command passes with localci --dry-run.

You need a GitHub credential to post the status. No GitTrove key is involved at run time: the key you used to install LocalCI authenticates the package download only.

2. Give LocalCI access to GitHub

If you use the GitHub CLI, sign in:

gh auth login --hostname github.com

LocalCI retrieves the token from gh without saving it in your checkout. Alternatively, set GITHUB_TOKEN using your secret manager. For example:

export GITHUB_TOKEN="$(gopass show -o github/localci)"

Create and store that token first. A fine-grained token needs Commit statuses: write access to the selected repository. A classic token can use the narrower repo:status scope. See GitHub's commit-status API permissions. Organization policies may also require token approval. GITHUB_TOKEN takes precedence over gh when both are available.

3. Enable reporting and run

Add github = true to the existing table in the repository's pyproject.toml. For example, a project using npm tests would have:

[tool.localci]
command = ["npm", "test"]
github = true
github_context = "LocalCI"

Keep your project's actual check command. Do not add a second [tool.localci] table if one already exists.

Commit the configuration and all changes you want checked, then push your branch and run:

git push -u origin your-branch
localci

Push first: GitHub must already know the commit before it can accept a status. LocalCI requires a clean working tree for GitHub reporting. It will also refuse to publish if the checks leave uncommitted changes or HEAD moves during the run. Use localci --no-github to check uncommitted work without posting a status.

LocalCI: acme/widget at 0632064b651f
LocalCI: running npm test
...
LocalCI: reported success to GitHub as 'LocalCI'

Open the pull request to see the status, or query it directly, replacing OWNER/NAME with your repository:

gh api "repos/OWNER/NAME/commits/$(git rev-parse HEAD)/statuses" \
  --jq '.[] | {context, state, description}'

A failed check posts a failure status. A rebase or amend creates a new commit that needs a new run. By default LocalCI posts only the final result. To show the run while it is happening, add github_pending = true:

[tool.localci]
command = ["npm", "test"]
github = true
github_pending = true

LocalCI then posts pending before the checks start, and a run that cannot start or times out closes it with an error instead of leaving it waiting. A run that is interrupted with Ctrl-C publishes nothing, which can leave a pending status until another run replaces it. Pending is off by default because a required status that is never replaced blocks the pull request. Asking for it with reporting off is a configuration error.

Stopping a check that hangs

Set a deadline so a check that waits forever ends with a verdict:

[tool.localci]
command = ["npm", "test"]
timeout_seconds = 900

--timeout SECONDS overrides the setting for one run, and --timeout 0 removes the deadline. A timed-out run reports timed out after 900s, exits 1, and never posts success. It attempts an error status only when it had posted pending.

Require the result before merging

Configure your GitHub branch protection or ruleset to require the status named LocalCI, or the name you set in github_context. Run LocalCI at least once so the status is available to select. Availability depends on your GitHub plan and repository visibility; see GitHub's protected branch documentation.

A local status is a developer-reported result. Anyone permitted to post that status can affect the gate. Keep independent CI if your review policy requires verification outside a developer's machine.

GitHub Enterprise

Set the API URL and sign in to that host:

[tool.localci]
command = ["make", "check"]
github = true
github_url = "https://github.example/api/v3"
gh auth login --hostname github.example

LocalCI asks gh for the configured host's credential. An explicit GITHUB_TOKEN still wins, so ensure it belongs to the correct host. Use trusted HTTPS endpoints because the token is sent to the configured API.

Troubleshooting

Message or symptom What to do
Missing GitHub credential Sign in with gh for the correct host, or set GITHUB_TOKEN.
Clean working tree required Commit or stash changes, including untracked files, or use --no-github.
Working tree or HEAD changed during checks Inspect the changes, commit the intended ones, and run again. Ignore disposable artifacts; use formatter check modes.
HTTP 401 Replace the expired or invalid token.
HTTP 403 Check token permissions, organization policies, and API rate limits.
HTTP 404 Check the repository identifier and that the token can access it. Use --repository owner/name if needed.
HTTP 422 mentioning the SHA Push the current commit before running again.
Exit 3 Read the error: the GitHub status failed, or the checkout changed while checks ran.
Status stuck on pending A run published pending and then died, or was interrupted. Run LocalCI again on the same commit to replace it.
Check never finishes Set timeout_seconds, or pass --timeout SECONDS, so the run ends with a clear message instead of holding the terminal.
No status on the pull request Confirm the PR head matches git rev-parse HEAD and that the run used the right repository and context.

--github enables reporting for one run; --no-github disables it, which is how a dirty working tree is checked locally. --github-pending and --no-github-pending do the same for the pending status. --dry-run prints the status payload without contacting GitHub or looking up a token, and neither a dry run nor a run with reporting off publishes a pending status.

Automated runs

LocalCI can run in an existing CI job after that job has installed LocalCI and prepared the project's environment. The job needs the GitTrove install key to download LocalCI from the private index, and a GitHub job token with statuses: write. Check out the PR's head commit when you want its status, and run only trusted code with those credentials.

Fork pull requests normally do not receive repository secrets or a writable job token. Do not bypass that boundary to run untrusted code with secrets. Use your normal trusted review and CI process for those contributions.

See the README for exit codes and the data sent to each service.