Skip to content

Add polling-github-pr-review plugin#302

Draft
jpelletier1 wants to merge 3 commits into
mainfrom
add-polling-github-pr-review-plugin
Draft

Add polling-github-pr-review plugin#302
jpelletier1 wants to merge 3 commits into
mainfrom
add-polling-github-pr-review-plugin

Conversation

@jpelletier1

Copy link
Copy Markdown
Contributor
  • A human has tested these changes.

Why

Teams that want automated code review on labeled PRs often can't use webhook-based automations because their OpenHands deployment isn't publicly reachable. This plugin fills that gap with a polling-based alternative that works in all deployment modes (local and cloud).

Summary

  • Adds plugins/polling-github-pr-review/ - a new plugin that deploys a cron automation (every 5 minutes) to poll GitHub for labeled PRs and start an OpenHands code review conversation for each new one
  • Adds a marketplace entry in marketplaces/openhands-extensions.json
  • Regenerates the README catalog via sync_extensions.py

Plugin files

File Purpose
SKILL.md Interactive onboarding: asks repo, label, and code-review skill URL; customizes the script; packages and deploys the automation
scripts/main.py Polling automation script (pure stdlib, no SDK required)
.plugin/plugin.json Plugin manifest with vendor symlinks
README.md Human documentation

Automation behaviour

  1. First run guard - records a baseline timestamp and exits cleanly (exit code 0). No reviews triggered for pre-existing PRs.
  2. Subsequent runs - queries GitHub for open PRs with the configured label created after last_run_ts, skips already-reviewed PR numbers, starts a new OpenHands conversation for each new match.
  3. State is persisted to {WORKSPACE_BASE}/automation-state/github_pr_poller_{id}.json.

SKILL onboarding questions

Before deploying, the SKILL asks the user:

  1. Which GitHub repository to monitor?
  2. What PR label should trigger a review?
  3. What code review skill URL to use? (default: https://github.com/OpenHands/extensions/tree/main/skills/code-review)

Issue Number

N/A

How to Test

  1. Load the plugin in an OpenHands conversation
  2. The SKILL guides through the 3 setup questions
  3. Review the automation summary it presents, then confirm deployment
  4. Open a new PR in the monitored repo with the configured label
  5. Within ~5 minutes, an OpenHands conversation should appear performing the code review

To verify the script logic without deploying:

cd plugins/polling-github-pr-review
python3 -m py_compile scripts/main.py && echo "Syntax OK"

To verify CI:

python3 -m pytest tests/test_plugin_manifest.py -v
python3 scripts/sync_extensions.py --check

Video/Screenshots

N/A

Notes

  • Required secret: GITHUB_PERSONAL_ACCESS_TOKEN (Classic PAT with repo/public_repo, or fine-grained with Pull requests: Read and Write)
  • All 76 existing tests pass; sync_extensions.py --check exits clean
  • The pre-existing issue-duplicate-checker coverage warning is unrelated to this PR

This pull request was created by an AI agent (OpenHands) on behalf of the user.

@jpelletier1 can click here to continue refining the PR

Adds a new plugin that deploys a cron automation (every 5 minutes)
to poll a GitHub repository for labeled pull requests and start an
OpenHands code review conversation for each new one.

Plugin components:
- SKILL.md: interactive onboarding that asks the user 3 questions
  (repo, label, code-review skill URL), customizes the script, then
  packages and deploys the automation via the Automation API
- scripts/main.py: the polling automation script; first-run guard
  records a baseline timestamp and exits (no reviews on first run);
  subsequent runs filter PRs by label and created_at, deduplicate
  against a persisted reviewed_prs list, and start conversations
- .plugin/plugin.json: manifest with vendor symlinks
- README.md: human documentation

Also adds a marketplace entry in openhands-extensions.json and
regenerates the README catalog via sync_extensions.py.

Co-authored-by: openhands <openhands@all-hands.dev>
…f detection

Two logic changes:

1. Label filter is now optional: LABEL = "" (empty string) means no
   label filter and the automation reviews all newly-opened PRs. The
   SKILL onboarding marks Question 2 as optional.

2. PR detection now uses a set-diff approach instead of created_at
   filtering:
   - Each run fetches the full set of currently open PRs
   - Diffs against the open_pr_numbers snapshot stored from the
     previous run
   - Any PR in the current set but not the previous snapshot has
     moved to Open status (newly created or reopened)
   - Updates the snapshot at the end of each run

   State shape change: last_run_ts / reviewed_prs replaced by
   open_pr_numbers (sorted list of currently open PR numbers).
   The datetime import is also removed as it is no longer needed.

Co-authored-by: openhands <openhands@all-hands.dev>
Previously the first-run guard checked whether 'open_pr_numbers' was
absent from the loaded state dict. Because _load_state returns {} when
the file does not exist, this was indistinguishable from a missing or
corrupted file - and any ephemeral workspace would re-trigger the
first-run snapshot on every execution.

Now the check is done before loading state:

  is_first_run = not os.path.exists(state_path)

The state file's presence on disk is the sole source of truth for
whether this is the first run. _load_state is only called on
subsequent runs where the file is known to exist.

Co-authored-by: openhands <openhands@all-hands.dev>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants