Skip to content
Draft
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
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
---
applyTo: "**/Directory.Packages.props,**/*.csproj,**/Directory.Build.props,**/*.nuspec"
---
# Choosing Package Versions in Multi-Targeted Projects
# Choosing Third-Party Package Dependency Versions

Guidance for choosing NuGet package versions in multi-targeted projects (e.g. `net462;net8.0;net9.0`).
Guidance for choosing versions of **external (third-party) NuGet package dependencies** in multi-targeted projects (e.g. `net462;net8.0;net9.0`).

> **Scope:** This document covers dependencies consumed from NuGet — packages the SqlClient repo does NOT own. For versioning of SqlClient's own inter-sibling packages (Logging, Abstractions, SqlClient, Azure, AKV Provider, SqlServer.Server), see `sqlclient-package-versions.instructions.md`.

## Rule
For runtime-aligned packages, **the package major must match the target runtime major**: 8.x on `net8.0`, 9.x on `net9.0`, 10.x on `net10.0`, and so on. TFMs that aren't tied to a specific runtime major (`net462`, `netstandard2.0`) get the major of the floor LTS. Other categories are versioned as described below.
Expand Down
22 changes: 10 additions & 12 deletions .github/instructions/onebranch-pipeline-design.instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,9 @@ Defined in `stages/build-stages.yml`. Four build stages plus validation, ordered
Each build job copies PDB files into `$(JOB_OUTPUT)/symbols/` so they are included in the auto-published pipeline artifact alongside the NuGet packages in `$(JOB_OUTPUT)/packages/`.

Stage conditional rules:
- Wrap stages/jobs in `${{ if }}` compile-time conditionals based on build parameters
- `buildSqlClient` controls Stages 2, 3, validation, and Logging (when AKV is disabled)
- `buildAKVProvider AND buildSqlClient` controls Stage 4
- `buildSqlServerServer` controls SqlServer.Server job in Stage 1
- Logging builds when `buildAKVProvider OR buildSqlClient` is true
- The SqlClient family (Logging, Abstractions, SqlClient, Azure, AKV Provider) is **always built** — Stages 2, 3, and 4 and the Logging job in Stage 1 are unconditional. There is no `buildSqlClient`/`buildAKVProvider` toggle.
- `buildSqlServer` is the only build toggle; it controls just the SqlServer.Server job in Stage 1.
- When `buildSqlServer` is true, SqlClient/AKV depend on the freshly-built SqlServer artifact (downloaded into the local feed). When false, they depend on the most recently published SqlServer package — a version-only dependency (no artifact download) restored from NuGet.

## Job Templates

Expand All @@ -62,7 +60,8 @@ When adding a new package to the OneBranch flow:

- Defined in `stages/publish-symbols-stage.yml`; produces stage `publish_symbols`
- Entire stage excluded at compile time when `publishSymbols` is false
- `dependsOn` is conditional based on which `build*` parameters are set, mirroring the build stage dependency graph
- The SqlClient family symbols are always published; the SqlServer.Server symbols job is conditional on `buildSqlServer`
- `dependsOn` covers all family build stages (always present), plus `build_independent` for SqlServer
- One job per package (`publish-symbols-job.yml`), each downloading its build artifact and publishing PDBs from `symbols/`
- Each package's PDBs are published separately with unique artifact names and version information
- Build jobs copy PDBs into `$(JOB_OUTPUT)/symbols/` so they are included in the auto-published artifact
Expand All @@ -88,16 +87,15 @@ When adding a new package to the OneBranch flow:

## Parameters

Build parameters (all boolean, default `true`):
Build parameters:
- `debug` — enable debug output (default `false`)
- `isPreview` — use preview version numbers (default `false`)
- `publishSymbols` — publish symbols to servers (default `false`)
- `buildSqlServerServer` — build SqlServer.Server package
- `buildSqlClient` — build SqlClient, Extensions.Azure, Abstractions, and Logging
- `buildAKVProvider` — build AKV Provider (requires `buildSqlClient`)
- `buildSqlServer` — build the Microsoft.SqlServer.Server package (default `true`). The SqlClient family is always built, so this is the only build toggle. It also drives the SqlServer dependency version the family uses (built/next vs published).

