Skip to content

Commit 74758d7

Browse files
mschmickingclaude
andcommitted
docs: fix a ruleset setting that would make main unmergeable
Reviewing the exported rule found required_approving_review_count: 1 on a solo repository. GitHub does not allow approving your own pull request, and a ruleset with an empty bypass list does not exempt repository admins, so nothing could ever have been merged — including Dependabot updates and the release-please PR. Zero approvals still forces the PR flow, which is what makes the checks run. The rule also permitted merge and rebase alongside squash. The repository setting is only a default and can be switched back; the ruleset is what holds, so it should allow squash alone. Adds docs/main-ruleset.json as an importable copy, and corrects the note about availability: the ruleset can be created on a private free repo, it simply is not enforced until the repository is public. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1 parent 4dd6f3c commit 74758d7

2 files changed

Lines changed: 62 additions & 9 deletions

File tree

docs/GOING-PUBLIC.md

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,11 @@ Work top to bottom. The ordering in step 4 matters.
1212

1313
These change how merges behave, and the release automation depends on them.
1414

15-
> **Branch protection is not in this section on purpose.** On the free plan it is
16-
> unavailable for private repositories — the API answers "Upgrade to GitHub Pro or make
17-
> this repository public to enable this feature". It has to wait until step 5.
15+
> **Branch protection can be created now but will not be enforced yet.** GitHub warns
16+
> "Your rulesets won't be enforced on this private repository until you move to a GitHub
17+
> Team organization account". Reading it back over the API also 403s on the free plan.
18+
> So configure it whenever you like — it starts working the moment the repo is public.
19+
> `docs/main-ruleset.json` is a ready-to-import copy.
1820
1921
- [ ] **Settings → General → Pull Requests**
2022
- [ ] Enable **Allow squash merging**
@@ -123,17 +125,27 @@ Things that only start working once the repository is public:
123125
- [ ] **Branch protection** — now available, since the repository is public.
124126
**Settings → Rules → Rulesets → New branch ruleset**:
125127

126-
- Name: `main` (the name is only a label; it appears in the "blocked by" message when
127-
a push is rejected, so something plain is better than something clever)
128+
Import `docs/main-ruleset.json`, or set it by hand:
129+
130+
- Name: `main` (only a label; it appears in the "blocked by" message on a rejected push)
128131
- Enforcement status: **Active**
129132
- Target branches: **Include default branch**
130133
- Rules:
131-
- [ ] Require a pull request before merging (approvals: 0 is fine for a solo project —
132-
it still forces the PR flow so the checks run)
133-
- [ ] Require status checks to pass → add `test (22)`, `test (24)`, `audit`,
134+
- [ ] Require a pull request before merging, **required approvals: 0**
135+
- [ ] Allowed merge methods: **squash only**
136+
- [ ] Require status checks to pass → `test (22)`, `test (24)`, `audit`,
134137
`conventional-commit`, `gitleaks`
135138
- [ ] Require branches to be up to date before merging
136-
- [ ] Block force pushes
139+
- [ ] Block force pushes, block deletions
140+
141+
> **Required approvals must be 0 on a solo repository.** GitHub does not let you approve
142+
> your own pull request, and a ruleset with an empty bypass list does not exempt
143+
> repository admins — so requiring one approval makes `main` permanently unmergeable,
144+
> including for Dependabot and the release PR. Zero still forces the PR flow, which is
145+
> the part that makes the checks run.
146+
>
147+
> **Restrict merge methods to squash here too.** The repository setting is a default
148+
> that can be changed back; the ruleset is the thing that actually holds.
137149
138150
> A status check can only be selected after it has run at least once, so open a
139151
> throwaway PR first if the names do not appear in the picker.

docs/main-ruleset.json

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
{
2+
"name": "Main",
3+
"target": "branch",
4+
"enforcement": "active",
5+
"conditions": {
6+
"ref_name": {
7+
"exclude": [],
8+
"include": ["~DEFAULT_BRANCH"]
9+
}
10+
},
11+
"rules": [
12+
{ "type": "deletion" },
13+
{ "type": "non_fast_forward" },
14+
{
15+
"type": "pull_request",
16+
"parameters": {
17+
"required_approving_review_count": 0,
18+
"dismiss_stale_reviews_on_push": false,
19+
"required_reviewers": [],
20+
"require_last_push_approval": false,
21+
"required_review_thread_resolution": false,
22+
"allowed_merge_methods": ["squash"]
23+
}
24+
},
25+
{
26+
"type": "required_status_checks",
27+
"parameters": {
28+
"strict_required_status_checks_policy": true,
29+
"do_not_enforce_on_create": false,
30+
"required_status_checks": [
31+
{ "context": "test (22)", "integration_id": 15368 },
32+
{ "context": "test (24)", "integration_id": 15368 },
33+
{ "context": "audit", "integration_id": 15368 },
34+
{ "context": "conventional-commit", "integration_id": 15368 },
35+
{ "context": "gitleaks", "integration_id": 15368 }
36+
]
37+
}
38+
}
39+
],
40+
"bypass_actors": []
41+
}

0 commit comments

Comments
 (0)