fallow ci: post PR and MR feedback from CI
Reference for fallow ci: post or update the sticky PR comment, post inline reviews, resolve fixed review threads, and post GitHub Check Runs from rendered fallow output.
fallow ci posts fallow feedback to a pull request (GitHub) or a merge request (GitLab). The GitHub Action and the GitLab CI template call these commands for you. Use them directly when you build your own CI integration.
Each command reads a file that an earlier fallow run rendered. It does not analyze the project.
| Subcommand | What it does | Providers |
|---|---|---|
plan-pr-comment | Computes the action for a sticky summary comment. It does not call an API. | Both |
post-pr-comment | Creates, updates, or skips the sticky summary comment. | GitHub, GitLab |
post-review | Posts the new findings of a review envelope as inline review comments, and resolves the fallow threads of fixed findings. | GitHub, GitLab |
reconcile-review | Resolves the fallow review threads of findings that went away. | GitHub, GitLab |
post-check-run | Posts a GitHub Check Run from a PR decision file. | GitHub |
fallow dead-code --format pr-comment-github --quiet > fallow-comment.md
fallow ci post-pr-comment --provider github --pr 42 \
--body fallow-comment.md --marker-id fallow-results
Input files
| File | How to make it |
|---|---|
| PR comment body | Run an analysis with --format pr-comment-github or --format pr-comment-gitlab. The body has a <!-- fallow-id: <marker> --> line. The default marker is fallow-results. |
| PR comment envelope | Set FALLOW_PR_COMMENT_ENVELOPE_FILE to a path when you render the comment body. Fallow then also writes the typed envelope to that path. |
| PR decision file | Set FALLOW_PR_DECISION_FILE to a path when you render the comment body. Fallow then writes a fallow-pr-decision/v1 JSON file to that path. |
| Review envelope | Run an analysis with --format review-github or --format review-gitlab. |
Authentication
| Provider | Token | Repository or project |
|---|---|---|
| GitHub | GH_TOKEN, else GITHUB_TOKEN | --repo <owner/name>, else GH_REPO, else GITHUB_REPOSITORY |
| GitLab | GITLAB_TOKEN, a project access token or a personal access token with api scope | --project-id, else CI_PROJECT_ID |
The API base URL is --api-url. The GitHub default is github.com. The GitLab default is CI_API_V4_URL, else https://gitlab.com/api/v4. The GitLab CI_JOB_TOKEN cannot create or update MR notes, so fallow does not use it.
These environment variables also change the behavior:
| Variable | Effect |
|---|---|
FALLOW_BOT_LOGIN | The user name that fallow treats as its own when it finds an existing comment. Set it when you post with a personal access token. |
FALLOW_API_RETRIES | The maximum number of HTTP attempts (default 3). |
FALLOW_API_RETRY_DELAY | The minimum delay in seconds between retries (default 2). A Retry-After header overrides it. |
FALLOW_CONSOLIDATED_STATUS | With post-check-run --split-gates, set it to 1, true, yes, or on to also post one aggregate check. |
ci plan-pr-comment
Computes what to do with a sticky summary comment. It does not call a provider API. Use it when your own script posts the comment.
| Flag | Description |
|---|---|
--body <BODY> | Required. The path of the rendered comment body. |
--marker-id <MARKER_ID> | Required. The sticky marker id in the body. |
--clean | Treat the body as a clean result with no findings. |
--existing-comment-id <ID> | The id of the existing sticky comment, when one exists. |
--existing-body <PATH> | The path of the body of the existing comment. With this flag, the plan can skip an unchanged comment. |
The output is JSON with an action: create, update, or skip. A skip has a skip_reason: clean_no_existing_comment (a clean run with no comment to update) or unchanged (the body did not change).
{
"action": "create",
"marker_id": "fallow-results",
"body": "<!-- fallow-id: fallow-results -->\n### Fallow codebase report\n..."
}
ci post-pr-comment
Finds the existing sticky comment, then creates, updates, or skips it. The rules are the same as in plan-pr-comment.
| Flag | Description |
|---|---|
--provider <PROVIDER> | Required. github or gitlab. |
--pr <PR> | The pull request number (GitHub). |
--mr <MR> | The merge request IID (GitLab). |
--body <BODY> | Required. The path of the rendered comment body. |
--envelope <ENVELOPE> | The path of the typed PR comment envelope, when you have one. |
--marker-id <MARKER_ID> | Required. The sticky marker id in the body. |
--clean | Treat the body as a clean result with no findings. |
--repo <REPO> | The GitHub repository, in owner/name form. |
--project-id <PROJECT_ID> | The GitLab project id or path. |
--api-url <API_URL> | The provider API base URL. |
--dry-run | Compute the plan. Do not create or update the comment. |
The command prints the plan as JSON on stdout.
ci post-review
Posts a review envelope to the pull request or merge request. On GitHub, the comments go into one review. On GitLab, each comment is a discussion on the diff. The command posts only the comments whose fingerprint is not in an open fallow thread. It also resolves the fallow threads of findings that are not in the envelope any more, as reconcile-review does.
| Flag | Description |
|---|---|
--provider <PROVIDER> | Required. github or gitlab. |
--pr <PR> | The pull request number (GitHub). |
--mr <MR> | The merge request IID (GitLab). |
--envelope <ENVELOPE> | Required. The path of a review-github or review-gitlab JSON envelope. |
--repo <REPO> | The GitHub repository, in owner/name form. |
--project-id <PROJECT_ID> | The GitLab project id or path. |
--api-url <API_URL> | The provider API base URL. |
--dry-run | Compute the plan. Do not create comments. |
The JSON result gives comments_posted, comments_skipped, stale_fingerprints, and threads_resolved. A comment that the provider rejects goes into post_errors, and the command still exits 0. See CI integration for the fingerprint markers.
ci reconcile-review
Checks a review envelope and computes a stable plan. Then it resolves the fallow threads of findings that are not in the envelope any more.
| Flag | Description |
|---|---|
--provider <PROVIDER> | Required. github or gitlab. |
--pr <PR> | The pull request number (GitHub). |
--mr <MR> | The merge request IID (GitLab). |
--envelope <ENVELOPE> | Required. The path of a review-github or review-gitlab JSON envelope. |
--repo <REPO> | The GitHub repository, in owner/name form. |
--project-id <PROJECT_ID> | The GitLab project id or path. |
--api-url <API_URL> | The provider API base URL. |
--dry-run | Compute the plan. Do not post resolution notes or resolve threads. |
ci post-check-run
Posts a GitHub Check Run from a PR decision file. Only GitHub is supported. --provider gitlab exits with code 2.
| Flag | Description |
|---|---|
--provider <PROVIDER> | Required. Use github. |
--decision <DECISION> | Required. The path of a fallow-pr-decision/v1 JSON file. |
--repo <REPO> | Required. The GitHub repository, in owner/name form. |
--head-sha <HEAD_SHA> | Required. The commit that the check run attaches to. |
--api-url <API_URL> | The GitHub API base URL. |
--split-gates | Post one check run for each gate, named Fallow / <gate>, in place of one Fallow check. |
--dry-run | Print the check run payload. Do not post it. |
FALLOW_PR_DECISION_FILE=fallow-pr-decision.json \
fallow dead-code --format pr-comment-github --quiet > fallow-comment.md
fallow ci post-check-run --provider github --decision fallow-pr-decision.json \
--repo acme/app --head-sha "$GITHUB_SHA" --split-gates
Use --split-gates to make each gate a separate required check. See Gates.
Exit codes
| Code | Meaning |
|---|---|
0 | The command ran. A skipped post is a success. Errors for single comments or threads are in the post_errors and apply_errors arrays of the JSON result. |
2 | Invalid input, for example a file that fallow cannot read, an invalid envelope, or a missing --repo. |
7 | A network or provider API failure, for example a missing token or a failed API request. |
With --format json, an error is a JSON object with "error": true on stdout.