@openhands/extensions 0.4.0 → 0.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.release-please-manifest.json +1 -1
- package/automations/catalog/github-pr-reviewer.json +2 -2
- package/package.json +1 -1
- package/plugins/qa-changes/action.yml +1 -1
- package/pyproject.toml +1 -1
- package/skills/github-pr-reviewer/.plugin/plugin.json +1 -1
- package/skills/github-pr-reviewer/README.md +21 -15
- package/skills/github-pr-reviewer/SKILL.md +206 -44
- package/skills/github-pr-reviewer/commands/pr-reviewer-setup.md +1 -1
- package/skills/github-pr-reviewer/references/state-schema.md +126 -0
- package/skills/github-pr-reviewer/scripts/main.py +608 -0
- package/skills/index.js +3 -3
- package/skills/openhands-sdk/SKILL.md +3 -0
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
"id": "github-pr-reviewer",
|
|
3
3
|
"name": "GitHub Code Review Agent",
|
|
4
4
|
"category": "Code review",
|
|
5
|
-
"description": "Watch pull requests, inspect
|
|
5
|
+
"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.",
|
|
6
6
|
"requiredIntegrationIds": [
|
|
7
7
|
"github"
|
|
8
8
|
],
|
|
9
9
|
"popularityRank": 100,
|
|
10
10
|
"estimatedSetupMinutes": 4,
|
|
11
11
|
"prompt": "/pr-reviewer:setup",
|
|
12
|
-
"exampleImplementation": "Trigger:
|
|
12
|
+
"exampleImplementation": "Trigger: cron polling for open GitHub PRs with a configured label such as openhands-review\nRequired secret: GITHUB_PERSONAL_ACCESS_TOKEN\n\n1. Read repository, trigger label, review tone, and polling schedule from setup.\n2. List open PRs and find the latest matching GitHub labeled issue event for each labeled PR.\n3. Deduplicate on the label event ID so every label application queues exactly one review.\n4. Start an OpenHands conversation that clones the repo, checks out the exact PR head SHA, and inspects PR discussion, review comments, changed files, diff, and surrounding code.\n5. Post an acknowledgement with the conversation link, then post the final AI review comment only if the PR is still open and the head SHA has not changed."
|
|
13
13
|
}
|
package/package.json
CHANGED
|
@@ -160,7 +160,7 @@ runs:
|
|
|
160
160
|
# so we enforce the time limit via the coreutils timeout command.
|
|
161
161
|
TIMEOUT_SECONDS=$((TIMEOUT_MINUTES * 60))
|
|
162
162
|
timeout "${TIMEOUT_SECONDS}" \
|
|
163
|
-
uv run --no-project --with openhands-sdk --with openhands-tools --with lmnr \
|
|
163
|
+
uv run --no-project --with openhands-sdk --with openhands-tools --with 'lmnr<0.7.53' \
|
|
164
164
|
python ../extensions/plugins/qa-changes/scripts/agent_script.py
|
|
165
165
|
|
|
166
166
|
- name: Upload logs as artifact
|
package/pyproject.toml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "github-pr-reviewer",
|
|
3
3
|
"version": "1.0.0",
|
|
4
|
-
"description": "Create an automation that reviews GitHub pull requests when
|
|
4
|
+
"description": "Create an automation that reviews GitHub pull requests when a configurable trigger label is applied. It starts one OpenHands review conversation per label event, inspects full PR and repository context, and posts the final review comment back to GitHub.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "OpenHands",
|
|
7
7
|
"email": "contact@all-hands.dev"
|
|
@@ -1,34 +1,40 @@
|
|
|
1
1
|
# GitHub PR Reviewer
|
|
2
2
|
|
|
3
|
-
Create an automation that reviews GitHub pull requests
|
|
3
|
+
Create an automation that reviews GitHub pull requests when a configurable
|
|
4
|
+
trigger label is applied.
|
|
4
5
|
|
|
5
|
-
##
|
|
6
|
+
## Trigger
|
|
6
7
|
|
|
7
|
-
This skill is activated by
|
|
8
|
+
This skill is activated by:
|
|
8
9
|
|
|
9
|
-
- `
|
|
10
|
-
- `PR review automation`
|
|
11
|
-
- `auto-review PRs`
|
|
10
|
+
- `/pr-reviewer:setup`
|
|
12
11
|
|
|
13
12
|
## Features
|
|
14
13
|
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
14
|
+
- Reviews PRs on demand by watching for a GitHub label event
|
|
15
|
+
- Processes each label application exactly once, with persistent state
|
|
16
|
+
- Re-review support by removing and re-applying the label
|
|
17
|
+
- Suppresses stale reviews when the PR head commit changes mid-review
|
|
18
|
+
- Uses a real cloned checkout and full PR context instead of only a truncated diff
|
|
19
|
+
- Posts acknowledgement and final review comments with AI disclosure
|
|
20
|
+
- Configurable review tone and polling schedule
|
|
20
21
|
|
|
21
22
|
## Prerequisites
|
|
22
23
|
|
|
23
|
-
|
|
24
|
+
Set `GITHUB_PERSONAL_ACCESS_TOKEN` in OpenHands Settings -> Secrets. The token
|
|
25
|
+
must be able to read the repository, read pull requests, read issue events, and
|
|
26
|
+
write issue comments.
|
|
24
27
|
|
|
25
28
|
## Quick Start
|
|
26
29
|
|
|
27
30
|
Ask OpenHands:
|
|
28
31
|
|
|
29
|
-
> "Set up a PR review automation for my myorg/backend repo
|
|
30
|
-
>
|
|
32
|
+
> "Set up a PR review automation for my `myorg/backend` repo using the
|
|
33
|
+
> `openhands-review` label and concise reviews."
|
|
34
|
+
|
|
35
|
+
After setup, apply the configured label to a pull request to queue a review. To
|
|
36
|
+
request another review later, remove and re-apply the label.
|
|
31
37
|
|
|
32
38
|
## See Also
|
|
33
39
|
|
|
34
|
-
- [SKILL.md](SKILL.md)
|
|
40
|
+
- [SKILL.md](SKILL.md) - Full setup workflow reference
|
|
@@ -1,89 +1,251 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: github-pr-reviewer
|
|
3
3
|
description: >
|
|
4
|
-
Create an automation that reviews GitHub pull requests when
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
Create an automation that reviews GitHub pull requests when a configurable
|
|
5
|
+
trigger label is applied. Polls GitHub deterministically, starts one
|
|
6
|
+
OpenHands review conversation per label event, inspects full repository and
|
|
7
|
+
PR context, and posts the final review comment back to GitHub.
|
|
8
8
|
triggers:
|
|
9
9
|
- /pr-reviewer:setup
|
|
10
10
|
---
|
|
11
11
|
|
|
12
12
|
# GitHub PR Reviewer Automation
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
Create a cron automation that watches a GitHub repository for pull requests
|
|
15
|
+
with a review trigger label, starts an OpenHands review conversation once per
|
|
16
|
+
label event, and posts the AI review as a GitHub comment.
|
|
17
|
+
|
|
18
|
+
The automation script is deterministic: PR discovery, label-event tracking,
|
|
19
|
+
state persistence, stale-result suppression, and GitHub comment posting are
|
|
20
|
+
handled in Python. The LLM is invoked only for the review itself.
|
|
15
21
|
|
|
16
22
|
---
|
|
17
23
|
|
|
18
24
|
## Prerequisites
|
|
19
25
|
|
|
20
|
-
### Required
|
|
26
|
+
### Required secret
|
|
21
27
|
|
|
22
|
-
|
|
28
|
+
Verify that the following secret is set in **OpenHands Settings -> Secrets**:
|
|
23
29
|
|
|
24
|
-
|
|
30
|
+
| Secret name | Token type | Minimum permissions |
|
|
31
|
+
|---|---|---|
|
|
32
|
+
| `GITHUB_PERSONAL_ACCESS_TOKEN` | Classic PAT | `repo` for private repos or `public_repo` for public repos |
|
|
33
|
+
| `GITHUB_PERSONAL_ACCESS_TOKEN` | Fine-grained PAT | Contents: Read, Metadata: Read, Pull requests: Read, Issues: Read and Write |
|
|
25
34
|
|
|
26
|
-
|
|
35
|
+
Check with:
|
|
36
|
+
```bash
|
|
37
|
+
curl -s https://api.github.com/user \
|
|
38
|
+
-H "Authorization: Bearer $GITHUB_PERSONAL_ACCESS_TOKEN" \
|
|
39
|
+
| python3 -c "import json,sys; d=json.load(sys.stdin); print(d.get('login') or d.get('message'))"
|
|
40
|
+
```
|
|
27
41
|
|
|
28
|
-
|
|
29
|
-
2. **Trigger type** — event-based (reacts to `pull_request.opened` / `pull_request.synchronize`) or cron-based polling
|
|
30
|
-
3. **Review tone** — thorough, concise, or friendly
|
|
31
|
-
4. **Auto-post or draft** — should reviews be posted as GitHub comments automatically, or saved as draft artifacts for human approval first?
|
|
32
|
-
5. **Filters** — any label, branch, or author filters (e.g. skip drafts, only review PRs with `needs-review` label)
|
|
42
|
+
If the token is missing or invalid, inform the user and stop.
|
|
33
43
|
|
|
34
44
|
---
|
|
35
45
|
|
|
36
46
|
## Setup Workflow
|
|
37
47
|
|
|
38
|
-
|
|
48
|
+
Follow these steps in order.
|
|
49
|
+
|
|
50
|
+
### Step 1 - Verify `GITHUB_PERSONAL_ACCESS_TOKEN`
|
|
51
|
+
|
|
52
|
+
Run the `curl` check above.
|
|
53
|
+
|
|
54
|
+
- If absent: *"GITHUB_PERSONAL_ACCESS_TOKEN is not set. Please add it in
|
|
55
|
+
OpenHands Settings -> Secrets."* Stop.
|
|
56
|
+
- If the API returns `{"message": "Bad credentials"}`: tell the user the
|
|
57
|
+
token is invalid and ask them to update it. Stop.
|
|
39
58
|
|
|
40
|
-
|
|
59
|
+
### Step 2 - Collect repository
|
|
60
|
+
|
|
61
|
+
Ask: *"Which GitHub repository should be monitored?
|
|
62
|
+
(Format: `owner/repo`, e.g. `myorg/backend`)"*
|
|
63
|
+
|
|
64
|
+
Validate access:
|
|
65
|
+
```bash
|
|
66
|
+
curl -s "https://api.github.com/repos/{owner}/{repo}" \
|
|
67
|
+
-H "Authorization: Bearer $GITHUB_PERSONAL_ACCESS_TOKEN" \
|
|
68
|
+
| python3 -c "
|
|
69
|
+
import json, sys
|
|
70
|
+
d = json.load(sys.stdin)
|
|
71
|
+
if 'message' in d:
|
|
72
|
+
print('ERROR:', d['message'])
|
|
73
|
+
else:
|
|
74
|
+
print(f\"Accessible. Private: {d.get('private')}. Permissions: {d.get('permissions')}\")
|
|
75
|
+
"
|
|
41
76
|
```
|
|
42
|
-
|
|
77
|
+
|
|
78
|
+
Record `REPO = "{owner}/{repo}"`.
|
|
79
|
+
|
|
80
|
+
### Step 3 - Collect trigger label
|
|
81
|
+
|
|
82
|
+
Ask: *"Which PR label should trigger a review?
|
|
83
|
+
(Press Enter for the default: `openhands-review`.)"*
|
|
84
|
+
|
|
85
|
+
Record the answer as `TRIGGER_LABEL`. If the label does not exist yet, tell the
|
|
86
|
+
user that GitHub will still record the event once the label is created and
|
|
87
|
+
applied to a PR.
|
|
88
|
+
|
|
89
|
+
The automation reviews a PR when it sees the latest matching `labeled` event for
|
|
90
|
+
that label. To request another review later, remove and re-apply the label.
|
|
91
|
+
|
|
92
|
+
### Step 4 - Collect review tone
|
|
93
|
+
|
|
94
|
+
Ask: *"What review tone should the reviewer use?
|
|
95
|
+
1. Thorough (default) - comprehensive coverage of correctness, security, tests, style
|
|
96
|
+
2. Concise - high-signal only, skips minor style feedback
|
|
97
|
+
3. Friendly - constructive and encouraging
|
|
98
|
+
(Press Enter for Thorough, or type your choice or any custom style description)"*
|
|
99
|
+
|
|
100
|
+
Map the choice to `REVIEW_TONE`:
|
|
101
|
+
|
|
102
|
+
| Answer | `REVIEW_TONE` | `REVIEW_STYLE_INSTRUCTIONS` |
|
|
103
|
+
|---|---|---|
|
|
104
|
+
| 1 / Enter | `"thorough"` | `""` |
|
|
105
|
+
| 2 | `"concise"` | `""` |
|
|
106
|
+
| 3 | `"friendly"` | `""` |
|
|
107
|
+
| Custom text, e.g. `strict but kind` | `"thorough"` | the custom text verbatim |
|
|
108
|
+
|
|
109
|
+
### Step 5 - Collect cron schedule
|
|
110
|
+
|
|
111
|
+
Ask: *"How often should the automation poll for labeled PRs?
|
|
112
|
+
(Press Enter for the default: every 5 minutes.
|
|
113
|
+
Use a cron expression for a different interval, e.g. `0 * * * *` = hourly)"*
|
|
114
|
+
|
|
115
|
+
Default: `*/5 * * * *`.
|
|
116
|
+
|
|
117
|
+
Record as `CRON_SCHEDULE`.
|
|
118
|
+
|
|
119
|
+
### Step 6 - Generate the automation script
|
|
120
|
+
|
|
121
|
+
Read `scripts/main.py` from this skill's directory. Apply exactly five constant
|
|
122
|
+
substitutions near the top of the file:
|
|
123
|
+
|
|
124
|
+
| Placeholder | Replace with |
|
|
125
|
+
|---|---|
|
|
126
|
+
| `REPO = "owner/repo"` | `REPO = "{owner_repo}"` |
|
|
127
|
+
| `TRIGGER_LABEL = "openhands-review"` | `TRIGGER_LABEL = "{trigger_label}"` |
|
|
128
|
+
| `REVIEW_TONE = "thorough"` | `REVIEW_TONE = "{review_tone}"` |
|
|
129
|
+
| `REVIEW_STYLE_INSTRUCTIONS = ""` | `REVIEW_STYLE_INSTRUCTIONS = "{style_instructions}"` |
|
|
130
|
+
| `DEFAULT_OPENHANDS_URL = "http://localhost:8000"` | leave unchanged unless the user has a preference |
|
|
131
|
+
|
|
132
|
+
Use a safe string writer such as `json.dumps(value)` when inserting user-provided
|
|
133
|
+
repository names, labels, or style instructions into Python string literals.
|
|
134
|
+
|
|
135
|
+
Write the customized script to a temporary build directory:
|
|
136
|
+
```bash
|
|
137
|
+
mkdir -p /tmp/pr-reviewer-build
|
|
138
|
+
# write the customized main.py to /tmp/pr-reviewer-build/main.py
|
|
43
139
|
```
|
|
44
140
|
|
|
45
|
-
|
|
141
|
+
Validate syntax before packaging:
|
|
142
|
+
```bash
|
|
143
|
+
python3 -m py_compile /tmp/pr-reviewer-build/main.py && echo "Syntax OK"
|
|
144
|
+
```
|
|
46
145
|
|
|
47
|
-
|
|
146
|
+
Fix any syntax errors before proceeding.
|
|
48
147
|
|
|
49
|
-
|
|
50
|
-
Check `<RUNTIME_SERVICES>` for deployment reachability. If the deployment has a public URL, recommend an event trigger on `pull_request.opened` and `pull_request.synchronize`.
|
|
148
|
+
### Step 7 - Package and upload
|
|
51
149
|
|
|
52
|
-
|
|
53
|
-
|
|
150
|
+
Determine the Automation backend URL and auth from the `<RUNTIME_SERVICES>`
|
|
151
|
+
block in your system context:
|
|
152
|
+
- **OPENHANDS_HOST**: the Automation backend `url_from_agent`
|
|
153
|
+
- **Auth**: `X-Session-API-Key: $OPENHANDS_AUTOMATION_API_KEY`
|
|
54
154
|
|
|
55
|
-
|
|
155
|
+
```bash
|
|
156
|
+
tar -czf /tmp/pr-reviewer.tar.gz -C /tmp/pr-reviewer-build .
|
|
56
157
|
|
|
57
|
-
|
|
58
|
-
-
|
|
59
|
-
-
|
|
60
|
-
-
|
|
61
|
-
-
|
|
158
|
+
TARBALL_PATH=$(curl -s -X POST \
|
|
159
|
+
"${OPENHANDS_HOST}/api/automation/v1/uploads?name=github-pr-reviewer" \
|
|
160
|
+
-H "X-Session-API-Key: $OPENHANDS_AUTOMATION_API_KEY" \
|
|
161
|
+
-H "Content-Type: application/gzip" \
|
|
162
|
+
--data-binary @/tmp/pr-reviewer.tar.gz \
|
|
163
|
+
| python3 -c "import json,sys; print(json.load(sys.stdin)['tarball_path'])")
|
|
62
164
|
|
|
63
|
-
|
|
165
|
+
echo "Uploaded: $TARBALL_PATH"
|
|
166
|
+
```
|
|
64
167
|
|
|
65
|
-
|
|
66
|
-
- Use the **Automation backend** `url_from_agent` as `OPENHANDS_HOST`
|
|
67
|
-
- Auth: `X-Session-API-Key: $OPENHANDS_AUTOMATION_API_KEY`
|
|
168
|
+
### Step 8 - Register the automation
|
|
68
169
|
|
|
69
|
-
Use the **prompt preset** endpoint:
|
|
70
170
|
```bash
|
|
71
|
-
curl -s -X POST "${OPENHANDS_HOST}/api/automation/v1
|
|
171
|
+
curl -s -X POST "${OPENHANDS_HOST}/api/automation/v1" \
|
|
72
172
|
-H "X-Session-API-Key: $OPENHANDS_AUTOMATION_API_KEY" \
|
|
73
173
|
-H "Content-Type: application/json" \
|
|
74
|
-
-d
|
|
75
|
-
"name": "GitHub PR Reviewer",
|
|
76
|
-
"
|
|
77
|
-
"
|
|
78
|
-
|
|
174
|
+
-d "{
|
|
175
|
+
\"name\": \"GitHub PR Reviewer: {owner}/{repo} label {trigger_label}\",
|
|
176
|
+
\"trigger\": {\"type\": \"cron\", \"schedule\": \"{cron_schedule}\"},
|
|
177
|
+
\"tarball_path\": \"$TARBALL_PATH\",
|
|
178
|
+
\"entrypoint\": \"python3 main.py\",
|
|
179
|
+
\"timeout\": 300
|
|
180
|
+
}" | python3 -m json.tool
|
|
79
181
|
```
|
|
80
182
|
|
|
81
|
-
|
|
183
|
+
Record the returned `id`.
|
|
184
|
+
|
|
185
|
+
### Step 9 - Confirm
|
|
82
186
|
|
|
83
187
|
Tell the user:
|
|
188
|
+
|
|
84
189
|
> ✅ **GitHub PR Reviewer** is running!
|
|
85
190
|
>
|
|
86
191
|
> - Automation ID: `{id}`
|
|
87
|
-
> -
|
|
88
|
-
> - Trigger: `{
|
|
89
|
-
> - Review
|
|
192
|
+
> - Repository: `{owner}/{repo}`
|
|
193
|
+
> - Trigger label: `{trigger_label}`
|
|
194
|
+
> - Review tone: `{tone}`
|
|
195
|
+
> - Polling schedule: `{cron_schedule}`
|
|
196
|
+
> - State file: `~/.openhands/workspaces/automation-state/github_pr_reviewer_label_event_{id}.json`
|
|
197
|
+
>
|
|
198
|
+
> Apply the `{trigger_label}` label to a pull request to queue a review. Each
|
|
199
|
+
> label event is processed once. To request another review, remove and re-apply
|
|
200
|
+
> the label.
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
## Runtime Behaviour (per poll)
|
|
205
|
+
|
|
206
|
+
Each cron run executes `main.py`, which:
|
|
207
|
+
|
|
208
|
+
1. Loads state from the JSON file (see `references/state-schema.md`).
|
|
209
|
+
2. Resolves and validates `GITHUB_PERSONAL_ACCESS_TOKEN` and repository access.
|
|
210
|
+
3. Lists open PRs, newest-updated first.
|
|
211
|
+
4. For each open PR carrying `TRIGGER_LABEL`:
|
|
212
|
+
- Refetches current PR metadata to avoid acting on stale list data.
|
|
213
|
+
- Finds the latest matching GitHub `labeled` issue event.
|
|
214
|
+
- Skips the event if it has already been tracked.
|
|
215
|
+
- Starts an OpenHands conversation with a review prompt that includes PR
|
|
216
|
+
metadata, the exact head SHA, label event details, and instructions to
|
|
217
|
+
clone the repo, inspect PR discussion, review comments, changed files,
|
|
218
|
+
diff, and surrounding code.
|
|
219
|
+
- Posts an acknowledgement comment with the label event, head SHA, and
|
|
220
|
+
conversation link.
|
|
221
|
+
- Records the label-event review in state with `status: "active"`.
|
|
222
|
+
5. For each active review conversation:
|
|
223
|
+
- Marks it closed without posting if the PR has closed or merged.
|
|
224
|
+
- Suppresses stale results if the PR head SHA changed after the review was
|
|
225
|
+
queued.
|
|
226
|
+
- When the conversation reaches `idle`, `finished`, `error`, or `stuck`,
|
|
227
|
+
posts the agent's final response as a GitHub comment and marks the review
|
|
228
|
+
closed.
|
|
229
|
+
6. Saves state atomically and fires the completion callback.
|
|
230
|
+
|
|
231
|
+
---
|
|
232
|
+
|
|
233
|
+
## Additional Resources
|
|
234
|
+
|
|
235
|
+
- **`references/state-schema.md`** - State JSON schema, field definitions, and
|
|
236
|
+
review lifecycle diagram.
|
|
237
|
+
- **`scripts/main.py`** - The complete automation script. Customize the five
|
|
238
|
+
constants at the top before packaging.
|
|
239
|
+
|
|
240
|
+
---
|
|
241
|
+
|
|
242
|
+
## Troubleshooting
|
|
243
|
+
|
|
244
|
+
| Symptom | Likely cause | Fix |
|
|
245
|
+
|---|---|---|
|
|
246
|
+
| Bot never queues reviews | Trigger label not present or no matching `labeled` event | Apply the configured label to the PR |
|
|
247
|
+
| "Bad credentials" in run logs | Token expired | Rotate and update `GITHUB_PERSONAL_ACCESS_TOKEN` |
|
|
248
|
+
| 404 on repo access | Repo name wrong or no access | Re-check `owner/repo` and token permissions |
|
|
249
|
+
| Same PR not reviewed after new commits | Label event was already processed | Remove and re-apply the trigger label |
|
|
250
|
+
| Review result never posts | Conversation still running or stuck | Open the conversation link from the acknowledgement comment |
|
|
251
|
+
| Stale review suppressed | PR head SHA changed while the agent was reviewing | Re-apply the trigger label after the latest commit |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
# auto-generated by sync_extensions.py
|
|
3
|
-
description: Create an automation that reviews GitHub pull requests when
|
|
3
|
+
description: Create an automation that reviews GitHub pull requests when a configurable trigger label is applied. Polls GitHub deterministically, starts one OpenHands review conversation per label event, inspects full repository and PR context, and posts the final review comment back to GitHub.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
Read and follow the complete instructions in the SKILL.md file located in this skill's directory.
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# State File Schema
|
|
2
|
+
|
|
3
|
+
The automation maintains a JSON state file that persists across polling runs.
|
|
4
|
+
It is the source of truth for which trigger-label events have queued reviews
|
|
5
|
+
and which conversations are still active.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## File Location
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
{WORKSPACE_BASE_ROOT}/automation-state/github_pr_reviewer_label_event_{automation_id}.json
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
`WORKSPACE_BASE_ROOT` is derived by going two levels up from the `WORKSPACE_BASE`
|
|
16
|
+
environment variable, stripping `automation-runs/{run_id}`.
|
|
17
|
+
|
|
18
|
+
Example on a local install:
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
~/.openhands/workspaces/automation-state/github_pr_reviewer_label_event_abc12345-....json
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
The `automation_id` is read from the `AUTOMATION_EVENT_PAYLOAD` environment
|
|
25
|
+
variable, field `automation_id`.
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Top-Level Schema
|
|
30
|
+
|
|
31
|
+
```jsonc
|
|
32
|
+
{
|
|
33
|
+
"version": 2,
|
|
34
|
+
"repo": "owner/repo",
|
|
35
|
+
"trigger_label": "openhands-review",
|
|
36
|
+
"updated_at": 1717200000.0,
|
|
37
|
+
"reviews": {},
|
|
38
|
+
"prs": {}
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## `reviews` Map
|
|
45
|
+
|
|
46
|
+
Key: `"{pr_number}:label:{label_event_id}"`. This makes the latest GitHub
|
|
47
|
+
`labeled` event the idempotency key. Re-applying the trigger label creates a new
|
|
48
|
+
GitHub event and therefore a new review request.
|
|
49
|
+
|
|
50
|
+
Value: **ReviewRecord**
|
|
51
|
+
|
|
52
|
+
```jsonc
|
|
53
|
+
{
|
|
54
|
+
"pr_number": 42,
|
|
55
|
+
"head_sha": "0123456789abcdef...",
|
|
56
|
+
"trigger_label_event_id": 123456789,
|
|
57
|
+
"trigger_label_event_created_at": "2026-06-12T00:00:00Z",
|
|
58
|
+
"html_url": "https://github.com/owner/repo/pull/42",
|
|
59
|
+
"status": "active",
|
|
60
|
+
"conversation_id": "550e8400-e29b-41d4-a716-446655440000",
|
|
61
|
+
"last_activity": 1717200000.0
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
`status` values:
|
|
66
|
+
|
|
67
|
+
| Status | Meaning |
|
|
68
|
+
|---|---|
|
|
69
|
+
| `active` | Review conversation is running or waiting to be collected |
|
|
70
|
+
| `closed` | Final result was posted, or the PR closed before collection |
|
|
71
|
+
| `stale` | PR head SHA changed before the review completed, so the result was suppressed |
|
|
72
|
+
|
|
73
|
+
When a review becomes stale, `stale_reason` records the old and new head SHAs.
|
|
74
|
+
When a review closes after posting, `completed_at` records the completion time.
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## `prs` Map
|
|
79
|
+
|
|
80
|
+
Key: `"{pr_number}"`.
|
|
81
|
+
|
|
82
|
+
Value: latest PR snapshot observed during polling:
|
|
83
|
+
|
|
84
|
+
```jsonc
|
|
85
|
+
{
|
|
86
|
+
"head_sha": "0123456789abcdef...",
|
|
87
|
+
"label_present": true,
|
|
88
|
+
"labels": ["openhands-review", "bug"],
|
|
89
|
+
"last_seen": 1717200000.0
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
This snapshot is informational and helps diagnose whether a PR was skipped
|
|
94
|
+
because the trigger label was absent.
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## Review Lifecycle
|
|
99
|
+
|
|
100
|
+
```
|
|
101
|
+
Trigger label applied on GitHub
|
|
102
|
+
|
|
|
103
|
+
v
|
|
104
|
+
[active] - conversation created, acknowledgement comment posted
|
|
105
|
+
|
|
|
106
|
+
+-- PR closes/merges before collection --> [closed] without posting
|
|
107
|
+
|
|
|
108
|
+
+-- PR head SHA changes before collection --> [stale] without posting
|
|
109
|
+
|
|
|
110
|
+
v
|
|
111
|
+
[closed] - final review comment posted
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## Resetting State
|
|
117
|
+
|
|
118
|
+
To force the automation to reconsider previous label events, delete the state
|
|
119
|
+
file:
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
rm ~/.openhands/workspaces/automation-state/github_pr_reviewer_label_event_<id>.json
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Usually, prefer removing and re-applying the trigger label. That preserves
|
|
126
|
+
history while creating a new review request.
|