Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion automations/bundle-index.js

Large diffs are not rendered by default.

55 changes: 40 additions & 15 deletions automations/catalog/github-pr-reviewer/manifest.json
Original file line number Diff line number Diff line change
@@ -1,22 +1,19 @@
{
"id": "github-pr-reviewer",
"version": "1.0.0",
"version": "1.1.0",
"name": "GitHub code review",
"category": "Code review",
"description": "Watch for a configurable label on GitHub pull requests, inspect full PR and repository context, and post an AI review comment once per label event.",
"description": "Review labelled pull requests at their current head commit, publish a readable GitHub review, and optionally verify acceptance criteria.",
"requires": {
"integrations": {
"github": {
"message": "Used to read pull requests and post review comments."
}
},
"integrations": {},
"features": [
"customTarball"
"customTarball",
"agentProfiles"
]
},
"popularityRank": 100,
"estimatedSetupMinutes": 4,
"exampleImplementation": "Trigger: cron polling for open GitHub PRs with a configured label such as openhands-review\nRequired secret: GITHUB_PERSONAL_ACCESS_TOKEN, with permission to write pull request reviews\n\n1. Read the repositories, trigger label, review tone, and polling schedule from setup.\n2. Poll each repository independently, with its own state, so PR numbers never collide.\n3. List open PRs and find the latest matching GitHub labeled issue event for each labeled PR.\n4. Deduplicate on the label event ID so every label application queues exactly one review.\n5. Extract the PR head commit into a directory of its own and start an OpenHands conversation with that directory as its workspace, so the agent reviews the exact commit without cloning anything.\n6. Post an acknowledgement with the conversation link, then confirm on GitHub that the review was published for that head SHA, falling back to posting the agent's text as a comment.\n7. Remove the checkout once the conversation has stopped, so nothing accumulates between runs.",
"exampleImplementation": "Trigger: scheduled polling for labelled pull requests needing review\nCredentials: the selected agent profile supplies the configured GitHub token\n\n1. Select pull requests whose current head needs review or acceptance verification.\n2. Attach to the conversation provisioned for the selected profile and prepare the exact pull request head.\n3. Read the changes and repository context using the existing code review workflow.\n4. Publish a readable GitHub review and verify that it was submitted for the same head commit.\n5. When configured, run independent acceptance checks with the existing QA workflow and publish the result for that head.\n6. Recheck the head before recording success so new changes require fresh review.",
"impact": {
"basis": "completed-runs",
"one": "1 PR review sweep completed",
Expand Down Expand Up @@ -48,7 +45,7 @@
"repositories": {
"type": "repo-picker",
"label": "Repositories",
"help": "The repositories whose pull requests will be reviewed. Each is polled independently and keeps its own state, so pull request numbers never collide between them.",
"help": "Repositories processed sequentially in each run. Use separate automation definitions for independent conversation context.",
"provider": "github",
"multiple": true,
"required": true
Expand Down Expand Up @@ -84,21 +81,49 @@
"label": "Friendly"
}
]
},
"githubTokenSecret": {
"type": "text",
"label": "GitHub token secret",
"help": "Name of a saved secret allowed by the selected agent profile. Enter its name, not its value.",
"default": "GITHUB_PERSONAL_ACCESS_TOKEN",
"required": true
},
"branchPrefix": {
"type": "text",
"label": "Delivery branch prefix",
"help": "Optional: review every new head on branches with this prefix and an issue number, instead of filtering by label. Requires independent test commands.",
"default": "",
"required": false
},
"testCommands": {
"type": "textarea",
"label": "Independent test commands",
"help": "Optional: one command per line, including dependency installation. Enables independent tests and QA before acceptance. Quoted arguments are supported; shell operators and pipes are not.",
"default": "",
"required": false
}
}
},
"bundle": {
"version": "1.0.0",
"entrypoint": "python3 main.py",
"timeout": 600,
"version": "1.1.0",
"entrypoint": "python3 worker.py",
"timeout": 7200,
"files": {
"main.py": "skills/github-pr-reviewer/scripts/main.py",
"github_client.py": "skills/github/scripts/github_client.py"
"github_client.py": "skills/github/scripts/github_client.py",
"worker.py": "skills/github-pr-reviewer/scripts/worker.py",
"qa_prompt.py": "skills/github-pr-reviewer/scripts/qa_prompt.py",
"qa-changes.md": "skills/github-pr-reviewer/scripts/qa-changes.md",
"github-pr-review.md": "skills/github-pr-reviewer/scripts/github-pr-review.md"
},
"config": {
"repos": "{{form.repositories}}",
"trigger_label": "{{form.triggerLabel}}",
"review_tone": "{{form.reviewTone}}"
"review_tone": "{{form.reviewTone}}",
"github_token_secret": "{{form.githubTokenSecret}}",
"branch_prefix": "{{form.branchPrefix}}",
"test_commands": "{{form.testCommands}}"
}
},
"message": "This deployment cannot run the scheduled review automation directly. Set it up in this conversation instead: confirm the repository to review, the trigger label, the review tone, and the polling schedule, then create the automation."
Expand Down
8 changes: 8 additions & 0 deletions skills/github-pr-reviewer/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,11 @@ request another review later, remove and re-apply the label.
## See Also

- [SKILL.md](SKILL.md) - Full setup workflow reference

## Continuous delivery

The catalog bundle runs `worker.py` using the Automation Service's provisioned
conversation and reuses the existing review prompt and checkout helpers. Select
an agent profile on the definition. The bundle consumes the SDK conversation API
identically in local and Docker workspaces. Configure `test_commands` and
`branch_prefix` to require independent tests and canonical QA before acceptance.
57 changes: 53 additions & 4 deletions skills/github-pr-reviewer/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,9 @@ checkout once the conversation has stopped. Nothing accumulates between runs.

