diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index d9953cd9..c969281a 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -17,6 +17,8 @@ Do not duplicate language-specific rules here. Feature -> develop PRs squash-merge - the PR title becomes the single commit on develop. Develop -> main PRs merge-commit - main's history shows one merge commit per release with develop's tip as the second parent. Titles are descriptive and have no versioning effect - versioning is handled by [Nerdbank.GitVersioning](https://github.com/dotnet/Nerdbank.GitVersioning) reading [version.json](../version.json) and git history, not by parsing commit messages. +`develop` leads `main` by a minor. After a `develop -> main` release lands and main's publish completes, bump the minor in [version.json](../version.json) on `develop` via an isolated `bump-version-X.Y` PR, so develop's prereleases sort above main's last stable. A `develop -> main` promotion that carries only maintenance (not a release) holds main's version instead - `git checkout main -- version.json` on the promotion branch. See [AGENTS.md "Release Model"](../AGENTS.md#release-model). + Branch protection enforces the merge method on both bases (develop allows only squash, main allows only merge). When running `gh pr merge` against either base, pick the matching flag (`--squash` for develop, `--merge` for main); a mismatch fails with "Merge method ... is not allowed on this repository". The merge-bot workflow (`.github/workflows/merge-bot-pull-request.yml`) does this dispatch automatically for Dependabot and codegen PRs via a `case` on `base.ref` - keep that pattern when adding new auto-merge jobs. ### Format diff --git a/AGENTS.md b/AGENTS.md index a71f14b7..409be1fe 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -49,6 +49,9 @@ The template uses a **two-phase model by default**: PRs build fast, publishing i - *Source-only / no build* (validate + tag + release): you need none of the package/image leaf tasks - only your validation in `test-pull-request.yml`, one `release-asset-*` leaf task for the artifact you attach (or zero, if the release is just a tag), and the verbatim `get-version` + `github-release` + `date-badge` orchestration. - `get-version-task.yml` installs the .NET SDK only because NBGV needs the runtime to compute the version/tag - heavyweight but expected even for a non-.NET downstream; acceptable as-is. - **No-op republish guarantee.** A weekly/dispatch publish where NBGV `SemVer2` is **unchanged** (no new commit since the last publish) re-pushes **nothing** to GitHub Releases (the `github-release` job's `release-exists` check skips the create step), NuGet (`dotnet nuget push --skip-duplicate`), or PyPI (`gh-action-pypi-publish` `skip-existing: true`) - all three key on the version string. **Docker always re-pushes** by design: it picks up upstream base-image refreshes (e.g. `ubuntu:rolling`) that aren't visible in the repo. Boundary: `version.json` has **no `pathFilters`**, so *any* commit - including a CI/workflow-only or docs-only change - advances the NBGV git height and therefore `SemVer2`, and the next publish *does* create a fresh release for it even when the shipped binary is byte-identical. This is accepted NBGV behavior; `pathFilters` are intentionally not added. +- **Versioning is semantic and maintainer-controlled.** The `version` (major.minor) in [`version.json`](./version.json) is the version floor; NBGV appends the git height (the SemVer patch position) for the build version. `main` (the public release ref) builds a stable `X.Y.`; `develop` builds a prerelease `X.Y.-g`. The maintainer edits `version.json`; dependency bumps, CI/workflow fixes, doc edits, and template re-syncs leave it untouched. + - **`develop` leads `main` by a minor.** After a `develop -> main` release lands and main's publish completes, bump the minor in `version.json` on `develop` in an isolated `bump-version-X.Y` PR (squash to develop). This keeps every develop prerelease numerically above main's last stable: at a shared `X.Y`, develop's prerelease `X.Y.-g` sorts *below* main's stable `X.Y.` in `--version`, `HISTORY.md`, and consumer update prompts, and the lead avoids that. + - **A maintenance `develop -> main` promotion holds main's version.** Catch-up work - dependency bumps, CI/doc fixes, template re-syncs - reaches `main` without releasing develop's leading minor: run `git checkout main -- version.json` on the promotion branch before opening the PR, so `main`'s stable advances only its NBGV height (the patch position), not its minor, and `develop` keeps its lead. A release promotion instead carries develop's version to `main`, and `develop` then bumps again to restore the lead. ## Pull Request Title and Commit Message Conventions diff --git a/README.md b/README.md index b6334339..01a0317e 100644 --- a/README.md +++ b/README.md @@ -571,6 +571,7 @@ See [AGENTS.md "Branching Model"](./AGENTS.md#branching-model) for the authorita - Feature -> `develop`: **squash-merge** (develop ruleset enforces this; develop is kept linear). - `develop` -> `main`: **merge-commit** (preserves develop's commit list as a real second-parent reference on main; main ruleset enforces this). - **`develop` is forward-only.** No `main -> develop` back-merges. The develop squash-only ruleset physically blocks merge commits. +- **A `develop -> main` release requires a develop version bump right after.** Once the merge lands and main's publish completes, raise the `version` minor in [`version.json`](./version.json) on `develop` via an isolated `bump-version-X.Y` PR, so develop's prereleases stay numerically above main's last stable. A `develop -> main` promotion that carries only maintenance (not a release) holds main's version instead (`git checkout main -- version.json` on the promotion branch). See [AGENTS.md "Release Model"](./AGENTS.md#release-model). - **Bots open parallel PRs against both branches.** [`.github/dependabot.yml`](./.github/dependabot.yml) duplicates each ecosystem entry per branch, and [`.github/workflows/run-codegen-pull-request-task.yml`](./.github/workflows/run-codegen-pull-request-task.yml) runs as a matrix (branch names `codegen-main` and `codegen-develop`). Each branch absorbs its own bot PRs independently - neither falls behind, no back-merges needed. - **Review-then-merge loop.** Every PR is reviewed by GitHub Copilot. The agent pushes, re-requests a review on the new head (via the `requestReviews` GraphQL mutation), addresses and resolves each finding, repeats until green, and then **waits for the maintainer's explicit permission to merge** - it does not self-merge. See [AGENTS.md "PR Review Etiquette"](./AGENTS.md#pr-review-etiquette) and the [Copilot Review Runbook](./.github/copilot-instructions.md#github-copilot-review-runbook) for the mechanics.