Skip to content

feat: add ready-for-dev issue and PR readiness gates - #380

Draft
neubig wants to merge 1 commit into
mainfrom
feat/ready-for-dev-gates
Draft

feat: add ready-for-dev issue and PR readiness gates#380
neubig wants to merge 1 commit into
mainfrom
feat/ready-for-dev-gates

Conversation

@neubig

@neubig neubig commented Aug 24, 2026

Copy link
Copy Markdown
Member

Summary

Adds the ready-for-dev readiness gates for issues and linked PRs, adapted to this repository's development workflow (uv, pytest, python, curl), addressing #379.

What was added

  • .github/workflows/issue-readiness-check.yml — manages the ready-for-dev label on issues events:
    • Bugs (bug label): ### Actual Behavior must reference a reproducible command from this repo's supported dev workflow (uv, pytest, python, curl) and ### Acceptance Criteria must contain at least one checklist item.
    • Enhancements (enhancement label): non-empty ### Desired Behavior and ### Acceptance Criteria (with a checklist item).
    • Label add/remove is idempotent; feedback comments are upserted via a hidden marker (at most one per issue), and comments are only posted on open/reopen or on actual label transitions — edits that don't change readiness don't spam.
    • The readiness script's --json mode always exits 0, so a not-ready issue does not abort the workflow under set -euo pipefail — label removal and the feedback comment still run.
    • A refresh-linked-pr-gates job re-runs the PR description check for every open PR linking the issue whenever ready-for-dev is added/removed, so the PR gate never goes stale.
  • .github/workflows/pr-description-check.yml — a pull_request_target gate (checking out trusted base-branch code only) that fails when a PR's linked issues (Fixes #N / Closes #N / Resolves #N, or bare #N under an ## Issue Number heading) are missing ready-for-dev. Bot PRs are exempt; issues created before the rollout date (2026-08-26, day after the expected merge — happy to adjust) are grandfathered so existing work is not blocked retroactively. PRs that link no issues pass.
  • .github/scripts/check_issue_readiness.py, check_pr_description.py, refresh_linked_pr_checks.py, post-readiness-comment.mjs (pattern adapted from OpenHands/software-agent-sdk).
  • .github/ISSUE_TEMPLATE/ — bug and feature-request forms producing the sections the readiness check parses.
  • tests/ — 30 pytest tests for the three Python scripts (readiness criteria, set -euo pipefail-safe exit codes, linked-issue extraction, grandfathering, label-transition refresh logic), loaded via importlib like the SDK repo's tests/cross suite.

Testing

  • uv run pytest tests/test_check_issue_readiness.py tests/test_check_pr_description.py tests/test_refresh_linked_pr_checks.py — 30 passed.
  • Full unit suite: 974 passed (the 341 errors are pre-existing docker.errors from testcontainers-based tests — no Docker daemon in this environment; CI runners have Docker).
  • pre-commit run on all new files: yamlfmt, ruff format/lint, pycodestyle, pyright all pass.
  • Smoke-tested the workflow's shell steps under set -euo pipefail for both ready and not-ready payloads, and the PR gate live against the GitHub API (grandfathered issue passes; nonexistent issue reference fails).

Notes

  • The new workflows only start running once merged to main (issues events and pull_request_target read workflows from the default branch), so they cannot gate this PR itself.
  • After merge, editing or labeling an existing issue will trigger the readiness check; issue Add ready-for-dev issue and PR readiness gates #379 itself predates the rollout cutoff and is grandfathered for PR-gating purposes.

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

@neubig can click here to continue refining the PR

Add an issue readiness workflow that manages the ready-for-dev label via
type-specific criteria (bugs need a reproducible uv/pytest/python/curl
command plus acceptance-criteria checklist; enhancements need desired
behavior plus checklist), with idempotent upserted feedback comments and
not-ready results handled safely under set -euo pipefail.

Add a pull_request_target gate that blocks PRs whose linked issues are
not ready-for-dev (grandfathering pre-rollout issues), re-run for all
linked open PRs whenever the label changes.

Add matching issue forms (bug, feature request) and pytest coverage for
the three CI scripts.

Fixes #379

Co-authored-by: openhands <openhands@all-hands.dev>
@github-actions github-actions Bot added the type: feat A new feature label Aug 24, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Coverage

@all-hands-bot

Copy link
Copy Markdown
Contributor

🤖 OpenHands is reviewing this PR.

Head commit: aec7a94da4acbbb0e5b347b29fd1a8bd6ffffee4
View the conversation: https://oss-agent-canvas.ngrok.dev/conversations/5bf8f7d2-8c7f-461f-938a-c4f81a575ec7

This comment was posted by an AI agent (OpenHands).

@all-hands-bot all-hands-bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This review was created by an AI agent (OpenHands) on behalf of the repository maintainers.

Two material issues, both in the async "refresh" path and the linked-issue gate's 404 handling. The readiness-check core (check_issue_readiness.py), the PR-body parser, and the pull_request_target checkout-from-base security posture all look sound; the 30 new tests pass locally.

Risk assessment

Medium. Neither issue blocks the happy path (issues earn/lose ready-for-dev correctly; PRs linking ready or grandfathered issues gate correctly), but the two findings below cause silent false-negatives/positives in edge cases the PR is explicitly designed to handle.

1. refresh-linked-pr-gates job is missing issues: read (.github/workflows/issue-readiness-check.yml)

The job's permissions block grants only contents: read, pull-requests: read, and actions: write. But refresh_linked_pr_checks.py::_linked_open_prs runs gh api graphql against repository.issue(number).timelineItems, which requires issues: read. Without it the query fails, _run returns nonzero, and _linked_open_prs logs a ::warning:: and returns [] — so the whole "re-run PR description checks so the gate never goes stale" feature silently does nothing. Add issues: read to that job's permissions.

2. A nonexistent linked issue is silently ignored unless every link 404s (.github/scripts/check_pr_description.py)

In validate_linked_issue_ready, a 404 on fetch_issue_details is swallowed with continue, and the "could not be found" error is only emitted when not checked (i.e. all referenced issues 404). So a PR body like Fixes #123 where #123 is a typo or doesn't exist, combined with one valid Fixes #12, passes the gate instead of failing closed. Since the gate's purpose is to keep linked work honest, a nonexistent reference should fail the check regardless of how many other valid links exist. Consider collecting 404'd numbers and reporting them alongside not_ready_new rather than skipping them.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type: feat A new feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants