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
11 changes: 10 additions & 1 deletion .github/workflows/release.md → .github/release-process.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ The following process is used when publishing new releases to NuGet.org.

## 2. Prepare the release

From a local clone of the repository, use Copilot CLI to invoke the `prepare-release` skill. The skill assesses the semantic version, bumps the version in [`src/Directory.Build.props`](../../src/Directory.Build.props), runs API compatibility checks, reviews documentation, drafts release notes, and creates a pull request with all release artifacts.
From a local clone of the repository, use Copilot CLI to invoke the `prepare-release` skill. The skill assesses the semantic version, bumps the version in [`src/Directory.Build.props`](../src/Directory.Build.props), runs API compatibility checks, reviews documentation, drafts release notes, and creates a pull request with all release artifacts.

Review the PR, request changes if needed, and merge when ready.

Expand All @@ -20,6 +20,15 @@ After the prepare-release PR is merged, invoke the `publish-release` skill. The

Review the draft release on GitHub, check 'Set as a pre-release' if appropriate, and click 'Publish release'.

## Branching

The `main` branch is the next-MAJOR preview and development line; currently, it produces the `2.0.0-preview.*` series. Nightly `cron` CI on `main` publishes CI-suffixed packages to GitHub Packages.
Long-lived `release/{MAJOR}.x` branches are created on demand when a shipped MAJOR needs servicing releases. Every push to a `release/*` branch publishes a CI-suffixed package to GitHub Packages, so servicing CI packages are commit-driven rather than clock-driven.
Short-lived `release-{version}` branches are local prepare-release work branches that become pull requests, such as `release-2.0.0-preview.1` or `release-1.3.1`.
Official NuGet.org publishes occur only when a GitHub Release is created from a branch's tag.
The prepare-release skill asks for the source/base branch first so the release PR targets the same line it assessed.
For the agent-facing, structured version of these rules, see [release-branches.md](skills/shared-resources/release-branches.md).

## 4. Monitor the Release workflow

- After publishing, a workflow will produce build artifacts and publish the NuGet packages to NuGet.org
Expand Down
28 changes: 18 additions & 10 deletions .github/skills/bump-version/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,21 @@ compatibility: Requires gh CLI with repo access for creating branches and pull r

