Doorman 為首次貢獻者的 pull request 提供自動檢查回饋
Every first pull request deserves a doorman
James Ngandu 建立 Doorman,一個 GitHub Action,會在貢獻者首次開啟 pull request 時約一秒內檢查內容並留言,肯定已有的優點,並列出需修正或可選事項。
This is a submission for the MLH x DEV Writing Challenge
What I Built
The most fragile moment in open source is not a merge conflict. It is the twenty minutes after someone opens their first pull request.
They have read the code, worked up the nerve, forked, branched, pushed, and written the thing that always feels too short. Then they wait. What usually comes back is silence, because maintainers are busy, or a two-line review that reads like a door closing.
Doorman is a GitHub Action that stands at that door.
When a first-time contributor opens a pull request, Doorman reads it and leaves one comment in about a second. It says what is already good, then lists the few things a maintainer would have asked for anyway:
- a title that says what changed
- a description that explains why
- an issue linked
- a branch name someone can read
- commit messages that mean something
- a change small enough to review
- tests, when code changed
- no binary files that should not be there
Eight checks, no model, no call to a language model API, and nothing outside the Python standard library.
The rules are the point. A contributor's first interaction with a project should not depend on a model's mood. A check that says "your description is 10 characters, add what was wrong and what you changed" is boring, and boring is what trust is made of. You can read every line that decides what the bot says to you.
Three rules shaped the writing more than the code did.
Good news first. Every comment starts with what already works. There is always something.
No review language. No "you must", no "changes requested". A finding is either "needs fixing" or "optional", and the comment says plainly that none of it is a rejection.
A person is still coming. The last line of every comment says a human will read it. The action is a doorman, not a gatekeeper.
There is also a hidden marker in the comment, so if Doorman has already greeted a pull request, a new commit will not set off a second greeting.
The whole thing is about 600 lines of standard library Python with 28 tests, and it runs on pull_request_target with only the permissions it needs. It never checks out or runs code from the fork, which matters when the entire job is to comment on a stranger's branch.
Demo
Here is the real output on a first pull request that is a little rough, the kind that arrives at every project:
Hi @newcontributor, welcome to your first pull request here. Thank you for taking the time.
**4 things worth a look, 4 already good.**
### Already good
- **Commit messages describe the change.**
- **Focused change: 1 file.**
- **No code changed, so no test was needed.**
- **No unexpected binary files.**
### Worth a look
- **The title "Update README.md" does not say what changed.** Vague titles get lost in a busy pull request list.
- Try something like "Fix KeyError when a user has no profile".
- _Needs fixing_
- **The description is very short.** 10 characters.
- Add what was wrong, what you changed, and how you checked it.
- _Needs fixing_
- **No issue linked.** Maintainers use the issue to remember why the change exists.
- If this closes one, add a line like "Closes #42" to the description.
- _Optional_
None of this is a rejection. Push a new commit to the same branch and everything updates, including this note.
On a pull request that already does the basics, it says one line and gets out of the way: Everything I check looks good.
You can run it yourself with no token, against the two recorded payloads in the repo:
python3 -m doorman review --event examples/first_pull_request.json
python3 -m doorman review --event examples/steady_pull_request.json
Repo: github.com/mukuvi/doorman. MIT licensed, tagged v0.1.0. The cover image above is drawn by a script in the repo, because I could not bring myself to pay for a design tool for a weekend project.
Partner Technologies
The partner technology here is GitHub itself: Actions, the REST API, pull_request_target, the token model, and the label system.
Most of the interesting work was in the permissions. A pull request from a fork gets a read-only token by default, which is exactly right, and also means a plain pull_request workflow cannot leave a comment. pull_request_target fixes that, but it runs in the context of the base repository, so checking out the fork becomes a security decision. Doorman never checks out the fork. It reads the event payload, calls the API for the changed files and commits, and posts a comment. Two write permissions, and no code execution.
I also used the label API to add a first-time-contributor label, so a maintainer can filter for the exact people who need a slower, kinder review.
I did not use Auth0 or Tiger Data this time, even though both were on the week's schedule. Doorman has no users to authenticate and no rows to store. Adding either would have been decoration.
Hackathon Experience
I built this during Global Hack Week: Builders Week, the MLH week that runs November 6 to 12.
The theme is building, which sounds obvious until you notice how much of a hackathon is usually setup. Accounts, keys, a database you do not need, an auth flow for a demo with no users. I wanted the opposite of that: one repository, one action, one file you can read in an evening.
Building from Nairobi means the livestreams land late. Most of my work happened after eleven at night, with the workshop recordings open in one window and a terminal in the other. I had the GitHub Copilot session running while I wrote the checks, which is a strange way to spend an evening about automation: writing careful deterministic rules while someone on screen demonstrates the opposite.
What I will remember is finishing. A hackathon project that still makes sense on the Monday after is rare, and this one is small enough to keep. The next step is to run it on a real repository, my own included, and read every comment it writes as if a stranger had written it to me.
If you maintain a project and want to try it, it is one block in a workflow. Tell me what it says that it should not, or what it misses.
來源:DEV Community · dev.to