diff --git a/.github/instructions/onebranch-pipeline-design.instructions.md b/.github/instructions/onebranch-pipeline-design.instructions.md index 272369dfb5..7a24fd3799 100644 --- a/.github/instructions/onebranch-pipeline-design.instructions.md +++ b/.github/instructions/onebranch-pipeline-design.instructions.md @@ -135,6 +135,7 @@ Variable groups: - Jobs that produce no assemblies (symbol publishing, signed-package validation, version computation) set `ob_sdl_apiscan_enabled: false` rather than reporting a name/version - Each build job also sets `ob_sdl_apiscan_softwareFolder` and `ob_sdl_apiscan_symbolsFolder` to its per-package `apiScan//dlls` and `apiScan//pdbs` paths - CodeQL, SBOM, Policheck (`break: true`): enabled in both pipelines +- SBOM package name/version are resolvable **only** from the pipeline's `globalSdl.sbom` block — OneBranch's artifact-publishing path reads `globalSdl.sbom.packageName`/`packageVersion` directly and has no per-job equivalent (the `templateContext.sdl.sbom` override only applies to the native 1ES Stages entry point, which this repo does not use). Because the pipeline produces six differently-named and independently-versioned packages, `globalSdl.sbom` indirects through the `$(sbomPackageName)` / `$(sbomPackageVersion)` variables, which each build job sets to its own `packageFullName` and computed `packageVersion`. Jobs that publish no packages (version computation, symbol publishing) set `ob_sdl_sbom_enabled: false` alongside their existing APIScan/BinSkim opt-outs, so the variables never need pipeline-level defaults - asyncSdl `enabled: false` in both; individual sub-tools (CredScan, BinSkim, Armory, Roslyn) configured underneath - Policheck exclusions: `$(REPO_ROOT)\.config\PolicheckExclusions.xml` - CredScan suppressions: `$(REPO_ROOT)/.config/CredScanSuppressions.json` diff --git a/.github/instructions/sqlclient-package-versions.instructions.md b/.github/instructions/sqlclient-package-versions.instructions.md index 1692082a68..691367d9de 100644 --- a/.github/instructions/sqlclient-package-versions.instructions.md +++ b/.github/instructions/sqlclient-package-versions.instructions.md @@ -40,7 +40,7 @@ Each `Versions.props` uses a 3-tier `` block: | Priority | Condition | PackageVersion | FileVersion | |----------|-----------|----------------|-------------| | 1 | `PackageVersion` explicitly provided | Used as-is | Strip prerelease + append BuildNumber | -| 2 | `BuildNumber` provided (non-zero) | `NextVersion[-BuildSuffix+BuildNumber]` | `NextVersion.Split('-')[0].BuildNumber` | +| 2 | `BuildNumber` provided (non-zero) | `NextVersion[-BuildSuffix]`, then `.BuildNumber` appended if that carries a prerelease tag | `NextVersion.Split('-')[0].BuildNumber` | | 3 | Nothing provided | `NextVersion-dev` | `NextVersion.Split('-')[0].0` | For every family package, `` is `SqlClient` (e.g. `-p:SqlClientPackageVersion=...`); for @@ -79,7 +79,7 @@ Microsoft.SqlServer.Server it is `SqlServer`. - 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` +- **Result:** `7.1.0-preview1-pr.15401` / FileVersion `7.1.0.15401` - Dependencies are project references — all packages built together in-tree. **Mode:** Package (PR package-ref validation) @@ -93,7 +93,7 @@ Microsoft.SqlServer.Server it is `SqlServer`. Same structure as PR but passes `buildSuffix: 'ci'` explicitly. -- **Result:** `7.1.0-preview1-ci15401` / FileVersion `7.1.0.15401` +- **Result:** `7.1.0-preview1-ci.15401` / FileVersion `7.1.0.15401` ### OneBranch Pipeline (official) @@ -104,8 +104,8 @@ 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 -getProperty:PackageVersion` with `BuildNumber` but **no BuildSuffix**. -3. Falls into Priority 2 without BuildSuffix → `PackageVersion = NextVersion` as-is (e.g. `7.1.0-preview1`). +2. Each target calls `dotnet build -getProperty:PackageVersion` and `-getProperty:FileVersion` with `BuildNumber` but **no BuildSuffix**. +3. Falls into Priority 2 without BuildSuffix. `NextVersion` already carries a prerelease tag on `main`, so the build number is appended (e.g. `7.1.0-preview1.26238.3`); on a release branch the stable `NextVersion` is used as-is (e.g. `7.1.0`). 4. `GetVersionsSqlServer` also extracts `SqlServerPublishedVersion` (the SqlClient family has no published version). #### Step B: Resolve Effective Versions @@ -136,15 +136,12 @@ Each downstream build job receives: Since an explicit `PackageVersion` is provided, Versions.props hits Priority 1 — uses the value verbatim. -#### Package Version Shapes: `addRevision` +#### Package Version Shapes -Both OneBranch pipelines expose `addRevision` (default `false`), which selects between two mutually -exclusive package version shapes. Their human-readable run name is `$(Year:YY)$(DayOfYear)$(Rev:.r)`, -and the compute stage receives both that run name (as `Build.BuildNumber`) and the globally unique -`Build.BuildId` (as the revision). - -**Default path — `addRevision: false`.** The pipeline run name is appended after any prerelease -suffix, reproducing the shape shipped by earlier previews. `Build.BuildId` is not used: +Both OneBranch pipelines use the human-readable run name `$(Year:YY)$(DayOfYear)$(Rev:.r)`, which the +compute stage receives as `Build.BuildNumber`. That run name drives the single supported package +version shape: it is appended after any prerelease suffix, reproducing the shape shipped by earlier +previews. - `1.2.3` stays `1.2.3` — non-preview releases are never stamped with a build number - `1.2.3-preview1` becomes `1.2.3-preview1.`, e.g. `7.1.0-preview3.26238.3` @@ -152,34 +149,15 @@ suffix, reproducing the shape shipped by earlier previews. `Build.BuildId` is no Note the asymmetry: the *package* version omits the build number for non-preview releases, but the *file* version always carries one in its fourth component. This keeps every shipped assembly -date-encoded and traceable to the run that produced it, while preserving the released package -version customers expect. - -**Opt-in path — `addRevision: true`.** Version revisions come from `Build.BuildId` instead, which is -mapped into the unsigned 16-bit file-version range before canonical file versions are evaluated: - -```text -revision = ((Build.BuildId - 1) % 65535) + 1 -``` - -Build IDs `1` through `65535` map directly; subsequent IDs wrap back through that range. The compute -stage logs the mapping whenever wrapping occurs because the revision can then collide with an earlier -run. The mapped value is inserted before any package prerelease suffix so package and file versions -use the same revision: - -- `1.2.3` becomes `1.2.3.` -- `1.2.3-preview1` becomes `1.2.3.-preview1` -- The matching file version is `1.2.3.` - -This shape exists for repeated test publishes of the same base version, where each run needs a -distinct package version. `Build.BuildNumber` is not used on this path. +date-encoded, while preserving the released package version customers expect. -Only packages built in the current run are revised or stamped. When `buildSqlServer` is `false`, the -effective SqlServer version remains `SqlServerPublishedVersion` so dependency restore continues to -request the package that actually exists on NuGet. +The file version's fourth component is only the *date* segment of the run name, because a four-part +file version cannot hold the full `.` value. Repeated runs on the same day therefore share +a file version even though their package versions differ. -An explicit four-part package version is also treated as the complete file version base by both -canonical Versions.props files; they do not append `FileVersionBuildNumber` as a fifth component. +Only packages built in the current run are stamped. When `buildSqlServer` is `false`, the effective +SqlServer version remains `SqlServerPublishedVersion` so dependency restore continues to request the +package that actually exists on NuGet. #### Summary diff --git a/build.proj b/build.proj index 31795fc6a7..2e19233b2a 100644 --- a/build.proj +++ b/build.proj @@ -96,6 +96,21 @@ packages — use PackageVersionSqlClient (below) to set the version for the entire family. --> + + + + -p:SqlClientNextVersion=$(SqlClientNextVersion) + + + + + -p:SqlClientFileVersion=$(FileVersionSqlClient) + + + + + + -p:SqlServerNextVersion=$(SqlServerNextVersion) + + + + + -p:SqlServerFileVersion=$(FileVersionSqlServer) + + - <_Cmd>"$(DotnetPath)dotnet" build "$(SqlClientProjectPath)" -getProperty:SqlClientPackageVersion $(BuildNumberArgument) $(BuildSuffixArgument) + <_Cmd>"$(DotnetPath)dotnet" build "$(SqlClientProjectPath)" -getProperty:SqlClientPackageVersion $(BuildNumberArgument) $(BuildSuffixArgument) $(SqlClientNextVersionArgument) <_Cmd>$([System.Text.RegularExpressions.Regex]::Replace($(_Cmd), "\s+", " ")) - <_Cmd>"$(DotnetPath)dotnet" build "$(SqlClientProjectPath)" -getProperty:SqlClientFileVersion $(BuildNumberArgument) $(BuildSuffixArgument) + <_Cmd>"$(DotnetPath)dotnet" build "$(SqlClientProjectPath)" -getProperty:SqlClientFileVersion $(BuildNumberArgument) $(BuildSuffixArgument) $(SqlClientNextVersionArgument) <_Cmd>$([System.Text.RegularExpressions.Regex]::Replace($(_Cmd), "\s+", " ")) @@ -476,7 +535,7 @@ - <_Cmd>"$(DotnetPath)dotnet" build "$(SqlServerProjectPath)" -getProperty:SqlServerPackageVersion $(BuildNumberArgument) $(BuildSuffixArgument) + <_Cmd>"$(DotnetPath)dotnet" build "$(SqlServerProjectPath)" -getProperty:SqlServerPackageVersion $(BuildNumberArgument) $(BuildSuffixArgument) $(SqlServerNextVersionArgument) <_Cmd>$([System.Text.RegularExpressions.Regex]::Replace($(_Cmd), "\s+", " ")) @@ -486,7 +545,7 @@ - <_Cmd>"$(DotnetPath)dotnet" build "$(SqlServerProjectPath)" -getProperty:SqlServerFileVersion $(BuildNumberArgument) $(BuildSuffixArgument) + <_Cmd>"$(DotnetPath)dotnet" build "$(SqlServerProjectPath)" -getProperty:SqlServerFileVersion $(BuildNumberArgument) $(BuildSuffixArgument) $(SqlServerNextVersionArgument) <_Cmd>$([System.Text.RegularExpressions.Regex]::Replace($(_Cmd), "\s+", " ")) @@ -574,6 +633,7 @@ $(BuildNumberArgument) $(BuildSuffixArgument) $(PackageVersionSqlClientArgument) + $(FileVersionSqlClientArgument) $(ReferenceTypeArgument) @@ -605,6 +665,7 @@ $(BuildNumberArgument) $(BuildSuffixArgument) $(PackageVersionSqlClientArgument) + $(FileVersionSqlClientArgument) $(ReferenceTypeArgument) @@ -636,6 +697,7 @@ $(BuildNumberArgument) $(BuildSuffixArgument) $(PackageVersionSqlClientArgument) + $(FileVersionSqlClientArgument) $(ReferenceTypeArgument) @@ -679,6 +741,7 @@ $(BuildNumberArgument) $(BuildSuffixArgument) $(PackageVersionSqlClientArgument) + $(FileVersionSqlClientArgument) $(ReferenceTypeArgument) @@ -839,6 +902,7 @@ $(BuildNumberArgument) $(BuildSuffixArgument) $(PackageVersionSqlClientArgument) + $(FileVersionSqlClientArgument) $(ReferenceTypeArgument) @@ -866,6 +930,7 @@ $(BuildNumberArgument) $(BuildSuffixArgument) $(PackageVersionSqlClientArgument) + $(FileVersionSqlClientArgument) $(ReferenceTypeArgument) @@ -946,6 +1011,7 @@ $(BuildNumberArgument) $(BuildSuffixArgument) $(PackageVersionSqlClientArgument) + $(FileVersionSqlClientArgument) $(ReferenceTypeArgument) @@ -972,6 +1038,7 @@ $(BuildNumberArgument) $(BuildSuffixArgument) $(PackageVersionSqlClientArgument) + $(FileVersionSqlClientArgument) $(ReferenceTypeArgument) @@ -1051,6 +1118,7 @@ $(BuildNumberArgument) $(BuildSuffixArgument) $(PackageVersionSqlClientArgument) + $(FileVersionSqlClientArgument) $(ReferenceTypeArgument) @@ -1077,6 +1145,7 @@ $(BuildNumberArgument) $(BuildSuffixArgument) $(PackageVersionSqlClientArgument) + $(FileVersionSqlClientArgument) $(ReferenceTypeArgument) @@ -1153,6 +1222,7 @@ $(BuildNumberArgument) $(BuildSuffixArgument) $(PackageVersionSqlClientArgument) + $(FileVersionSqlClientArgument) $([System.Text.RegularExpressions.Regex]::Replace($(DotnetCommand), "\s+", " ")) @@ -1176,6 +1246,7 @@ $(BuildNumberArgument) $(BuildSuffixArgument) $(PackageVersionSqlClientArgument) + $(FileVersionSqlClientArgument) $([System.Text.RegularExpressions.Regex]::Replace($(DotnetCommand), "\s+", " ")) @@ -1219,6 +1290,7 @@ $(BuildNumberArgument) $(BuildSuffixArgument) $(PackageVersionSqlServerArgument) + $(FileVersionSqlServerArgument) $([System.Text.RegularExpressions.Regex]::Replace($(DotnetCommand), "\s+", " ")) @@ -1242,6 +1314,7 @@ $(BuildNumberArgument) $(BuildSuffixArgument) $(PackageVersionSqlServerArgument) + $(FileVersionSqlServerArgument) $([System.Text.RegularExpressions.Regex]::Replace($(DotnetCommand), "\s+", " ")) diff --git a/eng/pipelines/onebranch/jobs/build-buildproj-job.yml b/eng/pipelines/onebranch/jobs/build-buildproj-job.yml index f750ed4b91..824776575d 100644 --- a/eng/pipelines/onebranch/jobs/build-buildproj-job.yml +++ b/eng/pipelines/onebranch/jobs/build-buildproj-job.yml @@ -66,8 +66,9 @@ parameters: type: object default: [] - # Positive unsigned 16-bit revision used by build.proj to derive assembly file versions. - - name: revision + # Assembly file version to stamp (required). Pre-computed by the compute-versions stage so no + # build job re-derives it. The assembly version is derived from this by Versions.props. + - name: fileVersion type: string # The full name of the package. This is used in the job name, and to form DLL and PDB filenames @@ -126,6 +127,13 @@ jobs: ob_sdl_apiscan_softwareName: ${{ parameters.packageFullName }} ob_sdl_apiscan_versionNumber: ${{ parameters.apiScanSoftwareVersion }} + # SBOM identity for this job's artifact. OneBranch reads the SBOM package name/version only + # from the pipeline's globalSdl block, which has no per-job form, so that block indirects + # through these variables and each build job supplies its own values. Jobs that publish no + # packages set ob_sdl_sbom_enabled to false instead. + sbomPackageName: ${{ parameters.packageFullName }} + sbomPackageVersion: ${{ parameters.packageVersion }} + steps: - template: /eng/pipelines/onebranch/steps/script-output-environment-variables-step.yml@self @@ -166,7 +174,7 @@ jobs: parameters: dependencyArguments: $(sqlServerVersionArgument) packageShortName: ${{ parameters.packageShortName }} - revision: ${{ parameters.revision }} + fileVersion: ${{ parameters.fileVersion }} versionPropertySuffix: ${{ parameters.versionPropertySuffix }} packageVersion: ${{ parameters.packageVersion }} @@ -176,7 +184,7 @@ jobs: buildConfiguration: Release dependencyArguments: $(sqlServerVersionArgument) packageShortName: ${{ parameters.packageShortName }} - revision: ${{ parameters.revision }} + fileVersion: ${{ parameters.fileVersion }} versionPropertySuffix: ${{ parameters.versionPropertySuffix }} packageVersion: ${{ parameters.packageVersion }} @@ -224,7 +232,7 @@ jobs: dependencyArguments: $(sqlServerVersionArgument) packageFullName: ${{ parameters.packageFullName }} packageShortName: ${{ parameters.packageShortName }} - revision: ${{ parameters.revision }} + fileVersion: ${{ parameters.fileVersion }} versionPropertySuffix: ${{ parameters.versionPropertySuffix }} packageVersion: ${{ parameters.packageVersion }} diff --git a/eng/pipelines/onebranch/jobs/publish-nuget-package-job.yml b/eng/pipelines/onebranch/jobs/publish-nuget-package-job.yml index cf7dd6a56b..e63c72bf58 100644 --- a/eng/pipelines/onebranch/jobs/publish-nuget-package-job.yml +++ b/eng/pipelines/onebranch/jobs/publish-nuget-package-job.yml @@ -74,6 +74,11 @@ jobs: - name: ob_outputDirectory value: $(JOB_OUTPUT) + # This job republishes an already-built package, whose SBOM came from its build job. It sets + # no sbomPackage* values, so leaving SBOM enabled would emit one with unresolved macros. + - name: ob_sdl_sbom_enabled + value: false + - name: artifactPath value: $(Pipeline.Workspace)/${{ parameters.artifactName }} diff --git a/eng/pipelines/onebranch/jobs/publish-symbols-job.yml b/eng/pipelines/onebranch/jobs/publish-symbols-job.yml index af59e54fc2..ab45b5f4c8 100644 --- a/eng/pipelines/onebranch/jobs/publish-symbols-job.yml +++ b/eng/pipelines/onebranch/jobs/publish-symbols-job.yml @@ -64,6 +64,9 @@ jobs: value: false - name: ob_sdl_binskim_enabled value: false + # No packages are published here, so there is nothing to describe in an SBOM. + - name: ob_sdl_sbom_enabled + value: false # Path where the downloaded artifact will be placed. - name: artifactPath value: '$(Pipeline.Workspace)/${{ parameters.packageFullName }}' diff --git a/eng/pipelines/onebranch/jobs/validate-signed-package-job.yml b/eng/pipelines/onebranch/jobs/validate-signed-package-job.yml index 476bb5de30..818b902cf7 100644 --- a/eng/pipelines/onebranch/jobs/validate-signed-package-job.yml +++ b/eng/pipelines/onebranch/jobs/validate-signed-package-job.yml @@ -53,6 +53,10 @@ jobs: - name: ob_sdl_apiscan_enabled value: false + # Likewise it produces no package, and sets no sbomPackage* values for globalSdl to resolve. + - name: ob_sdl_sbom_enabled + value: false + # Path within the downloaded artifact where NuGet packages are located. - name: artifactPath value: '$(Pipeline.Workspace)\${{ parameters.artifactName }}' diff --git a/eng/pipelines/onebranch/scripts/compute-versions.ps1 b/eng/pipelines/onebranch/scripts/compute-versions.ps1 index 93e8d318aa..4bce0b1495 100644 --- a/eng/pipelines/onebranch/scripts/compute-versions.ps1 +++ b/eng/pipelines/onebranch/scripts/compute-versions.ps1 @@ -12,63 +12,39 @@ The published SqlServer version is needed when SqlServer is not built because downstream SqlClient projects restore that existing package from NuGet. - Two mutually exclusive package version shapes are supported: - - When AddRevision is true, BuildNumber is ignored if specified. For non-preview releases, versions - will be 1.2.3.. For preview releases, versions will be 1.2.3.-previewX. - - When AddRevision is false, BuildNumber must be specified. Non-preview versions will be 1.2.3, and - preview releases will be 1.2.3-previewX.. - - This asymmetry maintains the existing package versioning practice where previews include a - date-coded build number, but normal releases do not. + Package versions take a single shape, produced by Versions.props from the pipeline build number. + Preview versions carry the full build number after the prerelease suffix, such as + 1.2.3-preview1.26238.3. Stable versions are left exactly as declared in Versions.props, such as + 1.2.3, because released packages are not stamped with a build number. File versions are always four-part and always carry a build number in the fourth component, even - when the package version does not: - - - AddRevision true. The fourth component is the mapped revision, so package and file versions - agree. A package version of 1.2.3.34430-preview1 has file version 1.2.3.34430. - - - AddRevision false. The fourth component is the first segment of BuildNumber. A package - version of 1.2.3-preview1.26238.3 has file version 1.2.3.26238, and a stable package version - of 1.2.3 still has file version 1.2.3.26238. This keeps every file version date-encoded and - traceable back to the run that produced it. + when the package version does not. Versions.props derives that component from the date segment of + BuildNumber, so a package version of 1.2.3-preview1.26238.3 has file version 1.2.3.26238, and a + stable package version of 1.2.3 still has file version 1.2.3.26238. That segment is date-coded, + so repeated runs on the same day share a file version even though their package versions differ. - The supplied revision is mapped to the range 1 through 65535 before canonical versions - are evaluated so every file version has a valid fourth component. Revisions above 65535 wrap - through the valid unsigned 16-bit file-version range. When AddRevision is true the script logs - the mapping because the revision may then collide with an earlier run. An unbuilt SqlServer - package is never revised or stamped with a build number because its effective version must - continue to identify the package that already exists on NuGet. + An unbuilt SqlServer package is never stamped with a build number because its effective version + must continue to identify the package that already exists on NuGet. The script emits these output variables for downstream stages: - - VersionRevision - SqlClientPackageVersion + - SqlClientFileVersion - SqlServerPackageVersion + - SqlServerFileVersion - SqlClientApiScanVersion - SqlServerApiScanVersion .PARAMETER ProjectPath Absolute or relative path to the repository build.proj file. -.PARAMETER Revision - Positive integer used to distinguish versions. Values above 65535 are wrapped into the unsigned - 16-bit revision range. Only consumed when AddRevision is true. - .PARAMETER BuildNumber - Pipeline build number in the form ., such as 26238.3. Required when AddRevision is - false, and ignored when AddRevision is true. When required, it is appended to prerelease package - versions and its first segment becomes the file-version build number, so file versions remain - date-encoded. + Pipeline build number in the form ., such as 26238.3. Versions.props appends it to + prerelease package versions and derives the file-version build number from its date segment. .PARAMETER BuildSqlServer Whether this run builds Microsoft.SqlServer.Server. When false, the effective SqlServer package version is its last published version and its file version is not consumed downstream. -.PARAMETER AddRevision - Whether to insert the revision into package versions built during this run. - Defaults to false in both top-level OneBranch pipelines. - .PARAMETER DotnetPath dotnet executable to invoke. Defaults to the dotnet command resolved from PATH. This parameter primarily supports isolated testing and specialized agent configurations. @@ -76,33 +52,19 @@ .EXAMPLE ./compute-versions.ps1 ` -ProjectPath ./build.proj ` - -Revision 165500 ` -BuildNumber 26238.3 ` - -BuildSqlServer $true ` - -AddRevision $false + -BuildSqlServer $true - Computes versions for an official-style run that builds SqlServer. Prerelease package versions - become 7.1.0-preview3.26238.3 and file versions become 7.1.0.26238. + Computes versions for a run that builds SqlServer. Prerelease package versions become + 7.1.0-preview3.26238.3 and file versions become 7.1.0.26238. .EXAMPLE ./compute-versions.ps1 ` -ProjectPath ./build.proj ` - -Revision 165500 ` - -BuildSqlServer $true ` - -AddRevision $true - - Computes versions for a run that builds SqlServer and appends mapped revision 34430 to both - package families and their file versions. BuildNumber is not supplied because AddRevision is - true. - -.EXAMPLE - ./compute-versions.ps1 ` - -ProjectPath ./build.proj ` - -Revision 165500 ` - -BuildSqlServer $false ` - -AddRevision $true + -BuildNumber 26238.3 ` + -BuildSqlServer $false - Revises the SqlClient family versions while retaining SqlServerPublishedVersion for dependency + Stamps the SqlClient family versions while retaining SqlServerPublishedVersion for dependency restore because SqlServer is not built in this run. .NOTES @@ -117,20 +79,13 @@ param( [ValidateScript({ Test-Path -LiteralPath $_ -PathType Leaf })] [string]$ProjectPath, - [Parameter(Mandatory = $true, HelpMessage = "Positive integer version revision.")] - [ValidateRange(1, [long]::MaxValue)] - [long]$Revision, - - [Parameter(HelpMessage = "Pipeline build number, such as 26238.3. Required when AddRevision is false.")] - [ValidatePattern("^$|^\d+\.\d+$")] - [string]$BuildNumber = "", + [Parameter(Mandatory = $true, HelpMessage = "Pipeline build number, such as 26238.3.")] + [ValidatePattern("^\d+\.\d+$")] + [string]$BuildNumber, [Parameter(Mandatory = $true, HelpMessage = "Whether Microsoft.SqlServer.Server is built in this run.")] [bool]$BuildSqlServer, - [Parameter(Mandatory = $true, HelpMessage = "Whether to append the revision to built package versions.")] - [bool]$AddRevision, - [Parameter(HelpMessage = "dotnet executable to invoke.")] [ValidateNotNullOrEmpty()] [string]$DotnetPath = "dotnet" @@ -139,11 +94,6 @@ param( Set-StrictMode -Version Latest $ErrorActionPreference = "Stop" -$wrappedRevision = (($Revision - 1) % 65535) + 1 -if ($AddRevision -and $Revision -gt 65535) { - Write-Host "Revision $Revision exceeds the unsigned 16-bit limit and wrapped to $wrappedRevision; this revision may collide with an earlier run." -} - <# .SYNOPSIS Extracts the first value associated with a labeled GetVersions target output line. @@ -179,7 +129,7 @@ function Get-LabeledValue { GetVersions target suffix: SqlClient or SqlServer. .OUTPUTS - An object containing PackageVersion and PublishedVersion. + An object containing PackageVersion, FileVersion, and PublishedVersion. #> function Get-CanonicalVersions { param( @@ -188,93 +138,28 @@ function Get-CanonicalVersions { ) $output = & $DotnetPath build $ProjectPath ` - -t:"GetVersions${Label}" -v:m -nologo -p:BuildNumber=$wrappedRevision 2>&1 + -t:"GetVersions${Label}" -v:m -nologo -p:BuildNumber=$BuildNumber 2>&1 if ($LASTEXITCODE -ne 0) { throw ($output -join [Environment]::NewLine) } $packageVersion = Get-LabeledValue -Output $output -Label "PackageVersion" + $fileVersion = Get-LabeledValue -Output $output -Label "FileVersion" $publishedVersion = Get-LabeledValue -Output $output -Label "PublishedVersion" if ([string]::IsNullOrWhiteSpace($packageVersion)) { throw "Failed to extract PackageVersion for ${Label}.`n$($output -join [Environment]::NewLine)" } + if ([string]::IsNullOrWhiteSpace($fileVersion)) { + throw "Failed to extract FileVersion for ${Label}.`n$($output -join [Environment]::NewLine)" + } [pscustomobject]@{ PackageVersion = $packageVersion + FileVersion = $fileVersion PublishedVersion = $publishedVersion } } -<# -.SYNOPSIS - Inserts a numeric revision before a package version's prerelease suffix. - -.PARAMETER Version - Package version with a three-part numeric base and optional prerelease suffix. - -.PARAMETER Revision - Revision in the unsigned 16-bit file-version range. - -.OUTPUTS - A four-part package version preserving the original prerelease suffix. -#> -function Add-VersionRevision { - param( - [string]$Version, - [ValidateRange(1, 65535)] - [int]$Revision - ) - - $parts = $Version -split "-", 2 - if ($parts[0] -notmatch "^\d+\.\d+\.\d+$") { - throw "Expected a three-part numeric version base, but received '$Version'." - } - - $versionWithRevision = "$($parts[0]).$Revision" - if ($parts.Count -eq 2) { - return "$versionWithRevision-$($parts[1])" - } - - return $versionWithRevision -} - -<# -.SYNOPSIS - Appends a pipeline build number to a prerelease package version. - -.DESCRIPTION - Reproduces the version shape used by earlier previews, where the build number follows the - prerelease suffix, such as 7.1.0-preview3.26238.3. Stable versions are returned unchanged - because released packages are not stamped with a build number. - -.PARAMETER Version - Package version with a three-part numeric base and optional prerelease suffix. - -.PARAMETER BuildNumber - Pipeline build number to append. - -.OUTPUTS - The package version with the build number appended to its prerelease suffix, or the original - version when it carries no prerelease suffix. -#> -function Add-VersionBuildNumber { - param( - [string]$Version, - [string]$BuildNumber - ) - - $parts = $Version -split "-", 2 - if ($parts[0] -notmatch "^\d+\.\d+\.\d+$") { - throw "Expected a three-part numeric version base, but received '$Version'." - } - - if ($parts.Count -eq 2) { - return "$($parts[0])-$($parts[1]).$BuildNumber" - } - - return $Version -} - <# .SYNOPSIS Extracts the major.minor components from a package version. @@ -316,14 +201,18 @@ function Set-PipelineOutputVariable { Write-Host "##vso[task.setvariable variable=${Name};isOutput=true]$Value" } -Write-Host "Extracting versions with revision=$Revision (wrapped=$wrappedRevision)..." +Write-Host "Extracting versions with build number $BuildNumber..." $sqlClientVersions = Get-CanonicalVersions -Label "SqlClient" $sqlServerVersions = Get-CanonicalVersions -Label "SqlServer" -Write-Host " SqlClient: pkg=$($sqlClientVersions.PackageVersion)" -Write-Host " SqlServer: pkg=$($sqlServerVersions.PackageVersion) pub=$($sqlServerVersions.PublishedVersion)" +Write-Host " SqlClient: pkg=$($sqlClientVersions.PackageVersion) file=$($sqlClientVersions.FileVersion)" +Write-Host " SqlServer: pkg=$($sqlServerVersions.PackageVersion) file=$($sqlServerVersions.FileVersion) pub=$($sqlServerVersions.PublishedVersion)" $sqlClientPackageVersion = $sqlClientVersions.PackageVersion +$sqlClientFileVersion = $sqlClientVersions.FileVersion + +# An unbuilt SqlServer resolves to its published version, which no build job stamps, so it has no +# effective file version. $sqlServerPackageVersion = if ($BuildSqlServer) { $sqlServerVersions.PackageVersion } else { @@ -332,46 +221,11 @@ $sqlServerPackageVersion = if ($BuildSqlServer) { } $sqlServerVersions.PublishedVersion } - -$fileVersionBuildNumber = $null - -if ($AddRevision) { - $sqlClientPackageVersion = Add-VersionRevision ` - -Version $sqlClientPackageVersion ` - -Revision $wrappedRevision - if ($BuildSqlServer) { - $sqlServerPackageVersion = Add-VersionRevision ` - -Version $sqlServerPackageVersion ` - -Revision $wrappedRevision - } - - # The revision is already the fourth component of the package version, so it is also the - # file-version build number. - $fileVersionBuildNumber = $wrappedRevision - Write-Host "Version revision: $wrappedRevision (input=$Revision)" -} -else { - if ([string]::IsNullOrWhiteSpace($BuildNumber)) { - throw "BuildNumber is required when AddRevision is false." - } - - $fileVersionBuildNumber = $BuildNumber.Split(".")[0] - - $sqlClientPackageVersion = Add-VersionBuildNumber ` - -Version $sqlClientPackageVersion ` - -BuildNumber $BuildNumber - if ($BuildSqlServer) { - $sqlServerPackageVersion = Add-VersionBuildNumber ` - -Version $sqlServerPackageVersion ` - -BuildNumber $BuildNumber - } - - Write-Host "Version build number: $BuildNumber (file version build number=$fileVersionBuildNumber)" -} +$sqlServerFileVersion = if ($BuildSqlServer) { $sqlServerVersions.FileVersion } else { "" } Write-Host "Effective versions:" -Write-Host " SqlClient (family): $sqlClientPackageVersion" -Write-Host " SqlServer: $sqlServerPackageVersion" +Write-Host " SqlClient (family): $sqlClientPackageVersion (file $sqlClientFileVersion)" +Write-Host " SqlServer: $sqlServerPackageVersion (file $sqlServerFileVersion)" $sqlClientApiScanVersion = Get-MajorMinorVersion -Version $sqlClientPackageVersion $sqlServerApiScanVersion = Get-MajorMinorVersion -Version $sqlServerPackageVersion @@ -381,7 +235,8 @@ Write-Host " SqlClient (family): $sqlClientApiScanVersion" Write-Host " SqlServer: $sqlServerApiScanVersion" Set-PipelineOutputVariable -Name "SqlClientPackageVersion" -Value $sqlClientPackageVersion +Set-PipelineOutputVariable -Name "SqlClientFileVersion" -Value $sqlClientFileVersion Set-PipelineOutputVariable -Name "SqlServerPackageVersion" -Value $sqlServerPackageVersion +Set-PipelineOutputVariable -Name "SqlServerFileVersion" -Value $sqlServerFileVersion Set-PipelineOutputVariable -Name "SqlClientApiScanVersion" -Value $sqlClientApiScanVersion Set-PipelineOutputVariable -Name "SqlServerApiScanVersion" -Value $sqlServerApiScanVersion -Set-PipelineOutputVariable -Name "VersionRevision" -Value $fileVersionBuildNumber diff --git a/eng/pipelines/onebranch/scripts/tests/README.md b/eng/pipelines/onebranch/scripts/tests/README.md index bda88d58a1..3585312d53 100644 --- a/eng/pipelines/onebranch/scripts/tests/README.md +++ b/eng/pipelines/onebranch/scripts/tests/README.md @@ -31,7 +31,7 @@ Invoke-Pester ./publish-symbols.Tests.ps1 -Output Detailed | Area | What's tested | | --------------------- | ---------------------------------------------------------------- | -| Version computation | Canonical output parsing, revisions, wrapping, effective package selection, and failures | +| Version computation | Canonical output parsing, effective package selection, target version composition, and failures | | Parameter validation | Empty strings rejected for all mandatory parameters | | URL construction | Base URL, register URL, request URL built from parameters | | Request bodies | Registration body, default publish flags, flag overrides | @@ -41,5 +41,6 @@ Invoke-Pester ./publish-symbols.Tests.ps1 -Output Detailed ## Notes - All external calls (`az`, `Invoke-RestMethod`) are mocked — no network access or Azure credentials are required. -- Version tests mock `dotnet`, so they do not invoke MSBuild or require a restored repository. +- Script-level version tests mock `dotnet`; package-composition tests invoke the real MSBuild + `GetVersionsSqlClient` and `GetVersionsSqlServer` targets. - Tests validate scripts in the parent directory relative to this directory. diff --git a/eng/pipelines/onebranch/scripts/tests/compute-versions.Tests.ps1 b/eng/pipelines/onebranch/scripts/tests/compute-versions.Tests.ps1 index cd38e6bb66..7a9e9779cb 100644 --- a/eng/pipelines/onebranch/scripts/tests/compute-versions.Tests.ps1 +++ b/eng/pipelines/onebranch/scripts/tests/compute-versions.Tests.ps1 @@ -4,7 +4,9 @@ #> BeforeAll { + $script:repoRoot = Resolve-Path (Join-Path $PSScriptRoot '..' '..' '..' '..' '..') $scriptPath = Join-Path $PSScriptRoot '..' 'compute-versions.ps1' + $buildProjectPath = Resolve-Path (Join-Path $script:repoRoot 'build.proj') $projectPath = Join-Path $TestDrive 'build.proj' Set-Content -LiteralPath $projectPath -Value '' @@ -19,26 +21,23 @@ BeforeAll { function Invoke-ComputeVersions { param( - [long]$Revision = 42, - [string]$BuildNumber = '', - [bool]$BuildSqlServer = $true, - [bool]$AddRevision = $true + [string]$BuildNumber = $script:testBuildNumber, + [bool]$BuildSqlServer = $true ) & $scriptPath ` -ProjectPath $projectPath ` - -Revision $Revision ` -BuildNumber $BuildNumber ` - -BuildSqlServer $BuildSqlServer ` - -AddRevision $AddRevision *>&1 | Out-String + -BuildSqlServer $BuildSqlServer *>&1 | Out-String } # Alternates between the SqlClient and SqlServer GetVersions targets, which the script always - # invokes in that order. + # invokes in that order. The versions returned here are already stamped, because Versions.props + # applies the build number before the script ever sees them. function Set-DotnetMock { param( - [string]$SqlClientPackageVersion = '7.1.0-preview3', - [string]$SqlServerPackageVersion = '1.1.0-preview1' + [string]$SqlClientPackageVersion = "7.1.0-preview3.$script:testBuildNumber", + [string]$SqlServerPackageVersion = "1.1.0-preview1.$script:testBuildNumber" ) $global:computeVersionsDotnetCallCount = 0 @@ -48,12 +47,14 @@ BeforeAll { if ($global:computeVersionsDotnetCallCount % 2 -eq 1) { return @( " PackageVersion: $SqlClientPackageVersion" + ' FileVersion: 7.1.0.26238' ' PublishedVersion: 7.0.0' ) } return @( " PackageVersion: $SqlServerPackageVersion" + ' FileVersion: 1.1.0.26238' ' PublishedVersion: 1.0.0' ) }.GetNewClosure() @@ -62,6 +63,90 @@ BeforeAll { function Set-SuccessfulDotnetMock { Set-DotnetMock } + + function Invoke-VersionTarget { + param( + [Parameter(Mandatory)] + [string]$Target, + + [Parameter(Mandatory)] + [string]$NextVersionProperty, + + [Parameter(Mandatory)] + [string]$BaseVersion, + + [string]$BuildSuffix + ) + + $arguments = @( + 'build' + $buildProjectPath + "-t:$Target" + '-v:m' + '-nologo' + "-p:BuildNumber=$script:testBuildNumber" + "-p:$NextVersionProperty=$BaseVersion" + ) + if ($BuildSuffix) { + $arguments += "-p:BuildSuffix=$BuildSuffix" + } + + $output = & dotnet @arguments 2>&1 | Out-String + if ($LASTEXITCODE -ne 0) { + throw "$Target failed with exit code ${LASTEXITCODE}:`n$output" + } + + $output + } + + # Drives PrepareForBuild rather than the validation target directly, because the hook point is + # itself the thing under test: a check wired after the compile would pass a direct invocation. + # An explicit target framework is required, as PrepareForBuild is not valid on the outer + # cross-targeting build. + function Invoke-VersionValidation { + param( + [Parameter(Mandatory)] + [string]$ProjectPath, + + [Parameter(Mandatory)] + [string]$TargetFramework, + + [string[]]$Properties = @() + ) + + $arguments = @( + 'build' + $ProjectPath + '-f' + $TargetFramework + '-t:PrepareForBuild' + '-v:m' + '-nologo' + ) + $Properties + + $output = & dotnet @arguments 2>&1 | Out-String + [pscustomobject]@{ ExitCode = $LASTEXITCODE; Output = $output } + } + + function Invoke-BuildProjTarget { + param( + [Parameter(Mandatory)] + [string]$Target, + + [string[]]$Properties = @() + ) + + $arguments = @( + 'build' + $buildProjectPath + "-t:$Target" + '-v:m' + '-nologo' + ) + $Properties + + $output = & dotnet @arguments 2>&1 | Out-String + [pscustomobject]@{ ExitCode = $LASTEXITCODE; Output = $output } + } } AfterAll { @@ -73,101 +158,218 @@ Describe 'compute-versions.ps1 Effective Versions' { Set-SuccessfulDotnetMock } - It 'appends the build number after the prerelease suffix when package revisioning is disabled' { - $output = Invoke-ComputeVersions -AddRevision $false -BuildNumber $script:testBuildNumber + It 'forwards the stamped prerelease versions from Versions.props' { + $output = Invoke-ComputeVersions $output | Should -Match "SqlClientPackageVersion;isOutput=true]7\.1\.0-preview3\.$script:testBuildNumberPattern" $output | Should -Match "SqlServerPackageVersion;isOutput=true]1\.1\.0-preview1\.$script:testBuildNumberPattern" $output | Should -Match 'SqlClientApiScanVersion;isOutput=true]7\.1' $output | Should -Match 'SqlServerApiScanVersion;isOutput=true]1\.1' $output | Should -Match 'APIScan registration versions:\s+SqlClient \(family\): 7\.1\s+SqlServer:\s+1\.1' - $output | Should -Match "VersionRevision;isOutput=true]$script:testFileVersionBuildNumber" - } - - It 'inserts the revision before prerelease suffixes for built packages' { - $output = Invoke-ComputeVersions - - $output | Should -Match 'SqlClientPackageVersion;isOutput=true]7\.1\.0\.42-preview3' - $output | Should -Match 'SqlServerPackageVersion;isOutput=true]1\.1\.0\.42-preview1' + $output | Should -Match 'SqlClientFileVersion;isOutput=true]7\.1\.0\.26238' + $output | Should -Match 'SqlServerFileVersion;isOutput=true]1\.1\.0\.26238' } It 'retains the published SqlServer package when SqlServer is not built' { $output = Invoke-ComputeVersions -BuildSqlServer $false - $output | Should -Match 'SqlClientPackageVersion;isOutput=true]7\.1\.0\.42-preview3' + $output | Should -Match "SqlClientPackageVersion;isOutput=true]7\.1\.0-preview3\.$script:testBuildNumberPattern" $output | Should -Match 'SqlServerPackageVersion;isOutput=true]1\.0\.0' $output | Should -Match 'SqlServerApiScanVersion;isOutput=true]1\.0' - $output | Should -Not -Match 'SqlServerPackageVersion;isOutput=true]1\.0\.0\.42' - } - - It 'wraps revisions above 65535 and logs the mapping as information' { - $output = Invoke-ComputeVersions -Revision 65536 - - $output | Should -Match 'Revision 65536.*wrapped to 1' - $output | Should -Not -Match 'task\.logissue type=warning' - $output | Should -Match 'SqlClientPackageVersion;isOutput=true]7\.1\.0\.1-preview3' - $output | Should -Match 'SqlServerPackageVersion;isOutput=true]1\.1\.0\.1-preview1' - $output | Should -Match 'VersionRevision;isOutput=true]1' - } - - It 'emits the build number rather than the wrapped revision when package revisioning is disabled' { - $output = Invoke-ComputeVersions -Revision 65536 -AddRevision $false -BuildNumber $script:testBuildNumber - - $output | Should -Not -Match 'task\.logissue type=warning' - $output | Should -Not -Match 'wrapped to' - $output | Should -Match "SqlClientPackageVersion;isOutput=true]7\.1\.0-preview3\.$script:testBuildNumberPattern" - $output | Should -Match "SqlServerPackageVersion;isOutput=true]1\.1\.0-preview1\.$script:testBuildNumberPattern" - $output | Should -Match "VersionRevision;isOutput=true]$script:testFileVersionBuildNumber" - } + $output | Should -Not -Match "SqlServerPackageVersion;isOutput=true]1\.0\.0[\.-]$script:testFileVersionBuildNumber" - It 'retains the published SqlServer package unstamped when SqlServer is not built' { - $output = Invoke-ComputeVersions -BuildSqlServer $false -AddRevision $false -BuildNumber $script:testBuildNumber - - $output | Should -Match "SqlClientPackageVersion;isOutput=true]7\.1\.0-preview3\.$script:testBuildNumberPattern" - $output | Should -Match 'SqlServerPackageVersion;isOutput=true]1\.0\.0' - $output | Should -Not -Match "SqlServerPackageVersion;isOutput=true]1\.0\.0\.$script:testFileVersionBuildNumber" + # An unbuilt SqlServer is never stamped, so it has no effective file version. + $output | Should -Match 'SqlServerFileVersion;isOutput=true](\r?\n|$)' } - It 'omits the build number from non-preview package versions when package revisioning is disabled' { + It 'forwards unstamped non-preview package versions' { Set-DotnetMock -SqlClientPackageVersion '7.1.0' -SqlServerPackageVersion '1.1.0' - $output = Invoke-ComputeVersions -AddRevision $false -BuildNumber $script:testBuildNumber + $output = Invoke-ComputeVersions $output | Should -Match 'SqlClientPackageVersion;isOutput=true]7\.1\.0(\r?\n|$)' $output | Should -Match 'SqlServerPackageVersion;isOutput=true]1\.1\.0(\r?\n|$)' $output | Should -Not -Match "SqlClientPackageVersion;isOutput=true]7\.1\.0[\.-]$script:testFileVersionBuildNumber" $output | Should -Not -Match "SqlServerPackageVersion;isOutput=true]1\.1\.0[\.-]$script:testFileVersionBuildNumber" - # The file version is still stamped so every build produces a distinct, date-encoded - # file version even for non-preview releases. - $output | Should -Match "VersionRevision;isOutput=true]$script:testFileVersionBuildNumber" + # The file version is still stamped so every build produces a date-encoded file version even + # for non-preview releases. + $output | Should -Match 'SqlClientFileVersion;isOutput=true]7\.1\.0\.26238' } +} - It 'revises non-preview package versions when package revisioning is enabled' { - Set-DotnetMock -SqlClientPackageVersion '7.1.0' -SqlServerPackageVersion '1.1.0' - - $output = Invoke-ComputeVersions - - $output | Should -Match 'SqlClientPackageVersion;isOutput=true]7\.1\.0\.42' - $output | Should -Match 'SqlServerPackageVersion;isOutput=true]1\.1\.0\.42' - $output | Should -Match 'VersionRevision;isOutput=true]42' +Describe 'GetVersions target package composition' { + It ' composes package and file versions' -ForEach @( + @{ + Target = 'GetVersionsSqlClient'; NextVersionProperty = 'SqlClientNextVersion' + BaseVersion = '7.1.0'; BuildSuffix = ''; ExpectedPackageVersion = '7.1.0' + ExpectedFileVersion = '7.1.0.26238'; Case = 'a stable base without a suffix' + } + @{ + Target = 'GetVersionsSqlClient'; NextVersionProperty = 'SqlClientNextVersion' + BaseVersion = '7.1.0'; BuildSuffix = 'ci'; ExpectedPackageVersion = '7.1.0-ci.26238.3' + ExpectedFileVersion = '7.1.0.26238'; Case = 'a stable base with a suffix' + } + @{ + Target = 'GetVersionsSqlClient'; NextVersionProperty = 'SqlClientNextVersion' + BaseVersion = '7.1.0-preview3'; BuildSuffix = ''; ExpectedPackageVersion = '7.1.0-preview3.26238.3' + ExpectedFileVersion = '7.1.0.26238'; Case = 'a prerelease base without a suffix' + } + @{ + Target = 'GetVersionsSqlClient'; NextVersionProperty = 'SqlClientNextVersion' + BaseVersion = '7.1.0-preview3'; BuildSuffix = 'ci'; ExpectedPackageVersion = '7.1.0-preview3-ci.26238.3' + ExpectedFileVersion = '7.1.0.26238'; Case = 'a prerelease base with a suffix' + } + @{ + Target = 'GetVersionsSqlServer'; NextVersionProperty = 'SqlServerNextVersion' + BaseVersion = '1.1.0'; BuildSuffix = ''; ExpectedPackageVersion = '1.1.0' + ExpectedFileVersion = '1.1.0.26238'; Case = 'a stable base without a suffix' + } + @{ + Target = 'GetVersionsSqlServer'; NextVersionProperty = 'SqlServerNextVersion' + BaseVersion = '1.1.0'; BuildSuffix = 'ci'; ExpectedPackageVersion = '1.1.0-ci.26238.3' + ExpectedFileVersion = '1.1.0.26238'; Case = 'a stable base with a suffix' + } + @{ + Target = 'GetVersionsSqlServer'; NextVersionProperty = 'SqlServerNextVersion' + BaseVersion = '1.1.0-preview1'; BuildSuffix = ''; ExpectedPackageVersion = '1.1.0-preview1.26238.3' + ExpectedFileVersion = '1.1.0.26238'; Case = 'a prerelease base without a suffix' + } + @{ + Target = 'GetVersionsSqlServer'; NextVersionProperty = 'SqlServerNextVersion' + BaseVersion = '1.1.0-preview1'; BuildSuffix = 'ci'; ExpectedPackageVersion = '1.1.0-preview1-ci.26238.3' + ExpectedFileVersion = '1.1.0.26238'; Case = 'a prerelease base with a suffix' + } + ) { + $output = Invoke-VersionTarget ` + -Target $Target ` + -NextVersionProperty $NextVersionProperty ` + -BaseVersion $BaseVersion ` + -BuildSuffix $BuildSuffix + + $output | Should -Match "PackageVersion:\s+$([regex]::Escape($ExpectedPackageVersion))(\r?\n|$)" + $output | Should -Match "FileVersion:\s+$([regex]::Escape($ExpectedFileVersion))(\r?\n|$)" } } -Describe 'compute-versions.ps1 Error Handling' { - It 'rejects a non-positive revision' { - { Invoke-ComputeVersions -Revision 0 } | Should -Throw +Describe 'File version component validation' { + It 'rejects a four-part ' -ForEach @( + @{ + Product = 'SqlClient'; Property = 'SqlClientPackageVersion' + RelativeProject = 'src/Microsoft.Data.SqlClient/src/Microsoft.Data.SqlClient.csproj' + TargetFramework = 'net8.0' + Properties = @('-p:SqlClientPackageVersion=7.1.0.123') + ExpectedFileVersion = '7.1.0.123.0' + } + @{ + Product = 'SqlClient'; Property = 'SqlClientNextVersion' + RelativeProject = 'src/Microsoft.Data.SqlClient/src/Microsoft.Data.SqlClient.csproj' + TargetFramework = 'net8.0' + Properties = @('-p:SqlClientNextVersion=7.1.0.123', '-p:BuildNumber=1234') + ExpectedFileVersion = '7.1.0.123.1234' + } + @{ + Product = 'SqlServer'; Property = 'SqlServerPackageVersion' + RelativeProject = 'src/Microsoft.SqlServer.Server/Microsoft.SqlServer.Server.csproj' + TargetFramework = 'netstandard2.0' + Properties = @('-p:SqlServerPackageVersion=1.1.0.123') + ExpectedFileVersion = '1.1.0.123.0' + } + @{ + Product = 'SqlServer'; Property = 'SqlServerNextVersion' + RelativeProject = 'src/Microsoft.SqlServer.Server/Microsoft.SqlServer.Server.csproj' + TargetFramework = 'netstandard2.0' + Properties = @('-p:SqlServerNextVersion=1.1.0.123', '-p:BuildNumber=1234') + ExpectedFileVersion = '1.1.0.123.1234' + } + ) { + $result = Invoke-VersionValidation ` + -ProjectPath (Join-Path $script:repoRoot $RelativeProject) ` + -TargetFramework $TargetFramework ` + -Properties $Properties + + $result.ExitCode | Should -Not -Be 0 + $result.Output | Should -Match ([regex]::Escape("${Product}FileVersion '$ExpectedFileVersion' is not a four-part numeric version")) } - It 'requires a build number when package revisioning is disabled' { - Set-SuccessfulDotnetMock + It 'rejects an externally supplied file version for ' -ForEach @( + @{ + Product = 'SqlClient'; Description = 'short' + RelativeProject = 'src/Microsoft.Data.SqlClient/src/Microsoft.Data.SqlClient.csproj' + TargetFramework = 'net8.0' + FileVersion = '1.2' + } + @{ + Product = 'SqlClient'; Description = 'non-numeric' + RelativeProject = 'src/Microsoft.Data.SqlClient/src/Microsoft.Data.SqlClient.csproj' + TargetFramework = 'net8.0' + FileVersion = 'abc' + } + @{ + Product = 'SqlServer'; Description = 'short' + RelativeProject = 'src/Microsoft.SqlServer.Server/Microsoft.SqlServer.Server.csproj' + TargetFramework = 'netstandard2.0' + FileVersion = '1.2' + } + @{ + Product = 'SqlServer'; Description = 'non-numeric' + RelativeProject = 'src/Microsoft.SqlServer.Server/Microsoft.SqlServer.Server.csproj' + TargetFramework = 'netstandard2.0' + FileVersion = 'abc' + } + ) { + $result = Invoke-VersionValidation ` + -ProjectPath (Join-Path $script:repoRoot $RelativeProject) ` + -TargetFramework $TargetFramework ` + -Properties @("-p:${Product}FileVersion=$FileVersion") + + $result.ExitCode | Should -Not -Be 0 + $result.Output | Should -Match ([regex]::Escape("${Product}FileVersion '$FileVersion' is not a four-part numeric version")) + } - { Invoke-ComputeVersions -AddRevision $false } | - Should -Throw '*BuildNumber is required when AddRevision is false*' + It 'accepts the declared version' -ForEach @( + @{ + Product = 'SqlClient' + RelativeProject = 'src/Microsoft.Data.SqlClient/src/Microsoft.Data.SqlClient.csproj' + TargetFramework = 'net8.0' + } + @{ + Product = 'SqlServer' + RelativeProject = 'src/Microsoft.SqlServer.Server/Microsoft.SqlServer.Server.csproj' + TargetFramework = 'netstandard2.0' + } + ) { + $result = Invoke-VersionValidation ` + -ProjectPath (Join-Path $script:repoRoot $RelativeProject) ` + -TargetFramework $TargetFramework ` + -Properties @("-p:BuildNumber=$script:testBuildNumber") + + $result.ExitCode | Should -Be 0 } +} +Describe 'build.proj file version wrappers' { + # A malformed value is used so the leaf project reports it by name, which proves the wrapper + # forwarded it verbatim without paying for a full compile. + It 'forwards through ' -ForEach @( + @{ Product = 'SqlClient'; Wrapper = 'FileVersionSqlClient'; Target = 'BuildLogging' } + @{ Product = 'SqlServer'; Wrapper = 'FileVersionSqlServer'; Target = 'BuildSqlServer' } + ) { + $result = Invoke-BuildProjTarget -Target $Target -Properties @("-p:$Wrapper=1.2") + + $result.ExitCode | Should -Not -Be 0 + $result.Output | Should -Match ([regex]::Escape("${Product}FileVersion '1.2' is not a four-part numeric version")) + } +} + +Describe 'compute-versions.ps1 Error Handling' { It 'rejects a malformed build number' { - { Invoke-ComputeVersions -AddRevision $false -BuildNumber 'not-a-build-number' } | Should -Throw + { Invoke-ComputeVersions -BuildNumber 'not-a-build-number' } | Should -Throw + } + + It 'requires a build number' { + # Bound as empty rather than omitted; omitting a mandatory parameter prompts interactively. + { Invoke-ComputeVersions -BuildNumber '' } | Should -Throw } It 'throws when a GetVersions target fails' { @@ -188,18 +390,12 @@ Describe 'compute-versions.ps1 Error Handling' { { Invoke-ComputeVersions } | Should -Throw '*Failed to extract PackageVersion*' } - It 'throws when a revised package does not have a three-part numeric base' { - $global:computeVersionsDotnetCallCount = 0 + It 'throws when a FileVersion label is absent' { Mock -CommandName 'dotnet' -MockWith { $global:LASTEXITCODE = 0 - $global:computeVersionsDotnetCallCount++ - if ($global:computeVersionsDotnetCallCount -eq 1) { - return @('PackageVersion: 7.1-preview3') - } - - return @('PackageVersion: 1.1.0-preview1', 'PublishedVersion: 1.0.0') + return 'PackageVersion: 7.1.0-preview3.26238.3' } - { Invoke-ComputeVersions } | Should -Throw "*Expected a three-part numeric version base*" + { Invoke-ComputeVersions } | Should -Throw '*Failed to extract FileVersion*' } } diff --git a/eng/pipelines/onebranch/sqlclient-non-official.yml b/eng/pipelines/onebranch/sqlclient-non-official.yml index 3ec9bdbc75..88231ed15b 100644 --- a/eng/pipelines/onebranch/sqlclient-non-official.yml +++ b/eng/pipelines/onebranch/sqlclient-non-official.yml @@ -28,13 +28,6 @@ parameters: type: boolean default: false - # Append the Build.BuildId revision to package and file versions to reduce collisions when - # repeatedly publishing tests to symbol servers or the NuGet test feed. - - name: addRevision - displayName: Use the build ID as the revision version - type: boolean - default: false - # True to publish symbols to private and public servers. - name: publishSymbols displayName: Publish symbols @@ -256,8 +249,12 @@ extends: sbom: enabled: true - packageName: 'Microsoft.Data.SqlClient' - packageVersion: '$(Build.BuildNumber)' + # OneBranch resolves these from globalSdl only -- there is no per-job form -- so they + # indirect through variables that each build job sets to the package it produces. Jobs + # that publish no packages disable SBOM via ob_sdl_sbom_enabled rather than defaulting + # these. See build-buildproj-job.yml. + packageName: '$(sbomPackageName)' + packageVersion: '$(sbomPackageVersion)' tsa: # TSA (Trust Services Automation) files SDL analysis findings as Azure DevOps bug work @@ -297,7 +294,6 @@ extends: - template: /eng/pipelines/onebranch/stages/compute-versions-stage.yml@self parameters: - addRevision: ${{ parameters.addRevision }} buildSqlServer: ${{ parameters.buildSqlServer }} - template: /eng/pipelines/onebranch/stages/build-stages.yml@self diff --git a/eng/pipelines/onebranch/sqlclient-official.yml b/eng/pipelines/onebranch/sqlclient-official.yml index 2bc98a655b..40b08c76c0 100644 --- a/eng/pipelines/onebranch/sqlclient-official.yml +++ b/eng/pipelines/onebranch/sqlclient-official.yml @@ -37,12 +37,6 @@ parameters: type: boolean default: false - # Append the Build.BuildId revision to package and file versions. - - name: addRevision - displayName: Use the build ID as the revision version - type: boolean - default: false - # True to publish symbols to private and public servers. - name: publishSymbols displayName: Publish symbols @@ -270,8 +264,12 @@ extends: sbom: enabled: true - packageName: 'Microsoft.Data.SqlClient' - packageVersion: '$(Build.BuildNumber)' + # OneBranch resolves these from globalSdl only -- there is no per-job form -- so they + # indirect through variables that each build job sets to the package it produces. Jobs + # that publish no packages disable SBOM via ob_sdl_sbom_enabled rather than defaulting + # these. See build-buildproj-job.yml. + packageName: '$(sbomPackageName)' + packageVersion: '$(sbomPackageVersion)' tsa: # TSA (Trust Services Automation) files SDL analysis findings as Azure DevOps bug work @@ -306,7 +304,6 @@ extends: - template: /eng/pipelines/onebranch/stages/compute-versions-stage.yml@self parameters: - addRevision: ${{ parameters.addRevision }} buildSqlServer: ${{ parameters.buildSqlServer }} - template: /eng/pipelines/onebranch/stages/build-stages.yml@self diff --git a/eng/pipelines/onebranch/stages/build-stages.yml b/eng/pipelines/onebranch/stages/build-stages.yml index 98e656004b..afd1907859 100644 --- a/eng/pipelines/onebranch/stages/build-stages.yml +++ b/eng/pipelines/onebranch/stages/build-stages.yml @@ -80,8 +80,10 @@ stages: dependsOn: compute_versions variables: - - name: versionRevision - value: $[ stageDependencies.compute_versions.compute_versions_job.outputs['versions.VersionRevision'] ] + - name: sqlClientFileVersion + value: $[ stageDependencies.compute_versions.compute_versions_job.outputs['versions.SqlClientFileVersion'] ] + - name: sqlServerFileVersion + value: $[ stageDependencies.compute_versions.compute_versions_job.outputs['versions.SqlServerFileVersion'] ] - name: sqlClientPackageVersion value: $[ stageDependencies.compute_versions.compute_versions_job.outputs['versions.SqlClientPackageVersion'] ] - name: sqlServerPackageVersion @@ -107,7 +109,7 @@ stages: signingEsrpConnectedServiceName: '${{ parameters.signingEsrpConnectedServiceName }}' dependencies: [] - revision: '$(versionRevision)' + fileVersion: '$(sqlClientFileVersion)' packageFullName: 'Microsoft.Data.SqlClient.Internal.Logging' packageShortName: 'Logging' versionPropertySuffix: 'SqlClient' @@ -130,7 +132,7 @@ stages: signingEsrpConnectedServiceName: '${{ parameters.signingEsrpConnectedServiceName }}' dependencies: [] - revision: '$(versionRevision)' + fileVersion: '$(sqlServerFileVersion)' packageFullName: 'Microsoft.SqlServer.Server' packageShortName: 'SqlServer' versionPropertySuffix: 'SqlServer' @@ -148,8 +150,8 @@ stages: - build_independent variables: - - name: versionRevision - value: $[ stageDependencies.compute_versions.compute_versions_job.outputs['versions.VersionRevision'] ] + - name: sqlClientFileVersion + value: $[ stageDependencies.compute_versions.compute_versions_job.outputs['versions.SqlClientFileVersion'] ] - name: sqlClientPackageVersion value: $[ stageDependencies.compute_versions.compute_versions_job.outputs['versions.SqlClientPackageVersion'] ] - name: sqlClientApiScanVersion @@ -174,7 +176,7 @@ stages: - artifactName: '${{ parameters.loggingArtifactsName }}' shortName: 'Logging' version: '$(sqlClientPackageVersion)' - revision: '$(versionRevision)' + fileVersion: '$(sqlClientFileVersion)' packageFullName: 'Microsoft.Data.SqlClient.Extensions.Abstractions' packageShortName: 'Abstractions' versionPropertySuffix: 'SqlClient' @@ -192,8 +194,8 @@ stages: - build_abstractions variables: - - name: versionRevision - value: $[ stageDependencies.compute_versions.compute_versions_job.outputs['versions.VersionRevision'] ] + - name: sqlClientFileVersion + value: $[ stageDependencies.compute_versions.compute_versions_job.outputs['versions.SqlClientFileVersion'] ] - name: sqlClientPackageVersion value: $[ stageDependencies.compute_versions.compute_versions_job.outputs['versions.SqlClientPackageVersion'] ] - name: sqlServerPackageVersion @@ -234,7 +236,7 @@ stages: - artifactName: '' shortName: 'SqlServer' version: '$(sqlServerPackageVersion)' - revision: '$(versionRevision)' + fileVersion: '$(sqlClientFileVersion)' packageFullName: 'Microsoft.Data.SqlClient' packageShortName: 'SqlClient' versionPropertySuffix: 'SqlClient' @@ -261,7 +263,7 @@ stages: - artifactName: '${{ parameters.loggingArtifactsName }}' shortName: 'Logging' version: '$(sqlClientPackageVersion)' - revision: '$(versionRevision)' + fileVersion: '$(sqlClientFileVersion)' packageFullName: 'Microsoft.Data.SqlClient.Extensions.Azure' packageShortName: 'Azure' versionPropertySuffix: 'SqlClient' @@ -278,8 +280,8 @@ stages: - build_dependent variables: - - name: versionRevision - value: $[ stageDependencies.compute_versions.compute_versions_job.outputs['versions.VersionRevision'] ] + - name: sqlClientFileVersion + value: $[ stageDependencies.compute_versions.compute_versions_job.outputs['versions.SqlClientFileVersion'] ] - name: sqlClientPackageVersion value: $[ stageDependencies.compute_versions.compute_versions_job.outputs['versions.SqlClientPackageVersion'] ] - name: sqlServerPackageVersion @@ -322,7 +324,7 @@ stages: - artifactName: '' shortName: 'SqlServer' version: '$(sqlServerPackageVersion)' - revision: '$(versionRevision)' + fileVersion: '$(sqlClientFileVersion)' packageFullName: 'Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider' packageShortName: 'AkvProvider' versionPropertySuffix: 'SqlClient' diff --git a/eng/pipelines/onebranch/stages/compute-versions-stage.yml b/eng/pipelines/onebranch/stages/compute-versions-stage.yml index 11e2187e57..9514c0d56e 100644 --- a/eng/pipelines/onebranch/stages/compute-versions-stage.yml +++ b/eng/pipelines/onebranch/stages/compute-versions-stage.yml @@ -17,20 +17,14 @@ # - Microsoft.SqlServer.Server is versioned separately: it uses its "next" version when it is # being built this run, or its "published" (last shipped to NuGet) version when it is not built # (so the SqlClient family depends on the most recently published SqlServer package). -# - Runs use their "next" version from Versions.props. By default the pipeline build number is -# appended to prerelease package versions (7.1.0-preview3.26238.3) and its date segment becomes -# the file-version build number (7.1.0.26238), matching the shape shipped by earlier previews. -# Runs can instead append the Build.BuildId revision, reducing collisions when repeatedly -# publishing the same base version for testing. +# - Runs use their "next" version from Versions.props. The pipeline build number is appended to +# prerelease package versions (7.1.0-preview3.26238.3) and its date segment becomes the +# file-version build number (7.1.0.26238), matching the shape shipped by earlier previews. # - Versions are extracted via build.proj GetVersions* targets by parsing stdout. # # This stage MUST run before all build stages so they can consume computed versions. parameters: - # Whether to append the Build.BuildId revision to package and file versions. - - name: addRevision - type: boolean - # Whether Microsoft.SqlServer.Server is being built this run. This drives the SqlServer version # selection (next when built, published when not); the SqlClient family always uses its next # version. When SqlServer is not built, the SqlClient family depends on the published SqlServer @@ -54,6 +48,8 @@ stages: ob_sdl_apiscan_enabled: false ob_sdl_binskim_break: false ob_sdl_binskim_enabled: false + # No packages are published here, so there is nothing to describe in an SBOM. + ob_sdl_sbom_enabled: false steps: - pwsh: | @@ -69,8 +65,8 @@ stages: # may run during the GetVersions* evaluation. - template: /eng/pipelines/common/steps/restore-dotnet-tools.yml@self - # Extract canonical versions, resolve the effective built/published values, optionally - # add the run revision, and publish the downstream stage output variables. + # Extract canonical versions, resolve the effective built/published values, and publish + # the downstream stage output variables. - task: PowerShell@2 displayName: "Compute Effective Versions" name: "versions" @@ -80,7 +76,5 @@ stages: filePath: $(Build.SourcesDirectory)/eng/pipelines/onebranch/scripts/compute-versions.ps1 arguments: >- -ProjectPath "$(Build.SourcesDirectory)/build.proj" - -Revision "$(Build.BuildId)" -BuildNumber "$(Build.BuildNumber)" -BuildSqlServer $${{ parameters.buildSqlServer }} - -AddRevision $${{ parameters.addRevision }} diff --git a/eng/pipelines/onebranch/steps/build-buildproj-step.yml b/eng/pipelines/onebranch/steps/build-buildproj-step.yml index 5cfc809772..961b972f8c 100644 --- a/eng/pipelines/onebranch/steps/build-buildproj-step.yml +++ b/eng/pipelines/onebranch/steps/build-buildproj-step.yml @@ -37,8 +37,8 @@ parameters: - SqlClient - SqlServer - # Version revision translated to build.proj's BuildNumber property at this boundary. - - name: revision + # Pre-computed assembly file version, translated to build.proj's FileVersion* property here. + - name: fileVersion type: string # Suffix appended to "PackageVersion" to form the build.proj msbuild property that stamps this @@ -75,7 +75,7 @@ steps: -p:ReferenceType=Package -p:SkipDependencyPack=true -p:SigningKeyPath="$(keyFile.secureFilePath)" - -p:BuildNumber="${{ parameters.revision }}" + -p:FileVersion${{ parameters.versionPropertySuffix }}="${{ parameters.fileVersion }}" -p:PackageVersion${{ parameters.versionPropertySuffix }}="${{ parameters.packageVersion }}" ${{ parameters.dependencyArguments }} diff --git a/eng/pipelines/onebranch/steps/pack-buildproj-step.yml b/eng/pipelines/onebranch/steps/pack-buildproj-step.yml index 4960872d7b..b8ee6e72dd 100644 --- a/eng/pipelines/onebranch/steps/pack-buildproj-step.yml +++ b/eng/pipelines/onebranch/steps/pack-buildproj-step.yml @@ -49,8 +49,8 @@ parameters: - SqlClient - SqlServer - # Version revision translated to build.proj's BuildNumber property at this boundary. - - name: revision + # Pre-computed assembly file version, translated to build.proj's FileVersion* property here. + - name: fileVersion type: string # Suffix appended to "PackageVersion" to form the build.proj msbuild property that stamps this @@ -79,7 +79,7 @@ steps: -p:Configuration=${{ parameters.buildConfiguration }} -p:PackBuild=false -p:ReferenceType=Package - -p:BuildNumber="${{ parameters.revision }}" + -p:FileVersion${{ parameters.versionPropertySuffix }}="${{ parameters.fileVersion }}" -p:PackageVersion${{ parameters.versionPropertySuffix }}="${{ parameters.packageVersion }}" ${{ parameters.dependencyArguments }} diff --git a/eng/pipelines/onebranch/steps/roslyn-analyzers-buildproj-step.yml b/eng/pipelines/onebranch/steps/roslyn-analyzers-buildproj-step.yml index 9f58773174..6e9b0e8106 100644 --- a/eng/pipelines/onebranch/steps/roslyn-analyzers-buildproj-step.yml +++ b/eng/pipelines/onebranch/steps/roslyn-analyzers-buildproj-step.yml @@ -129,11 +129,8 @@ parameters: - SqlClient - SqlServer - # The three parameters below mirror build-buildproj-step.yml so the analysis build resolves the - # same package versions as the real build. - # - # Version revision translated to build.proj's BuildNumber property at this boundary. - - name: revision + # Pre-computed assembly file version, translated to build.proj's FileVersion* property here. + - name: fileVersion type: string # Suffix appended to "PackageVersion" to form the build.proj msbuild property that stamps this @@ -165,7 +162,7 @@ steps: -p:Configuration=Release -p:ReferenceType=Package -p:SkipDependencyPack=true - -p:BuildNumber="${{ parameters.revision }}" + -p:FileVersion${{ parameters.versionPropertySuffix }}="${{ parameters.fileVersion }}" -p:PackageVersion${{ parameters.versionPropertySuffix }}="${{ parameters.packageVersion }}" -p:IsolatedBuildPath="$(Agent.TempDirectory)/roslyn" -p:EnableAnalyzers=true diff --git a/eng/pipelines/onebranch/variables/package-variables.yml b/eng/pipelines/onebranch/variables/package-variables.yml index 62afca6605..65fd0867d0 100644 --- a/eng/pipelines/onebranch/variables/package-variables.yml +++ b/eng/pipelines/onebranch/variables/package-variables.yml @@ -7,23 +7,6 @@ # This file contains variables that relate to the various packages that are produced via the # OneBranch official/non-official pipelines. They are grouped by the packages they represent. # -# VERSION STRATEGY -# ================ -# Package versions are computed by Versions.props using one input: -# - BuildNumber ($(Build.BuildNumber), provided by ADO) -# -# The SqlClient *family* (Internal.Logging, Extensions.Abstractions, Microsoft.Data.SqlClient, -# Extensions.Azure, and the AlwaysEncrypted.AzureKeyVaultProvider) shares a single version defined -# by SqlClientNextVersion in src/Microsoft.Data.SqlClient/Versions.props. Microsoft.SqlServer.Server -# is versioned separately by SqlServerNextVersion. -# -# The *NextVersion properties define the base version: -# - On main: X.Y.Z-preview1 → official produces "X.Y.Z-preview1" -# - On release/X.Y: X.Y.Z → official produces "X.Y.Z" -# -# No per-package version variables are needed here — Versions.props is the single source. -# Downstream stages obtain the computed versions via the compute-versions stage. -# # ARTIFACT NAMING # =============== # OneBranch automatically publishes pipeline artifacts from all jobs named as: diff --git a/src/Microsoft.Data.SqlClient/Versions.props b/src/Microsoft.Data.SqlClient/Versions.props index f67997a10f..38df551f3b 100644 --- a/src/Microsoft.Data.SqlClient/Versions.props +++ b/src/Microsoft.Data.SqlClient/Versions.props @@ -31,7 +31,6 @@ 7.1.0-preview3 @@ -50,13 +49,8 @@ not valid in a file version. Start with the suffix-free package base and append the configured file-version build number, which converts a three-part package version such as 1.2.3-preview1 to 1.2.3.42. - - A revision-enabled pipeline supplies a four-part package base such as 1.2.3.42. That base - is already a complete file version, so the following conditional assignment overrides the - fallback instead of producing an invalid five-part version. --> $(SqlClientPackageVersionBase).$(FileVersionBuildNumber) - $(SqlClientPackageVersionBase) @@ -65,18 +59,24 @@ When a build number is provided, the default version is used as the base of the package and file versions. - If a build suffix is provided, this is appended to the package version. This is meant to be - used by automated pre-release systems to indicate the source of the build. + If a build suffix is provided, it is appended as a prerelease tag. This is meant to be used + by automated pre-release systems to indicate the source of the build. - If a build suffix is not provided, no pre-release tag will be added to package version. If - the default version already has a pre-release tag added to it (eg, "7.0.0-preview1") this - will be retained for the package version, but will be stripped off for the file version - (letters are not allowed in file/assembly versions). This is meant to be used by official - build pipelines to generate production-ready builds. + The build number is then appended to any version carrying a prerelease tag — whether that + tag came from the declared version or from the build suffix — so every automated run + produces a distinct package version (eg, "7.0.0-preview1" becomes + "7.0.0-preview1.26238.3"). A version with no prerelease tag is left exactly as declared, + because released packages are not stamped with a build number. The tag is always stripped + for the file version (letters are not allowed in file/assembly versions). This is meant to + be used by official build pipelines to generate production-ready builds. --> - $(SqlClientNextVersion)-$(BuildSuffix)$(BuildNumber) - $(SqlClientNextVersion) + <_SqlClientCandidateVersion>$(SqlClientNextVersion) + <_SqlClientCandidateVersion Condition="'$(BuildSuffix)' != ''">$(SqlClientNextVersion)-$(BuildSuffix) + + + $(_SqlClientCandidateVersion).$(BuildNumber) + $(_SqlClientCandidateVersion) $(SqlClientNextVersion.Split('-')[0]).$(FileVersionBuildNumber) @@ -105,4 +105,11 @@ $(SqlClientFileVersion.Split('.')[0]).0.0.0 + + + + + diff --git a/src/Microsoft.SqlServer.Server/Versions.props b/src/Microsoft.SqlServer.Server/Versions.props index e03f8d2967..a83b5d246a 100644 --- a/src/Microsoft.SqlServer.Server/Versions.props +++ b/src/Microsoft.SqlServer.Server/Versions.props @@ -45,13 +45,8 @@ not valid in a file version. Start with the suffix-free package base and append the configured file-version build number, which converts a three-part package version such as 1.2.3-preview1 to 1.2.3.42. - - A revision-enabled pipeline supplies a four-part package base such as 1.2.3.42. That base - is already a complete file version, so the following conditional assignment overrides the - fallback instead of producing an invalid five-part version. --> $(SqlServerPackageVersionBase).$(FileVersionBuildNumber) - $(SqlServerPackageVersionBase) @@ -60,18 +55,24 @@ When a build number is provided, the default version is used as the base of the package and file versions. - If a build suffix is provided, this is appended to the package version. This is meant to be - used by automated pre-release systems to indicate the source of the build. + If a build suffix is provided, it is appended as a prerelease tag. This is meant to be used + by automated pre-release systems to indicate the source of the build. - If a build suffix is not provided, no pre-release tag will be added to package version. If - the default version already has a pre-release tag added to it (eg, "7.0.0-preview1") this - will be retained for the package version, but will be stripped off for the file version - (letters are not allowed in file/assembly versions). This is meant to be used by official - build pipelines to generate production-ready builds. + The build number is then appended to any version carrying a prerelease tag — whether that + tag came from the declared version or from the build suffix — so every automated run + produces a distinct package version (eg, "1.1.0-preview1" becomes + "1.1.0-preview1.26238.3"). A version with no prerelease tag is left exactly as declared, + because released packages are not stamped with a build number. The tag is always stripped + for the file version (letters are not allowed in file/assembly versions). This is meant to + be used by official build pipelines to generate production-ready builds. --> - $(SqlServerNextVersion)-$(BuildSuffix)$(BuildNumber) - $(SqlServerNextVersion) + <_SqlServerCandidateVersion>$(SqlServerNextVersion) + <_SqlServerCandidateVersion Condition="'$(BuildSuffix)' != ''">$(SqlServerNextVersion)-$(BuildSuffix) + + + $(_SqlServerCandidateVersion).$(BuildNumber) + $(_SqlServerCandidateVersion) $(SqlServerNextVersion.Split('-')[0]).$(FileVersionBuildNumber) @@ -100,4 +101,11 @@ $(SqlServerFileVersion.Split('.')[0]).0.0.0 + + + + +