Assess and bump the SDK version in `src/Directory.Build.props` to prepare for the next release. This skill owns the [Semantic Versioning 2.0.0](https://semver.org/spec/v2.0.0.html) assessment logic — the [SemVer assessment guide](references/semver-assessment.md) is the single source of truth for version assessment criteria used across the release workflow by both the **prepare-release** and **publish-release** skills.

Use the shared [release branch reference](../shared-resources/release-branches.md) for branch roles, previous-release lookup rules, and release work-branch naming.

> **Note**: For comprehensive release preparation — including ApiCompat/ApiDiff, documentation review, and release notes — use the **prepare-release** skill, which incorporates version assessment as part of its broader workflow.

## Process

### Step 1: Read Current Version and Previous Release

Read `src/Directory.Build.props` on the default branch and extract:
Read `src/Directory.Build.props` on the current branch and extract:
- `<VersionPrefix>` — the `MAJOR.MINOR.PATCH` version
- `<VersionSuffix>` — the prerelease suffix, when present

Display the current version to the user.
The candidate version is `{VersionPrefix}` plus `-{VersionSuffix}` when the suffix is present (for example, `2.0.0-preview.1`). Display the current candidate version to the user.

Determine the previous release tag from `gh release list` (most recent **published** release). Draft releases must be ignored — they represent a pending release that has not yet shipped. Use `--exclude-drafts` or filter to only published releases when querying.
Determine the previous release tag from `gh release list` (most recent **published** release). Draft releases must be ignored — they represent a pending release that has not yet shipped. Use `--exclude-drafts` or filter to only published releases when querying. The lookup is branch-aware: from a `release/{MAJOR}.x` branch, restrict candidates to tags matching `v{MAJOR}.*`; from `main`, use the most recent published release globally. See [release-branches.md](../shared-resources/release-branches.md) for details.

### Step 2: Assess and Determine Next Version

Expand All @@ -40,26 +43,31 @@ When context about queued changes is available or can be gathered, assess the ve

#### Default Suggestion (Fallback)

When a quick bump is needed without full change analysis, suggest the next **minor** version:
When a quick bump is needed without full change analysis, suggest based on the candidate version:

- Current `1.0.0` → suggest `1.1.0`
- Current `1.2.3` → suggest `1.3.0`
- **Stable candidate** — suggest the next **minor** version:
- Current `1.0.0` → suggest `1.1.0`
- Current `1.2.3` → suggest `1.3.0`
- **Prerelease candidate** — if the suffix starts with an identifier such as `preview.` or `rc.` followed by an integer, suggest incrementing the trailing integer:
- Current `2.0.0-preview.1` → suggest `2.0.0-preview.2`
- Current `2.0.0-rc.1` → suggest `2.0.0-rc.2`

Present the suggestion and let the user confirm or provide an alternative.

Parse the confirmed version into its `VersionPrefix` component.
Parse the confirmed version into its `VersionPrefix` and `VersionSuffix` components. Stable versions have no suffix.

### Step 3: Create Pull Request

1. Create a new branch named `bump-version-to-{version}` (e.g. `bump-version-to-1.1.0`) from the default branch
1. Create a new branch named `bump-version-to-{version}` (e.g. `bump-version-to-1.1.0`) from the current branch
2. Update `src/Directory.Build.props`:
- Set `<VersionPrefix>` to the new version
- Set `<VersionPrefix>` to the confirmed stable component
- Set `<VersionSuffix>` for prerelease versions, or clear it for stable versions; add the element if it is missing
- Update `<PackageValidationBaselineVersion>` if the MAJOR version has changed
3. Commit with message: `Bump version to {version}`
4. Push the branch and create a pull request:
- **Title**: `Bump version to {version}`
- **Label**: `infrastructure`
- **Base**: default branch
- **Base**: the current branch (which, for a servicing branch like `release/1.x`, is that servicing branch — not `main`)

### Step 4: Confirm

Expand Down
31 changes: 25 additions & 6 deletions .github/skills/bump-version/references/semver-assessment.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,31 @@ Recommend a PATCH version increment if no MAJOR or MINOR criteria are met.
- MINOR: `MAJOR.(MINOR+1).0`
- PATCH: `MAJOR.MINOR.(PATCH+1)`

**Examples** from previous release `v1.2.0`:
### Prereleases

| Level | Recommended |
|-------|-------------|
| PATCH | `v1.2.1` |
| MINOR | `v1.3.0` |
| MAJOR | `v2.0.0` |
While the candidate version uses a prerelease suffix (e.g., `X.Y.Z-preview.N`, `X.Y.Z-rc.N`), the recommended next version increments the trailing integer of the suffix: `preview.3` → `preview.4`, `rc.1` → `rc.2`.

Going to GA drops the suffix entirely: `2.0.0-rc.2` → `2.0.0`.

This is purely about how to *compute* the next version. It does **not** declare any new policy about what kinds of changes are permitted between previews — refer to the existing [versioning documentation](../../../../docs/versioning.html) for breaking-change policy.

### Branch context

The "previous release" lookup is constrained to tags matching `v{MAJOR}.*` when assessing from a `release/{MAJOR}.x` servicing branch. On `main`, the lookup is unconstrained (most recent published release globally).

The MAJOR/MINOR/PATCH classification criteria above are unchanged regardless of branch.

See [release-branches.md](../../shared-resources/release-branches.md) for branch-role definitions and previous-release lookup rules.

**Examples**:

| Previous release | Branch | Level | Recommended |
|--------------------|---------------|-----------------------|------------------------|
| `v1.2.0` | `main` | PATCH | `v1.2.1` |
| `v1.2.0` | `main` | MINOR | `v1.3.0` |
| `v1.2.0` | `main` | MAJOR | `v2.0.0` |
| `v2.0.0-preview.1` | `main` | (prerelease bump) | `v2.0.0-preview.2` |
| `v1.3.0` | `release/1.x` | PATCH | `v1.3.1` |

## Comparing Against the Candidate Version

Expand All @@ -83,6 +101,7 @@ Present the assessment as a summary table followed by a rationale:

| Aspect | Finding |
|--------|---------|
| Branch context | release/1.x |
| Previous release | v1.0.0 |
| Breaking changes | None confirmed |
| New API surface | Yes — 3 PRs add new public APIs |
Expand Down
Loading