---

The script imports shared GitHub transport from
`scripts/github_client.py`, installed with this skill. Include it beside
`main.py` when packaging manually, as shown below; catalog bundles include it
automatically.
The installed `scripts/` directory includes shared GitHub support and QA resources.
Package its files together; the installer materializes the shared sources, and
catalog bundles include the same files automatically.

## Prerequisites

Expand Down Expand Up @@ -320,3 +319,53 @@ The completion callback fires once for the whole run.
| Review arrives as a plain comment, not a review | Publishing failed, so the script posted the text as a fallback | Check that the token has Pull requests: Read and Write |
| Agent reports it cannot clone the repo | Prompt asked it not to; the workspace is already the checkout | No action - the code is at the head SHA in its working directory |
| Checkouts remain under `repositories/` | Their conversations had not stopped yet | They are removed by a later poll once the conversation is terminal |


## Continuous delivery review

The catalog bundle runs `worker.py` against the conversation provisioned by the
Automation Service. Select its agent profile on the automation definition; the
service and SDK resolve the model, tools, and allowed secrets. The workflow uses
the normal SDK conversation API and does not select or load profiles. Local and
Docker workspaces use the same bundle and entrypoint.

Package every file listed in this automation's catalog `setup.bundle.files`.
Set **GitHub token secret** to the name of the credential allowed by the profile
(default: `GITHUB_PERSONAL_ACCESS_TOKEN`). The command-line option
`--github-token-secret NAME` remains available for scripted deployments. This identifies a credential already
authorized by the profile; it does not grant access to another secret.

The review workflow reviews new heads carrying `trigger_label`. For continuous
delivery, set **Delivery branch prefix** and **Independent test commands** in
the setup form. Enter one command per line, including dependency installation;
quoted arguments work, but shell operators and pipes do not. Scripted deployments
can also supply `test_commands` as arrays of command arguments in `config.json`.
It then executes those commands independently, runs the canonical code review
and QA prompts, and publishes the readable reports as GitHub reviews. Only a
current, unchanged head with successful tests and both passing reports receives
a passing `software-factory/review` status. Permission errors and incomplete
reports never count as acceptance. `software-factory/tests` records the actual
command results; logs remain artifacts and comments contain a short summary.
QA reads linked issues and current acceptance criteria through the canonical
workflow instead of consuming a separately parsed issue snapshot.

The integrity check snapshots the fresh GitHub source archive before tests or
agent execution create build output. It protects all files shipped in that
archive, including tracked files that match ignore rules. Generated, ignored output remains writable for setup
and builds; this is not an immutable filesystem boundary. Independent test
commands run before the review agent changes any workspace output.

A new `trigger_label` requests review even when the commit has not changed, so
developers can explain a disputed finding without manufacturing a code change.
The reviewer removes the label after publishing its completed verdict. Pending
PRs use GitHub’s oldest-update-first order, so repeated revisions cannot keep
newer PRs waiting behind the same low-numbered PR. The
canonical workflow may publish a summary and inline review separately; all
reports from this run must agree before acceptance. An incomplete run retries
the full review and QA sequence in a new conversation, which can publish another
review on the same head. Earlier reports do not substitute for this run's
independent acceptance evidence.

Profile runs wait for review and QA to finish. The catalog allows 7200 seconds
for both stages and independent test commands; shorter timeouts can terminate
a review before it publishes its result.
1 change: 1 addition & 0 deletions skills/github-pr-reviewer/scripts/github-pr-review.md
19 changes: 16 additions & 3 deletions skills/github-pr-reviewer/scripts/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -732,7 +732,15 @@ def _load_repo_review_guide(workspace_dir: Path) -> str | None:
return None


def _build_review_prompt(repo: str, pr: dict, head_sha: str, label_event: dict, repo_review_guide: str | None = None) -> str:
def _build_review_prompt(
repo: str,
pr: dict,
head_sha: str,
label_event: dict,
repo_review_guide: str | None = None,
*,
github_access_instructions: str | None = None,
) -> str:
number = pr.get("number", "?")
title = pr.get("title", "(no title)")
body = (pr.get("body") or "").strip() or "(no description)"
Expand Down Expand Up @@ -777,8 +785,13 @@ def _build_review_prompt(repo: str, pr: dict, head_sha: str, label_event: dict,
"guidance to your review.\n"
" Then inspect the PR discussion, existing review comments, changed files, and the diff, "
"together with the surrounding code in the workspace.\n"
" Use `gh` or GitHub REST API calls with `GITHUB_PERSONAL_ACCESS_TOKEN`; never print secret values.\n"
"3. Ground every finding in the workspace code. Before using an inline location, verify that "
+ (
github_access_instructions
or "Use `gh` or GitHub REST API calls with "
"`GITHUB_PERSONAL_ACCESS_TOKEN`; never print secret values."
)
+ "\n"
+ "3. Ground every finding in the workspace code. Before using an inline location, verify that "
"the path and line are part of this pull request's diff.\n"
f"4. Publish one review with `POST /repos/{repo}/pulls/{number}/reviews`, using "
"`commit_id` equal to the Head SHA above and `event: COMMENT`.\n"
Expand Down
1 change: 1 addition & 0 deletions skills/github-pr-reviewer/scripts/qa-changes.md
1 change: 1 addition & 0 deletions skills/github-pr-reviewer/scripts/qa_prompt.py
Loading
Loading