Release parameters (all boolean, default `false`):
- `releaseSqlServerServer`, `releaseLogging`, `releaseAbstractions`, `releaseSqlClient`, `releaseAzure`, `releaseAKVProvider`
Release parameters (boolean, default `false`):
- `releaseSqlClient` — release the entire SqlClient family together (Logging, Abstractions, SqlClient, Azure, AKV Provider) at the shared version
- `releaseSqlServer` — release Microsoft.SqlServer.Server (versioned separately)

Official-only parameter:
- `releaseToProduction` — controls both NuGet target feed and symbol server destination (default `false`):
Expand Down
154 changes: 154 additions & 0 deletions .github/instructions/sqlclient-package-versions.instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
---
applyTo: "**/Versions.props,build.proj,eng/pipelines/**/*.yml"
---
# SqlClient Package Version Resolution

How package versions are determined across different build scenarios for the packages in this repository.

## Package families

The repository ships two independently-versioned units:

- **The SqlClient family** — `Microsoft.Data.SqlClient` plus the packages that version in lockstep with
it: `Microsoft.Data.SqlClient.Internal.Logging`, `Microsoft.Data.SqlClient.Extensions.Abstractions`,
`Microsoft.Data.SqlClient.Extensions.Azure`, and
`Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider`. **All family packages use the
SqlClient version numbers** — the same NuGet package version, file version, and assembly version —
and are always built and released together.
- **`Microsoft.SqlServer.Server`** — versioned and released on its own cadence.

## Version Properties

The SqlClient family version lives in `src/Microsoft.Data.SqlClient/Versions.props`, which is imported
for every project by `src/Directory.Build.props` (so the `SqlClient*` version properties are always
available). `Microsoft.SqlServer.Server` declares its own version in its own `Versions.props`.

| Property | Applies to | Purpose | Example |
|----------|-----------|---------|---------|
| `SqlClientNextVersion` | SqlClient family | Version being developed; used for the next release | `7.1.0-preview1` |
| `SqlServerNextVersion` | SqlServer | Version being developed for SqlServer | `1.1.0-preview1` |
| `SqlServerPublishedVersion` | SqlServer | Last SqlServer version shipped to NuGet | `1.0.0` |

The SqlClient family always ships its next version, so there is **no** family `PublishedVersion`. Only
`Microsoft.SqlServer.Server` keeps a published version (used when it is built as a SqlClient dependency
but not itself released).

## Resolution Logic

Each `Versions.props` uses a 3-tier `<Choose>` block:

| Priority | Condition | PackageVersion | FileVersion |
|----------|-----------|----------------|-------------|
| 1 | `<Pkg>PackageVersion` explicitly provided | Used as-is | Strip prerelease + append BuildNumber |
| 2 | `BuildNumber` provided (non-zero) | `NextVersion[-BuildSuffix+BuildNumber]` | `NextVersion.Split('-')[0].BuildNumber` |
| 3 | Nothing provided | `NextVersion-dev` | `NextVersion.Split('-')[0].0` |

For every family package, `<Pkg>` is `SqlClient` (e.g. `-p:SqlClientPackageVersion=...`); for
Microsoft.SqlServer.Server it is `SqlServer`.

## Scenarios

### Developer (local `dotnet build`)

**Mode:** Project (default `ReferenceType=Project`)

- No `BuildNumber`, no `BuildSuffix`, no `PackageVersion*` passed.
- Falls into Priority 3 (the `<Otherwise>` branch).
- **Result:** `7.1.0-preview1-dev` / FileVersion `7.1.0.0`
- Dependencies are project references — no package versions needed for siblings.

**Mode:** Package (`-p:ReferenceType=Package`)

- Same version resolution for the package being built.
- Sibling dependencies are restored from local `packages/` feed (previously packed with `-dev` suffix).
- A developer would first `dotnet build build.proj -t:Pack` to produce local packages, then consume them.

### PR Pipeline (non-official CI)

**`buildSuffix`** set via core template parameter:
- `buildSuffix: 'pr'` (passed explicitly from PR pipeline)
- `BuildNumber` = `$(DayOfYear)$(Rev:rr)` (e.g. `15401` for day-of-year 154, run 01)

**Mode:** Project (typical PR validation)

- Versions computed in `compute-versions-ci-stage.yml` (runs `GetVersions*` targets with `-p:BuildSuffix=pr -p:BuildNumber=...`)
- Falls into Priority 2 with BuildSuffix present.
- **Result:** `7.1.0-preview1-pr15401` / FileVersion `7.1.0.15401`
- Dependencies are project references — all packages built together in-tree.
Comment thread
paulmedynski marked this conversation as resolved.

