Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,10 @@ Treat this file as authoritative for everything else; don't restate its rules el
- `develop` → `main` is **merge-commit only** (no squash, no rebase). Merge commits preserve develop's commit list as a real second-parent reference on main, which is what makes the "release on every push" model attribute releases to the develop commits that produced them. Branch protection enforces this: the develop ruleset allows only `squash`, the main ruleset allows only `merge`.
- All commits on both branches must be cryptographically signed (SSH or GPG). Squash and merge commits created via the GitHub UI are signed by GitHub's web-flow key.
- **`develop` is forward-only — no `main → develop` back-merges.** The develop ruleset's squash-only setting physically blocks merge commits on develop. Historical back-merge commits visible in `git log` (`b9b0447`, `410ba56`, `ffb9e64`, `5ce95cf`, etc.) predate this rule and must not be repeated.
- **Main ruleset intentionally omits "Require branches to be up to date before merging".** This GitHub branch-protection check is graph-based — it asks whether main's tip commit is reachable from develop, not whether the two branches have the same content. After any develop → main release, main's tip is a brand-new merge commit that develop's history doesn't contain. Forward-only develop never adds it (no back-merge of main into develop), so the check would fail on every subsequent release. Other technical workarounds — rebasing develop onto main, or rewriting develop's history — exist but contradict the squash-only develop ruleset and the linearity invariant. The develop ruleset keeps the "up to date" check on (it's normal hygiene for feature → develop merges); only the main ruleset omits it. See [`README.md`](./README.md#template---github-setup) "Rules / Rulesets" for the configured state.
- **Both rulesets intentionally omit "Require branches to be up to date before merging".** The flag is off on `main` and on `develop`, for related but distinct reasons.
- *Main:* the check is graph-based — it asks whether main's tip commit is reachable from develop, not whether the two branches have the same content. After any develop → main release, main's tip is a brand-new merge commit that develop's history doesn't contain. Forward-only develop never adds it (no back-merge of main into develop), so the check would fail on every subsequent release. Other technical workarounds — rebasing develop onto main, or rewriting develop's history — exist but contradict the squash-only develop ruleset and the linearity invariant.
- *Develop:* the check stalls bot auto-merge when two bot PRs against develop land within the same window. As soon as the first merges, the second flips to `mergeStateStatus: BEHIND` and GitHub's auto-merge will not fire while strict is on. The merge-bot only *enables* auto-merge on `opened`/`reopened` (see below) and never auto-updates bot branches, and Dependabot's rebase isn't real-time, so the second PR sits OPEN with all checks green indefinitely. Squash mechanics still rebase the diff onto develop's tip on merge, `required_linear_history` still enforces linearity, textual conflicts still block `mergeable: CONFLICTING`, and the required `Check pull request workflow status` still gates merges — the only thing lost is pre-merge detection of *semantic-but-not-textual* conflicts, which the post-merge develop CI run catches anyway.
- See [`README.md`](./README.md#template---github-setup) "Rules / Rulesets" for the configured state.
- **Bots (Dependabot and codegen) target both `main` and `develop` in parallel.** [`.github/dependabot.yml`](./.github/dependabot.yml) duplicates every ecosystem entry (one per branch) and [`.github/workflows/run-codegen-pull-request-task.yml`](./.github/workflows/run-codegen-pull-request-task.yml) runs as a matrix over both branches with branch names `codegen-main` and `codegen-develop`. Each branch absorbs its own bot PRs independently, so neither falls behind, and the forward-only rule still holds (nothing is back-merged from main to develop — both branches receive their updates directly). The merge-bot ([`.github/workflows/merge-bot-pull-request.yml`](./.github/workflows/merge-bot-pull-request.yml)) dispatches `--squash` or `--merge` from each PR's base ref via a `case` statement so the form matches the ruleset on either base. Dependabot **security** PRs (CVE-driven) always open against the repo default branch (`main`) regardless of `target-branch` — the same `case` statement covers them.
- **Maintainer-pushed commits on a bot PR auto-disable auto-merge.** The merge-bot's `merge-dependabot` and `merge-codegen` jobs only fire on `opened` / `reopened` events (auto-merge is enabled exactly once per PR). When a maintainer pushes commits to a bot's branch (a `synchronize` event with an actor that isn't the same bot), the merge-bot's `disable-auto-merge-on-maintainer-push` job fires and calls `gh pr merge --disable-auto`. The maintainer's commits stay in the PR but won't auto-merge with the bot's content; re-enable auto-merge manually (`gh pr merge --auto <PR>` or the GitHub UI) when ready.
- **Why parallel dual-target rather than develop-only with eventual flow-through:** push-distribution channels (HACS for Home Assistant integrations, Linux distros that vendor from `main`, etc.) consume `main` directly. A develop-only model would leave `main` running stale code during long-running develop features. Codegen content can also be production-critical (live API-derived data, language lists, build catalogs) rather than just sample/demo content, so both branches need fresh codegen on their own cadence.
Expand Down
8 changes: 3 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ C# .NET project template.
[![Docker Latest][dockerlatestversion-shield]][docker-link]\
[![Docker Develop][dockerdevelopversion-shield]][docker-link]\
[![NuGet Release][nugetreleaseversion-shield]][nuget-link]\
[![NuGet Pre-Release][nugetprereleaseversion-shield]][nuget-link]\
[![PyPI Release][pypireleaseversion-shield]][pypi-link]

### Release Notes
Expand Down Expand Up @@ -478,12 +477,12 @@ Licensed under the [MIT License][license-link]\
- `Allow rebase merging` — disabled (no flow uses it; the develop ruleset forbids it anyway)
- `Always suggest updating pull request branches`
- `Allow auto-merge`
- Rules / Rulesets — **separate rulesets per branch**. Develop and main intentionally diverge on three rules — allowed merge methods, `Require linear history`, and `Require branches to be up to date before merging`; everything else is shared.
- Rules / Rulesets — **separate rulesets per branch**. Develop and main intentionally diverge on two rules — allowed merge methods and `Require linear history`. `Require branches to be up to date before merging` is **off on both** for related-but-distinct reasons (below); everything else is shared.
- "Develop":
- Target branches: `develop`.
- Allowed merge methods: `Squash`
- `Require linear history` (develop is kept linear; main carries merge commits by design, so this setting belongs to develop only)
- `Require status checks to pass` → `Require branches to be up to date before merging` ✓ (feature branches must rebase or merge develop before merging back — standard hygiene)
- `Require status checks to pass` → `Require branches to be up to date before merging` **intentionally OFF**. Leaving it on stalls bot auto-merge when two bot PRs against develop land within the same window — the first merge flips the second to `mergeStateStatus: BEHIND`, and GitHub's auto-merge will not fire while strict is on. The merge-bot in [`.github/workflows/merge-bot-pull-request.yml`](./.github/workflows/merge-bot-pull-request.yml) only enables auto-merge on `opened`/`reopened` and never auto-updates bot branches; Dependabot's rebase isn't real-time. With strict off, squash mechanics still rebase the diff onto develop's tip on merge, `Require linear history` still enforces linearity, textual conflicts still block `mergeable: CONFLICTING`, and the required `Check pull request workflow status` still gates merges. See [AGENTS.md "Branching Model"](./AGENTS.md#branching-model) for the full reasoning.
- Plus shared settings (below).
- "Main":
- Target branches: `main`.
Expand Down Expand Up @@ -558,9 +557,8 @@ For an example of the manual-release model in production, see [homeassistant-pur
[license-link]: ./LICENSE
[license-shield]: https://img.shields.io/github/license/ptr727/ProjectTemplate?label=License
[nuget-link]: https://www.nuget.org/packages/ptr727.ProjectTemplate.Library/
[nugetprereleaseversion-shield]: https://img.shields.io/nuget/vpre/ptr727.ProjectTemplate.Library?logo=nuget&label=NuGet%20Pre-Release&color=orange
[nugetreleaseversion-shield]: https://img.shields.io/nuget/v/ptr727.ProjectTemplate.Library?logo=nuget&label=NuGet%20Release
[prereleaseversion-shield]: https://img.shields.io/github/v/release/ptr727/ProjectTemplate?include_prereleases&label=GitHub%20Pre-Release&logo=github
[prereleaseversion-shield]: https://img.shields.io/github/v/release/ptr727/ProjectTemplate?include_prereleases&filter=*-g*&label=GitHub%20Pre-Release&logo=github
[pypi-link]: https://pypi.org/project/ptr727-projecttemplate-library/
[pypireleaseversion-shield]: https://img.shields.io/pypi/v/ptr727-projecttemplate-library?logo=pypi&label=PyPI%20Release
[releasebuildstatus-shield]: https://img.shields.io/github/actions/workflow/status/ptr727/ProjectTemplate/publish-release.yml?logo=github&label=Releases%20Build
Expand Down
Loading