|
| 1 | +# Validate PR |
| 2 | + |
| 3 | +Advisory validation for non-maintainer pull requests against contribution guidelines. Posts a single friendly comment when a PR doesn't reference an issue with prior maintainer discussion. **PRs are never closed, and no labels are applied.** |
| 4 | + |
| 5 | +## What it does |
| 6 | + |
| 7 | +For PRs from non-maintainer authors, the action checks that the PR body references a GitHub issue where the PR author and a maintainer have discussed the approach. When that's not the case, the action posts one short advisory comment inviting the contributor to start with an issue. Maintainers (`admin` or `maintain` role) and a hard-coded list of trusted bots are exempt. |
| 8 | + |
| 9 | +Small PRs (< 100 lines changed, excluding lock files) are skipped entirely — typo fixes and tiny bug fixes don't need to go through the issue-discussion loop. |
| 10 | + |
| 11 | +## Usage |
| 12 | + |
| 13 | +Create `.github/workflows/validate-pr.yml` in your repository: |
| 14 | + |
| 15 | +```yaml |
| 16 | +name: Validate PR |
| 17 | + |
| 18 | +on: |
| 19 | + pull_request_target: |
| 20 | + types: [opened] |
| 21 | + |
| 22 | +jobs: |
| 23 | + validate-pr: |
| 24 | + runs-on: ubuntu-24.04 |
| 25 | + permissions: |
| 26 | + pull-requests: write |
| 27 | + steps: |
| 28 | + - uses: getsentry/github-workflows/validate-pr@<sha> |
| 29 | + with: |
| 30 | + app-id: ${{ vars.SDK_MAINTAINER_BOT_APP_ID }} |
| 31 | + private-key: ${{ secrets.SDK_MAINTAINER_BOT_PRIVATE_KEY }} |
| 32 | +``` |
| 33 | +
|
| 34 | +Pin to a specific commit SHA (consumers in `getsentry/*` already follow this convention). The `pull-requests: write` permission is needed because the action posts comments on the PR. |
| 35 | + |
| 36 | +## Inputs |
| 37 | + |
| 38 | +| Input | Required | Description | |
| 39 | +|-------|----------|-------------| |
| 40 | +| `app-id` | Yes | GitHub App ID for the SDK Maintainer Bot | |
| 41 | +| `private-key` | Yes | GitHub App private key for the SDK Maintainer Bot | |
| 42 | + |
| 43 | +## Validation rules |
| 44 | + |
| 45 | +### Skipped entirely |
| 46 | + |
| 47 | +- PR author is in the trusted-bot allowlist (Dependabot, Renovate, Codecov AI, etc.) |
| 48 | +- PR author has `admin`, `maintain`, `push`, or `write` access on the repo |
| 49 | +- PR has fewer than 100 lines changed (`additions + deletions`), excluding common lock files |
| 50 | + |
| 51 | +### Lock files excluded from line counts |
| 52 | + |
| 53 | +Matched by basename, case-insensitive: |
| 54 | + |
| 55 | +| Ecosystem | File | |
| 56 | +|-----------|------| |
| 57 | +| Rust | `Cargo.lock` | |
| 58 | +| JS | `package-lock.json`, `yarn.lock`, `pnpm-lock.yaml` | |
| 59 | +| Python | `Pipfile.lock`, `poetry.lock`, `uv.lock` | |
| 60 | +| Ruby | `Gemfile.lock` | |
| 61 | +| PHP | `composer.lock` | |
| 62 | +| Go | `go.sum` (`go.mod` is hand-edited and stays counted) | |
| 63 | +| Elixir | `mix.lock` | |
| 64 | +| Dart/Flutter | `pubspec.lock` | |
| 65 | +| .NET/NuGet | `packages.lock.json` | |
| 66 | +| CocoaPods | `Podfile.lock` | |
| 67 | +| Nix | `flake.lock` | |
| 68 | + |
| 69 | +### Issue reference check |
| 70 | + |
| 71 | +For PRs that reach validation, the action scans the PR body for issue references in these formats: |
| 72 | + |
| 73 | +- `#123` (same-repo) |
| 74 | +- `getsentry/repo#123` (cross-repo) |
| 75 | +- `https://github.com/getsentry/repo/issues/123` (full URL) |
| 76 | +- With optional keywords: `Fixes #123`, `Closes getsentry/repo#123`, etc. |
| 77 | + |
| 78 | +The PR is considered compliant if **any** referenced issue passes all of: |
| 79 | + |
| 80 | +- The issue is fetchable and in a `getsentry` repository |
| 81 | +- If the issue has assignees, the PR author is one of them |
| 82 | +- Both the PR author and a maintainer have participated in the issue discussion |
| 83 | + |
| 84 | +If no referenced issue passes, the action posts one advisory comment. The PR remains open and reviewable; no labels or status checks are applied. The comment is idempotent — workflow re-runs on the same PR will not produce duplicates. |
| 85 | + |
| 86 | +## Updating from earlier revisions |
| 87 | + |
| 88 | +Earlier revisions of this action closed non-compliant PRs and applied labels (`violating-contribution-guidelines`, `missing-issue-reference`, `missing-maintainer-discussion`, `issue-already-assigned`). The current version does neither — it only posts a comment. |
| 89 | + |
| 90 | +To update an existing consumer: |
| 91 | + |
| 92 | +- Bump the pinned commit SHA to the latest on `main`. |
| 93 | +- Change `types: [opened, reopened]` → `types: [opened]`. |
| 94 | +- Remove any code that reads the `was-closed` output (it no longer exists). |
| 95 | + |
| 96 | +Existing labels on old PRs are not removed automatically. Clean them up with a one-off script if desired. |
0 commit comments