**Mode:** Package (PR package-ref validation)

- Same version computation via compute-versions stage.
- Downstream stages define stage-level variables from compute-versions output using `$[ stageDependencies... ]`.
- Each build step receives an explicit family `-p:SqlClientPackageVersion=<value>` (and `-p:SqlServerPackageVersion=` where needed), hitting Priority 1.
- Sibling dependencies consumed from pipeline artifacts published by upstream stages.

### CI Pipeline (non-official, triggered on merge)

Same structure as PR but passes `buildSuffix: 'ci'` explicitly.

- **Result:** `7.1.0-preview1-ci15401` / FileVersion `7.1.0.15401`

### OneBranch Pipeline (official)

**Mode:** Always Package (`ReferenceType=Package`)

Uses the full `compute-versions-stage.yml` machinery:

#### Step A: Compute Versions (dedicated early stage)

1. Runs the `GetVersionsSqlClient` and `GetVersionsSqlServer` MSBuild targets against `build.proj`.
2. Each target calls `dotnet build <project> -getProperty:<Pkg>PackageVersion` with `BuildNumber` but **no BuildSuffix**.
3. Falls into Priority 2 without BuildSuffix → `PackageVersion = NextVersion` as-is (e.g. `7.1.0-preview1`).
4. `GetVersionsSqlServer` also extracts `SqlServerPublishedVersion` (the SqlClient family has no published version).

#### Step B: Resolve Effective Versions

- The **SqlClient family** always uses `SqlClientNextVersion`.
- **`Microsoft.SqlServer.Server`** uses its next or published version based on the
`releaseSqlServer` boolean:

| `releaseSqlServer` | Effective SqlServer Version | Meaning |
|--------------------------|-----------------------------|---------|
| `True` | `SqlServerNextVersion` (e.g. `1.1.0-preview1`) | SqlServer is being released |
| `False` | `SqlServerPublishedVersion` (e.g. `1.0.0`) | Only built as a SqlClient dependency; use last-shipped |

These are published as ADO output variables: `versions.SqlClientPackageVersion`,
`versions.SqlServerPackageVersion`, and their `*FileVersion` counterparts.

#### Step C: Build Stages Consume Pre-computed Versions

Each downstream build job receives:
- `packageVersion` parameter → passed as `-p:SqlClientPackageVersion=<value>` (or `-p:SqlServerPackageVersion=` for SqlServer)
- Dependency versions → family dependencies use the shared `SqlClientPackageVersion`; the SqlServer dependency uses `SqlServerPackageVersion`

Since an explicit `<Pkg>PackageVersion` is provided, Versions.props hits Priority 1 — uses the value verbatim.

#### Summary

| Package | Version Source | Example |
|---------|----------------|---------|
| SqlClient family (always released together) | `SqlClientNextVersion` | `7.1.0-preview1` |
| SqlServer, being released | `SqlServerNextVersion` | `1.1.0-preview1` |
| SqlServer, dependency only | `SqlServerPublishedVersion` | `1.0.0` |

## Key Architectural Difference

| Scenario | Who computes versions | How dependencies get versions |
|----------|----------------------|-------------------------------|
| Developer | Versions.props inline (Priority 3) | Project references (no version needed) |
| PR/CI (Project) | `compute-versions-ci-stage` up-front | Project references (no version needed) |
| PR/CI (Package) | `compute-versions-ci-stage` up-front | Stage variables via `$[ stageDependencies... ]` → `-p:SqlClientPackageVersion=` / `-p:SqlServerPackageVersion=` |
| OneBranch | `compute-versions-stage` up-front | Explicit `-p:SqlClientPackageVersion=` / `-p:SqlServerPackageVersion=` from stage outputs |

## Updating Versions

After releasing the **SqlClient family**:
1. Update `SqlClientNextVersion` in `src/Microsoft.Data.SqlClient/Versions.props` to the next planned
version. (There is no family published version to update.)

After releasing **`Microsoft.SqlServer.Server`**:
1. Update `SqlServerPublishedVersion` to the version just shipped.
2. Update `SqlServerNextVersion` to the next planned version.

The SqlServer properties live in `src/Microsoft.SqlServer.Server/Versions.props`.
Loading
Loading