From f6bbbafefdbaa748240efed95433dc286c4f93c9 Mon Sep 17 00:00:00 2001 From: Paul Medynski <31868385+paulmedynski@users.noreply.github.com> Date: Tue, 8 Jul 2025 08:31:05 -0300 Subject: [PATCH 01/30] User Story 37654: Create Abstractions package - Added empty Extensions package with some sample class and docs to demonstrate packaging. - Created CI stage to build, test, pack, and publish the Extensions NuGet package. - Updated downstream CI stages/jobs to use the Extensions package. - Updated build.proj Clean target to not delete packages/ dir. - Updated BUILDGUIDE with instructions for the Extensions package. - Cleaned up stale BUIDGUIDE sections. - Added temporary GitHub Discussion content so the team can review before posting it as a real Discussion. - Disable .pdb file inclusion in the application package. - Renamed Extensions package to Abstractions. - Updated README related to extensions design. --- .editorconfig | 2 +- BUILDGUIDE.md | 87 +++-- NuGet.config | 5 +- build.proj | 43 ++- .../templates/jobs/ci-build-nugets-job.yml | 31 +- .../templates/jobs/ci-run-tests-job.yml | 20 +- .../templates/stages/ci-run-tests-stage.yml | 16 +- .../templates/steps/build-all-tests-step.yml | 11 +- .../templates/steps/ci-prebuild-step.yml | 7 + .../templates/steps/ci-project-build-step.yml | 17 +- .../update-nuget-config-local-feed-step.yml | 9 +- eng/pipelines/dotnet-sqlclient-ci-core.yml | 172 +++++---- ...qlclient-ci-package-reference-pipeline.yml | 15 +- ...qlclient-ci-project-reference-pipeline.yml | 15 +- .../build-abstractions-package-ci-stage.yml | 351 ++++++++++++++++++ src/Directory.Build.props | 15 + src/Directory.Packages.props | 1 + .../Abstractions/Abstractions.slnx | 8 + .../Abstractions/README.md | 285 ++++++++++++++ .../Abstractions/doc/Sample.xml | 18 + .../Abstractions/src/Abstractions.csproj | 95 +++++ .../Abstractions/src/Sample.cs | 20 + .../test/Abstractions.Test.csproj | 26 ++ .../Abstractions/test/SampleTest.cs | 19 + src/Microsoft.Data.SqlClient.sln | 33 +- src/Microsoft.Data.SqlClient/NuGet.config | 13 + .../ref/Microsoft.Data.SqlClient.csproj | 1 + .../src/Microsoft.Data.SqlClient.csproj | 1 + .../netfx/ref/Microsoft.Data.SqlClient.csproj | 1 + .../netfx/src/Microsoft.Data.SqlClient.csproj | 1 + tools/props/Versions.props | 59 ++- tools/specs/Microsoft.Data.SqlClient.nuspec | 4 + 32 files changed, 1228 insertions(+), 173 deletions(-) create mode 100644 eng/pipelines/stages/build-abstractions-package-ci-stage.yml create mode 100644 src/Microsoft.Data.SqlClient.Extensions/Abstractions/Abstractions.slnx create mode 100644 src/Microsoft.Data.SqlClient.Extensions/Abstractions/README.md create mode 100644 src/Microsoft.Data.SqlClient.Extensions/Abstractions/doc/Sample.xml create mode 100644 src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/Abstractions.csproj create mode 100644 src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/Sample.cs create mode 100644 src/Microsoft.Data.SqlClient.Extensions/Abstractions/test/Abstractions.Test.csproj create mode 100644 src/Microsoft.Data.SqlClient.Extensions/Abstractions/test/SampleTest.cs create mode 100644 src/Microsoft.Data.SqlClient/NuGet.config diff --git a/.editorconfig b/.editorconfig index ff6d9f3bd7..14f37d4e02 100644 --- a/.editorconfig +++ b/.editorconfig @@ -163,7 +163,7 @@ indent_size = 2 indent_size = 2 # Xml files -[*.{xml,stylecop,resx,ruleset}] +[*.{xml,stylecop,resx,ruleset,slnx}] indent_size = 2 # Xml config files diff --git a/BUILDGUIDE.md b/BUILDGUIDE.md index efeb747cad..62dc090372 100644 --- a/BUILDGUIDE.md +++ b/BUILDGUIDE.md @@ -16,28 +16,34 @@ Once the environment is setup properly, execute the desired set of commands belo ### Targets +The following build targets are defined in `build.proj`: + |Target|Description| |-|-| |`BuildAllConfigurations`|Default target. Builds the .NET Framework and .NET drivers for all target frameworks and operating systems.| +|`BuildAbstractionsPackage`|Restore, build, and pack the Abstractions package, publishing the resulting NuGet into `packages/`.| |`BuildNetCore`|Builds the .NET driver for all target frameworks.| |`BuildNetCoreAllOS`|Builds the .NET driver for all target frameworks and operating systems.| |`BuildNetFx`|Builds the .NET Framework driver for all target frameworks.| |`BuildTestsNetCore`|Builds tests for the .NET driver.| |`BuildTestsNetFx`|Builds tests for the .NET Framework driver.| -|`Clean`|Cleans generated files.| -|`Restore`|Restores Nuget packages.| +|`Clean`|Cleans generated files, except for NuGet packages published to `packages/`.| +|`CleanAll`|Cleans all generated files.| +|`Restore`|Restores NuGet packages.| |`RunTests`|Runs the unit, functional, and manual tests for the .NET Framework and .NET drivers| |`RunUnitTests`|Runs just the unit tests for the .NET Framework and .NET drivers| |`RunFunctionalTests`|Runs just the functional tests for the .NET Framework and .NET drivers| |`RunManualTests`|Runs just the manual tests for the .NET Framework and .NET drivers| |`BuildAkv`|Builds the Azure Key Vault Provider package for all supported platforms.| - ### Parameters + +The following parameters may be defined as MSBuild properties to configure the +build: + |Name|Supported Values|Default|Description| |-|-|-|-| |`Configuration`|`Debug`, `Release`|`Debug`|Sets the release configuration.| -|`BuildNetFx`|`true`, `false`|`true` (Windows), `false` (other)|If false, skips building the .NET Framework driver on Windows.| |`OSGroup`|`Unix`, `Windows_NT`, `AnyOS`|typically defaults to the client system's OS, unless using `BuildAllConfigurations` or an `AnyOS` specific target|The operating system to target.| |`Platform`|`AnyCPU`, `x86`, `x64`, `ARM`, `ARM64`|`AnyCPU`|May only be set when using package reference type or running tests.| |`TestSet`|`1`, `2`, `3`, `AE`|all|Build or run a subset of the manual tests. Omit (default) to target all tests.| @@ -45,11 +51,12 @@ Once the environment is setup properly, execute the desired set of commands belo |`TF`|`net8.0`, `net462`, `net47`, `net471`, `net472`, `net48`, `net481`|`net8.0` in netcore, `net462` in netfx|Sets the target framework when building or running tests. Not applicable when building the drivers.| |`ResultsDirectory`|An absolute file path|./TestResults relative to current directory|Specifies where to write test results.| - ## Example Workflows using MSBuild (Recommended) + Using the default configuration and running all tests: ```bash +msbuild -t:BuildAbstractionsPackage msbuild msbuild -t:BuildTestsNetFx -p:TF=net462 msbuild -t:BuildTestsNetCore @@ -59,28 +66,31 @@ msbuild -t:RunTests Using the Release configuration: ```bash -msbuild -p:configuration=Release -msbuild -t:BuildTestsNetFx -p:TF=net462 -p:configuration=Release -msbuild -t:BuildTestsNetCore -p:configuration=Release -msbuild -t:RunTests -p:configuration=Release +msbuild -t:BuildAbstractionsPackage -p:Configuration=Release +msbuild -p:Configuration=Release +msbuild -t:BuildTestsNetFx -p:TF=net462 -p:Configuration=Release +msbuild -t:BuildTestsNetCore -p:Configuration=Release +msbuild -t:RunTests -p:Configuration=Release ``` Running only the unit tests: ```bash +msbuild -t:BuildAbstractionsPackage msbuild msbuild -t:BuildTestsNetFx -p:TF=net462 msbuild -t:BuildTestsNetCore msbuild -t:RunUnitTests ``` -Using a specific dotnet version/architecture: +Using a specific .NET runtime to run tests: ```bash -msbuild -p:configuration=Release -msbuild -t:BuildTestsNetFx -p:TF=net462 -p:configuration=Release -msbuild -t:BuildTestsNetCore -p:configuration=Release -msbuild -t:RunTests -p:configuration=Release -p:DotnetPath=C:\net8-win-x86\ +msbuild -t:BuildAbstractionsPackage +msbuild +msbuild -t:BuildTestsNetFx -p:TF=net462 +msbuild -t:BuildTestsNetCore +msbuild -t:RunTests -p:DotnetPath=C:\net8-win-x86\ ``` ### Running Manual Tests @@ -119,15 +129,13 @@ Manual Tests require the below setup to run: |IsManagedInstance | (Optional) When set to `true` **TVP** related tests will use on non-Azure bs files to compare test results. this is needed when testing against Managed Instances or TVP Tests will fail on Test set 3. The default value is `false`. | |PowerShellPath | The full path to PowerShell.exe. This is not required if the path is present in the PATH environment variable. | `D:\\escaped\\absolute\\path\\to\\PowerShell.exe` | - ## Example workflows using the Dotnet SDK -#### Run Functional Tests +### Run Functional Tests - Windows (`netfx x86`): ```bash -msbuild dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" -p:Platform="x86" -p:Configuration="Release" -p:TestTargetOS="Windowsnetfx" --no-build -v n --filter "category!=nonnetfxtests&category!=failing&category!=nonwindowstests" ``` @@ -152,7 +160,8 @@ dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.S ```bash dotnet test "src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj" -p:Platform="AnyCPU" -p:Configuration="Release" -p:TestTargetOS="Unixnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonlinuxtests&category!=nonuaptests" ``` -#### Run Manual Tests + +### Run Manual Tests - Windows (`netfx x86`): @@ -194,35 +203,40 @@ dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlCl Tests can be built and run with custom "Reference Type" property that enables different styles of testing: -- "Project" => Build and run tests with Microsoft.Data.SqlClient as Project Reference -- "Package" => Build and run tests with Microsoft.Data.SqlClient as Package Reference with configured "TestMicrosoftDataSqlClientVersion" in "Versions.props" file. +- "Project" => Build and run tests with Microsoft.Data.SqlClient as a Project Reference +- "Package" => Build and run tests with Microsoft.Data.SqlClient as a Package Reference with configured "TestMicrosoftDataSqlClientVersion" in "Versions.props" file. > ************** IMPORTANT NOTE BEFORE PROCEEDING WITH "PACKAGE" REFERENCE TYPE *************** > CREATE A NUGET PACKAGE WITH BELOW COMMAND AND ADD TO LOCAL FOLDER + UPDATE NUGET CONFIG FILE TO READ FROM THAT LOCATION > > ```bash -> msbuild -p:configuration=Release +> msbuild -t:BuildAbstractionsPackage -p:Configuration=Release +> msbuild -p:Configuration=Release > ``` A non-AnyCPU platform reference can only be used with package reference type. Otherwise, the specified platform will be replaced with AnyCPU in the build process. ### Building Tests with Reference Type -For .NET, all 4 reference types are supported: +For .NET: ```bash +# Project is the default reference type. The below commands are equivalent: +msbuild -t:BuildTestsNetCore msbuild -t:BuildTestsNetCore -p:ReferenceType=Project -# Default setting uses Project Reference. +# Package reference type: msbuild -t:BuildTestsNetCore -p:ReferenceType=Package ``` -For .NET Framework, below reference types are supported: +For .NET Framework: ```bash +# Project is the default reference type. The below commands are equivalent: +msbuild -t:BuildTestsNetFx -p:TF=net462 msbuild -t:BuildTestsNetFx -p:TF=net462 -p:ReferenceType=Project -# Default setting uses Project Reference. +# Package reference type: msbuild -t:BuildTestsNetFx -p:TF=net462 -p:ReferenceType=Package ``` @@ -241,26 +255,25 @@ Tests can be built and run with custom Target Frameworks. See the below examples ### Building Tests with custom target framework ```bash -msbuild -t:BuildTestsNetFx -p:TF=net462 # Build the tests for custom .NET Framework target +msbuild -t:BuildTestsNetFx -p:TF=net462 ``` ```bash -msbuild -t:BuildTestsNetCore -p:TF=net8.0 # Build the tests for custom .NET target +msbuild -t:BuildTestsNetCore -p:TF=net8.0 ``` ### Running Tests with custom target framework (traditional) ```bash +# Run tests with custom .NET Framework target dotnet test -p:TargetNetFxVersion=net462 ... -# Use above property to run Functional Tests with custom .NET Framework target +# Run tests with custom .NET target dotnet test -p:TargetNetCoreVersion=net8.0 ... -# Use above property to run Functional Tests with custom .NET target ``` - ## Using Managed SNI on Windows Managed SNI can be enabled on Windows by enabling the below AppContext switch: @@ -285,20 +298,6 @@ When connecting to a server, if a protocol lower than TLS 1.2 is negotiated, a s `Switch.Microsoft.Data.SqlClient.SuppressInsecureTLSWarning` -### Troubleshooting Docker issues - -There may be times where connection cannot be made to SQL Server, we found below ideas helpful: - -- Clear Docker images to create clean image from time-to-time, and clear docker cache if needed by running `docker system prune` in Command Prompt. - -- If you face `Microsoft.Data.SqlClient.SNI.dll not found` errors when debugging, try updating the below properties in the netcore\Microsoft.Data.SqlClient.csproj file and try again: - - ```xml - Unix - false - true - ``` - ## Collecting Code Coverage ### Using VSTest diff --git a/NuGet.config b/NuGet.config index d93875f3fb..32e4905f6d 100644 --- a/NuGet.config +++ b/NuGet.config @@ -2,10 +2,13 @@ - + + + + diff --git a/build.proj b/build.proj index 0443bbcf4e..0cf4efd4de 100644 --- a/build.proj +++ b/build.proj @@ -51,6 +51,7 @@ + @@ -91,6 +92,32 @@ + + + + + AbstractionsPackageVersion=$(AbstractionsPackageVersion) + + + + + @@ -346,13 +373,17 @@ - + - - - - - + + + + + + + + + diff --git a/eng/pipelines/common/templates/jobs/ci-build-nugets-job.yml b/eng/pipelines/common/templates/jobs/ci-build-nugets-job.yml index cb3790262c..bd165dac31 100644 --- a/eng/pipelines/common/templates/jobs/ci-build-nugets-job.yml +++ b/eng/pipelines/common/templates/jobs/ci-build-nugets-job.yml @@ -12,9 +12,13 @@ parameters: type: string default: ADO-MMS22-SQL19 - - name: artifactName + - name: abstractionsArtifactName type: string - default: Artifacts + default: Abstractions.Artifact + + - name: mdsArtifactName + type: string + default: MDS.Artifact - name: platform type: string @@ -28,6 +32,11 @@ parameters: type: stepList default: [] + - name: abstractionsPackageVersion + displayName: Abstractions Package Version Override + type: string + default: '' + jobs: - job: build_nugets @@ -44,12 +53,22 @@ jobs: - ${{ if ne(parameters.prebuildSteps, '') }}: - ${{ parameters.prebuildSteps }} # extra steps to run before the build like downloading sni and the required configuration + # Download the Abstractions package artifacts and put them in the packages/ + # directory in the repo root. This is where the MDS NuGet.config file will + # look for local packages. + - task: DownloadPipelineArtifact@2 + displayName: Download Abstractions Package Artifact + inputs: + artifactName: ${{ parameters.abstractionsArtifactName }} + targetPath: $(Build.SourcesDirectory)/packages + - template: ../steps/ci-project-build-step.yml@self parameters: platform: ${{ parameters.platform }} configuration: ${{ parameters.configuration }} operatingSystem: Windows build: all + abstractionsPackageVersion: ${{parameters.abstractionsPackageVersion}} - template: ../steps/generate-nuget-package-step.yml@self parameters: @@ -70,8 +89,8 @@ jobs: installNuget: false displayName: 'Generate NuGet package AKV Provider' - - task: PublishBuildArtifacts@1 - displayName: 'Publish Artifact: Artifacts' + - task: PublishPipelineArtifact@1 + displayName: 'Publish Pipeline Artifact' inputs: - PathtoPublish: $(packagePath) - ArtifactName: ${{ parameters.artifactName }} + targetPath: $(packagePath) + artifactName: ${{ parameters.mdsArtifactName }} diff --git a/eng/pipelines/common/templates/jobs/ci-run-tests-job.yml b/eng/pipelines/common/templates/jobs/ci-run-tests-job.yml index dbf5b10028..20cf0cd33d 100644 --- a/eng/pipelines/common/templates/jobs/ci-run-tests-job.yml +++ b/eng/pipelines/common/templates/jobs/ci-run-tests-job.yml @@ -29,13 +29,18 @@ parameters: type: object default: {} # - key: 'value' + - name: abstractionsPackageVersion + displayName: Abstractions Package Version Override + type: string + default: '' + - name: prebuildSteps type: stepList default: [] - - name: artifactName + - name: abstractionsArtifactName type: string - default: Artifacts + default: Abstractions.Artifact - name: targetFramework type: string @@ -98,6 +103,16 @@ jobs: value: '$(dotnetx86Path)' steps: + + # Download the Abstractions package artifacts and put them in the packages/ + # directory in the repo root. This is where the MDS NuGet.config file will + # look for local packages. + - task: DownloadPipelineArtifact@2 + displayName: Download Abstractions Package Artifact + inputs: + artifactName: ${{ parameters.abstractionsArtifactName }} + targetPath: $(Build.SourcesDirectory)/packages + - ${{ if ne(parameters.prebuildSteps, '') }}: - ${{ parameters.prebuildSteps }} # extra steps to run before the build like downloading sni and the required configuration @@ -229,6 +244,7 @@ jobs: targetFramework: ${{ parameters.targetFramework }} referenceType: ${{ parameters.buildType }} testSet: ${{ parameters.testSet }} + abstractionsPackageVersion: ${{ parameters.abstractionsPackageVersion }} ${{ if ne(parameters.operatingSystem, 'Windows') }}: OSGroup: Unix diff --git a/eng/pipelines/common/templates/stages/ci-run-tests-stage.yml b/eng/pipelines/common/templates/stages/ci-run-tests-stage.yml index e07685407f..da73ca4eb2 100644 --- a/eng/pipelines/common/templates/stages/ci-run-tests-stage.yml +++ b/eng/pipelines/common/templates/stages/ci-run-tests-stage.yml @@ -12,8 +12,8 @@ parameters: type: object - name: dependsOn - type: string - default: '' + type: object + default: [] - name: buildType displayName: 'Build Type' @@ -22,6 +22,11 @@ parameters: - Project - Package + - name: abstractionsPackageVersion + displayName: Abstractions Package Version Override + type: string + default: '' + - name: prebuildSteps type: stepList default: [] @@ -39,10 +44,7 @@ stages: - ${{ each config in parameters.testConfigurations }}: - ${{ each image in config.value.images }}: - stage: ${{ image.key }} - ${{ if ne(parameters.dependsOn, '') }}: - dependsOn: ${{ parameters.dependsOn }} - ${{ else }}: - dependsOn: [] + dependsOn: ${{ parameters.dependsOn }} jobs: - ${{ each targetFramework in config.value.TargetFrameworks }}: - ${{ each platform in config.value.buildPlatforms }}: @@ -58,6 +60,7 @@ stages: image: ${{ image.value }} jobDisplayName: ${{ format('{0}_{1}_{2}', replace(targetFramework, '.', '_'), platform, testSet) }} configProperties: ${{ config.value.configProperties }} + abstractionsPackageVersion: ${{ parameters.abstractionsPackageVersion }} prebuildSteps: ${{ parameters.prebuildSteps }} targetFramework: ${{ targetFramework }} netcoreVersionTestUtils: ${{config.value.netcoreVersionTestUtils }} @@ -88,6 +91,7 @@ stages: jobDisplayName: ${{ format('{0}_{1}_{2}_{3}', replace(targetFramework, '.', '_'), platform, 'NativeSNI', testSet) }} configProperties: ${{ config.value.configProperties }} useManagedSNI: ${{ useManagedSNI }} + abstractionsPackageVersion: ${{ parameters.abstractionsPackageVersion }} prebuildSteps: ${{ parameters.prebuildSteps }} targetFramework: ${{ targetFramework }} netcoreVersionTestUtils: ${{config.value.netcoreVersionTestUtils }} diff --git a/eng/pipelines/common/templates/steps/build-all-tests-step.yml b/eng/pipelines/common/templates/steps/build-all-tests-step.yml index 826be1df8b..a953d832d5 100644 --- a/eng/pipelines/common/templates/steps/build-all-tests-step.yml +++ b/eng/pipelines/common/templates/steps/build-all-tests-step.yml @@ -32,6 +32,11 @@ parameters: - name: testSet type: string + - name: abstractionsPackageVersion + displayName: Abstractions Package Version Override + type: string + default: '' + steps: - ${{ if contains(parameters.targetFramework, 'net4') }}: # .NET Framework - task: MSBuild@1 @@ -40,7 +45,7 @@ steps: solution: build.proj platform: '${{parameters.platform }}' configuration: '${{parameters.configuration }}' - msbuildArguments: '-t:BuildTestsNetFx -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.nugetPackageVersion }}' + msbuildArguments: '-t:BuildTestsNetFx -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.nugetPackageVersion }} -p:AbstractionsPackageVersion=${{ parameters.abstractionsPackageVersion }}.$(Build.BuildNumber)' # - ${{else if contains(parameters.targetFramework, 'netstandard')}}: # .NET Standard # - task: MSBuild@1 @@ -59,7 +64,7 @@ steps: solution: build.proj platform: '${{parameters.platform }}' configuration: '${{parameters.configuration }}' - msbuildArguments: '-t:BuildTestsNetCore -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.nugetPackageVersion }}' + msbuildArguments: '-t:BuildTestsNetCore -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.nugetPackageVersion }} -p:AbstractionsPackageVersion=${{ parameters.abstractionsPackageVersion }}.$(Build.BuildNumber)' condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT')) - ${{ else }}: # .NET on Unix @@ -69,7 +74,7 @@ steps: command: custom projects: build.proj custom: msbuild - arguments: '-t:BuildTestsNetCore -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.nugetPackageVersion }} -p:OSGroup=${{parameters.OSGroup }} -p:platform=${{parameters.platform }} -p:Configuration=${{parameters.configuration }}' + arguments: '-t:BuildTestsNetCore -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.nugetPackageVersion }} -p:OSGroup=${{parameters.OSGroup }} -p:platform=${{parameters.platform }} -p:Configuration=${{parameters.configuration }} -p:AbstractionsPackageVersion=${{ parameters.abstractionsPackageVersion }}.$(Build.BuildNumber)' verbosityRestore: Detailed verbosityPack: Detailed condition: and(succeeded(), ne(variables['Agent.OS'], 'Windows_NT')) diff --git a/eng/pipelines/common/templates/steps/ci-prebuild-step.yml b/eng/pipelines/common/templates/steps/ci-prebuild-step.yml index efe17856d8..48cab965ea 100644 --- a/eng/pipelines/common/templates/steps/ci-prebuild-step.yml +++ b/eng/pipelines/common/templates/steps/ci-prebuild-step.yml @@ -19,6 +19,11 @@ parameters: - Project - Package + - name: abstractionsPackageVersion + displayName: Abstractions Package Version Override + type: string + default: '' + steps: - template: ensure-dotnet-version.yml parameters: @@ -50,8 +55,10 @@ steps: parameters: downloadedNugetPath: $(Pipeline.Workspace)\${{parameters.artifactName }} debug: ${{ parameters.debug }} + abstractionsPackageVersion: ${{ parameters.abstractionsPackageVersion }} - ${{ else }}: # project - template: ci-project-build-step.yml@self parameters: build: allNoDocs + abstractionsPackageVersion: ${{parameters.abstractionsPackageVersion}} diff --git a/eng/pipelines/common/templates/steps/ci-project-build-step.yml b/eng/pipelines/common/templates/steps/ci-project-build-step.yml index e938c909fd..1edcdb1b51 100644 --- a/eng/pipelines/common/templates/steps/ci-project-build-step.yml +++ b/eng/pipelines/common/templates/steps/ci-project-build-step.yml @@ -34,6 +34,11 @@ parameters: - all - allNoDocs + - name: abstractionsPackageVersion + displayName: Abstractions Package Version Override + type: string + default: '' + steps: - template: ./ensure-dotnet-version.yml@self parameters: @@ -53,7 +58,7 @@ steps: inputs: solution: build.proj msbuildArchitecture: x64 - msbuildArguments: '-t:restore' + msbuildArguments: '-t:restore -p:AbstractionsPackageVersion=${{parameters.abstractionsPackageVersion}}.${{parameters.buildNumber}}' retryCountOnTaskFailure: 1 - ${{ if eq(parameters.build, 'allNoDocs') }}: @@ -65,7 +70,7 @@ steps: msbuildArchitecture: x64 platform: '${{ parameters.platform }}' configuration: '${{ parameters.configuration }}' - msbuildArguments: '-t:BuildAllConfigurations -p:GenerateDocumentationFile=false -p:GenerateNuGet=false -p:BuildNumber=${{ parameters.buildNumber }}' + msbuildArguments: '-t:BuildAllConfigurations -p:GenerateDocumentationFile=false -p:GenerateNuGet=false -p:BuildNumber=${{ parameters.buildNumber }} -p:AbstractionsPackageVersion=${{parameters.abstractionsPackageVersion}}.${{parameters.buildNumber}}' clean: true - ${{ if or(eq(parameters.build, 'MDS'), eq(parameters.build, 'all')) }}: @@ -77,7 +82,7 @@ steps: msbuildArchitecture: x64 platform: '${{ parameters.platform }}' configuration: '${{ parameters.configuration }}' - msbuildArguments: '-t:BuildAllConfigurations -p:GenerateNuGet=false -p:BuildNumber=${{ parameters.buildNumber }}' + msbuildArguments: '-t:BuildAllConfigurations -p:GenerateNuGet=false -p:BuildNumber=${{ parameters.buildNumber }} -p:AbstractionsPackageVersion=${{parameters.abstractionsPackageVersion}}.${{parameters.buildNumber}}' clean: true - ${{ if or(eq(parameters.build, 'AKV'), eq(parameters.build, 'all'), eq(parameters.build, 'allNoDocs')) }}: @@ -89,7 +94,7 @@ steps: msbuildArchitecture: x64 platform: '${{ parameters.platform }}' configuration: '${{ parameters.configuration }}' - msbuildArguments: '-t:BuildAKVNetFx -p:BuildNumber=${{ parameters.buildNumber }}' + msbuildArguments: '-t:BuildAKVNetFx -p:BuildNumber=${{ parameters.buildNumber }} -p:AbstractionsPackageVersion=${{parameters.abstractionsPackageVersion}}.${{parameters.buildNumber}}' - task: MSBuild@1 displayName: 'Build AKV Provider NetCore All OS [Win]' @@ -99,7 +104,7 @@ steps: msbuildArchitecture: x64 platform: '${{ parameters.platform }}' configuration: '${{ parameters.configuration }}' - msbuildArguments: '-t:BuildAKVNetCoreAllOS -p:BuildNumber=${{ parameters.buildNumber }}' + msbuildArguments: '-t:BuildAKVNetCoreAllOS -p:BuildNumber=${{ parameters.buildNumber }} -p:AbstractionsPackageVersion=${{parameters.abstractionsPackageVersion}}.${{parameters.buildNumber}}' - ${{ if or(eq(parameters.operatingSystem, 'Linux'), eq(parameters.operatingSystem, 'MacOS'), eq(parameters.operatingSystem, 'deferedToRuntime')) }}: - task: DotNetCoreCLI@2 @@ -109,7 +114,7 @@ steps: command: custom projects: build.proj custom: msbuild - arguments: '-t:BuildAll -p:TestEnabled=true -p:GenerateDocumentationFile=false -p:configuration=${{ parameters.configuration }}' + arguments: '-t:BuildAll -p:TestEnabled=true -p:GenerateDocumentationFile=false -p:configuration=${{ parameters.configuration }} -p:AbstractionsPackageVersion=${{parameters.abstractionsPackageVersion}}.${{parameters.buildNumber}}' verbosityRestore: Detailed verbosityPack: Detailed retryCountOnTaskFailure: 1 diff --git a/eng/pipelines/common/templates/steps/update-nuget-config-local-feed-step.yml b/eng/pipelines/common/templates/steps/update-nuget-config-local-feed-step.yml index 4eac341108..6753a14b48 100644 --- a/eng/pipelines/common/templates/steps/update-nuget-config-local-feed-step.yml +++ b/eng/pipelines/common/templates/steps/update-nuget-config-local-feed-step.yml @@ -11,6 +11,11 @@ parameters: - name: downloadedNugetPath # path to the downloaded nuget files type: string + - name: abstractionsPackageVersion + displayName: Abstractions Package Version Override + type: string + default: '' + - name: nugetPackageVersion type: string default: $(NugetPackageVersion) @@ -34,7 +39,7 @@ steps: [Xml] $nugetConfig = Get-Content -Path "NuGet.config" $Value = Resolve-Path ${{parameters.downloadedNugetPath }} $newAdd = $nugetConfig.CreateElement("add") - $newAdd.SetAttribute("key","Package source") + $newAdd.SetAttribute("key","pipeline") $newAdd.SetAttribute("value", "$Value/" ) $nugetConfig.configuration.packageSources.AppendChild($newAdd) $nugetConfig.Save("$rootFolder/NuGet.config") @@ -51,7 +56,7 @@ steps: inputs: command: 'custom' custom: 'msbuild' - arguments: 'build.proj -t:restore' + arguments: 'build.proj -t:restore -p:AbstractionsPackageVersion=${{parameters.abstractionsPackageVersion}}.$(buildNumber)' feedsToUse: 'select' - powershell: | diff --git a/eng/pipelines/dotnet-sqlclient-ci-core.yml b/eng/pipelines/dotnet-sqlclient-ci-core.yml index 353122828b..7415169212 100644 --- a/eng/pipelines/dotnet-sqlclient-ci-core.yml +++ b/eng/pipelines/dotnet-sqlclient-ci-core.yml @@ -34,6 +34,11 @@ parameters: type: object default: [1, 2, 3] +- name: abstractionsPackageVersion + displayName: Abstractions Package Version Override + type: string + default: '' + - name: useManagedSNI displayName: | Use Managed/Native SNI on Windows, @@ -89,20 +94,39 @@ parameters: variables: - template: libraries/ci-build-variables.yml@self - - name: artifactName - value: Artifacts + - name: abstractionsArtifactName + value: Abstractions.Artifact + + - name: mdsArtifactName + value: MDS.Artifact - name: defaultHostedPoolName value: 'Azure Pipelines' stages: + + # Build the Abstractions package, and publish it to the pipeline artifacts + # under the name specified by the 'abstractionsArtifactName' variable. + - template: stages/build-abstractions-package-ci-stage.yml@self + parameters: + buildConfiguration: Release + packageVersion: ${{parameters.abstractionsPackageVersion}} + buildNumber: $(buildNumber) + artifactName: $(abstractionsArtifactName) + ${{if eq(parameters.debug, 'true')}}: + verbosity: diagnostic + + # Build MDS and its NuGet packages. - stage: build_nugets displayName: 'Build NuGet Packages' + dependsOn: build_abstractions_package_stage jobs: - template: common/templates/jobs/ci-build-nugets-job.yml@self parameters: configuration: ${{ parameters.buildConfiguration }} - artifactName: $(artifactName) + abstractionsPackageVersion: ${{parameters.abstractionsPackageVersion}} + abstractionsArtifactName: $(abstractionsArtifactName) + mdsArtifactName: $(mdsArtifactName) ${{if ne(parameters.SNIVersion, '')}}: prebuildSteps: - template: common/templates/steps/override-sni-version.yml@self @@ -125,8 +149,19 @@ stages: debug: ${{ parameters.debug }} buildType: ${{ parameters.buildType }} testsTimeout: ${{ parameters.testsTimeout }} + abstractionsPackageVersion: ${{parameters.abstractionsPackageVersion}} + + # When testing MDS via packages, we must depend on the Abstractions _and_ + # MDS packages. ${{ if eq(parameters.buildType, 'Package') }}: - dependsOn: build_nugets + dependsOn: + - build_abstractions_package_stage + - build_nugets + # When testing MDS via projects, we only depend on the Abstrations + # package. + ${{ else }}: + dependsOn: + - build_abstractions_package_stage ${{if ne(parameters.SNIVersion, '')}}: prebuildSteps: # steps to run prior to building and running tests on each job @@ -137,15 +172,17 @@ stages: - template: common/templates/steps/ci-prebuild-step.yml@self parameters: debug: ${{ parameters.debug }} - artifactName: $(artifactName) + artifactName: $(mdsArtifactName) buildType: ${{ parameters.buildType }} + abstractionsPackageVersion: ${{parameters.abstractionsPackageVersion}} ${{else}}: prebuildSteps: # steps to run prior to building and running tests on each job - template: common/templates/steps/ci-prebuild-step.yml@self parameters: debug: ${{ parameters.debug }} - artifactName: $(artifactName) + artifactName: $(mdsArtifactName) buildType: ${{ parameters.buildType }} + abstractionsPackageVersion: ${{parameters.abstractionsPackageVersion}} ${{ if eq(parameters.buildType, 'Project') }}: # only run the code coverage job if the build type is project postTestJobs: # jobs to run after the tests are done @@ -354,9 +391,8 @@ stages: # ways to detect if they were present) won't run consistently across forks and non-forks. ${{ if eq(variables['system.pullRequest.isFork'], 'False') }}: AADPasswordConnectionString: $(AAD_PASSWORD_CONN_STR) - AADServicePrincipalId: $(AADServicePrincipalId) - ${{ if eq(variables['system.pullRequest.isFork'], 'False') }}: AADServicePrincipalSecret: $(AADServicePrincipalSecret) + AADServicePrincipalId: $(AADServicePrincipalId) AzureKeyVaultUrl: $(AzureKeyVaultUrl) AzureKeyVaultTenantId: $(AzureKeyVaultTenantId) SupportsIntegratedSecurity: false @@ -383,9 +419,8 @@ stages: AADAuthorityURL: $(AADAuthorityURL) ${{ if eq(variables['system.pullRequest.isFork'], 'False') }}: AADPasswordConnectionString: $(AAD_PASSWORD_CONN_STR_eastus) - AADServicePrincipalId: $(AADServicePrincipalId) - ${{ if eq(variables['system.pullRequest.isFork'], 'False') }}: AADServicePrincipalSecret: $(AADServicePrincipalSecret) + AADServicePrincipalId: $(AADServicePrincipalId) AzureKeyVaultUrl: $(AzureKeyVaultUrl) AzureKeyVaultTenantId: $(AzureKeyVaultTenantId) SupportsIntegratedSecurity: false @@ -393,37 +428,6 @@ stages: LocalDbAppName: $(LocalDbAppName) LocalDbSharedInstanceName: $(LocalDbSharedInstanceName) - ${{ if eq(variables['system.pullRequest.isFork'], 'False') }}: # only run enclave jobs if the password is available - windows_enclave_sql: - pool: ADO-CI-AE-1ES-Pool - images: - Win22_Enclave_Sql19: ADO-MMS22-SQL19 - TargetFrameworks: ${{parameters.targetFrameworks }} - netcoreVersionTestUtils: ${{parameters.netcoreVersionTestUtils }} - buildPlatforms: ${{parameters.buildPlatforms }} - testSets: [AE] - useManagedSNI: ${{parameters.useManagedSNI }} - codeCovTargetFrameworks: ${{parameters.codeCovTargetFrameworks }} - configSqlFor: enclave - operatingSystem: Windows - configProperties: - # config.json properties - TCPConnectionStringHGSVBS: $(SQL_TCP_CONN_STRING_HGSVBS) - TCPConnectionStringNoneVBS: $(SQL_TCP_CONN_STRING_NoneVBS) - TCPConnectionStringAASSGX: $(SQL_TCP_CONN_STRING_AASSGX) - EnclaveEnabled: true - AADAuthorityURL: $(AADAuthorityURL) - AADServicePrincipalId: $(AADServicePrincipalId) - ${{ if eq(variables['system.pullRequest.isFork'], 'False') }}: - AADServicePrincipalSecret: $(AADServicePrincipalSecret) - AzureKeyVaultUrl: $(AzureKeyVaultUrl) - AzureKeyVaultTenantId: $(AzureKeyVaultTenantId) - SupportsIntegratedSecurity: $(SupportsIntegratedSecurity) - UserManagedIdentityClientId: $(UserManagedIdentityClientId) - AliasName: $(SQLAliasName) - LocalDbAppName: $(LocalDbAppName) - LocalDbSharedInstanceName: $(LocalDbSharedInstanceName) - # self hosted SQL Server on Linux linux_sql_19_22: pool: ${{parameters.defaultPoolName }} @@ -469,9 +473,8 @@ stages: AADAuthorityURL: $(AADAuthorityURL) ${{ if eq(variables['system.pullRequest.isFork'], 'False') }}: AADPasswordConnectionString: $(AAD_PASSWORD_CONN_STR) - AADServicePrincipalId: $(AADServicePrincipalId) - ${{ if eq(variables['system.pullRequest.isFork'], 'False') }}: AADServicePrincipalSecret: $(AADServicePrincipalSecret) + AADServicePrincipalId: $(AADServicePrincipalId) AzureKeyVaultUrl: $(AzureKeyVaultUrl) AzureKeyVaultTenantId: $(AzureKeyVaultTenantId) SupportsIntegratedSecurity: false @@ -479,7 +482,65 @@ stages: LocalDbAppName: $(LocalDbAppName) LocalDbSharedInstanceName: $(LocalDbSharedInstanceName) - ${{ if eq(variables['system.pullRequest.isFork'], 'False') }}: # only run enclave jobs if the password is available + # Self hosted SQL Server on Mac + mac_sql_22: + pool: $(defaultHostedPoolName) + hostedPool: true + images: + MacOSLatest_Sql22: macos-latest + TargetFrameworks: ${{parameters.targetFrameworksLinux }} + netcoreVersionTestUtils: ${{parameters.netcoreVersionTestUtils }} + buildPlatforms: [AnyCPU] + testSets: ${{parameters.testSets }} + useManagedSNI: [true] + codeCovTargetFrameworks: ${{parameters.codeCovTargetFrameworks }} + configSqlFor: local + operatingSystem: Mac + configProperties: + # config.json properties + TCPConnectionString: $(SQL_TCP_CONN_STRING) + NPConnectionString: $(SQL_NP_CONN_STRING) + SupportsIntegratedSecurity: false + ManagedIdentitySupported: false + LocalDbAppName: $(LocalDbAppName) + LocalDbSharedInstanceName: $(LocalDbSharedInstanceName) + + # Enclave tests + # + # Only run enclave jobs if the password is available, which it won't be + # for forked PRs. + # + ${{ if eq(variables['system.pullRequest.isFork'], 'False') }}: + windows_enclave_sql: + pool: ADO-CI-AE-1ES-Pool + images: + Win22_Enclave_Sql19: ADO-MMS22-SQL19 + TargetFrameworks: ${{parameters.targetFrameworks }} + netcoreVersionTestUtils: ${{parameters.netcoreVersionTestUtils }} + buildPlatforms: ${{parameters.buildPlatforms }} + testSets: [AE] + useManagedSNI: ${{parameters.useManagedSNI }} + codeCovTargetFrameworks: ${{parameters.codeCovTargetFrameworks }} + configSqlFor: enclave + operatingSystem: Windows + configProperties: + # config.json properties + TCPConnectionStringHGSVBS: $(SQL_TCP_CONN_STRING_HGSVBS) + TCPConnectionStringNoneVBS: $(SQL_TCP_CONN_STRING_NoneVBS) + TCPConnectionStringAASSGX: $(SQL_TCP_CONN_STRING_AASSGX) + EnclaveEnabled: true + AADAuthorityURL: $(AADAuthorityURL) + AADServicePrincipalId: $(AADServicePrincipalId) + ${{ if eq(variables['system.pullRequest.isFork'], 'False') }}: + AADServicePrincipalSecret: $(AADServicePrincipalSecret) + AzureKeyVaultUrl: $(AzureKeyVaultUrl) + AzureKeyVaultTenantId: $(AzureKeyVaultTenantId) + SupportsIntegratedSecurity: $(SupportsIntegratedSecurity) + UserManagedIdentityClientId: $(UserManagedIdentityClientId) + AliasName: $(SQLAliasName) + LocalDbAppName: $(LocalDbAppName) + LocalDbSharedInstanceName: $(LocalDbSharedInstanceName) + linux_enclave_sql: pool: ADO-CI-AE-1ES-Pool images: @@ -507,26 +568,3 @@ stages: UserManagedIdentityClientId: $(UserManagedIdentityClientId) LocalDbAppName: $(LocalDbAppName) LocalDbSharedInstanceName: $(LocalDbSharedInstanceName) - - # Self hosted SQL Server on Mac - mac_sql_22: - pool: $(defaultHostedPoolName) - hostedPool: true - images: - MacOSLatest_Sql22: macos-latest - TargetFrameworks: ${{parameters.targetFrameworksLinux }} - netcoreVersionTestUtils: ${{parameters.netcoreVersionTestUtils }} - buildPlatforms: [AnyCPU] - testSets: ${{parameters.testSets }} - useManagedSNI: [true] - codeCovTargetFrameworks: ${{parameters.codeCovTargetFrameworks }} - configSqlFor: local - operatingSystem: Mac - configProperties: - # config.json properties - TCPConnectionString: $(SQL_TCP_CONN_STRING) - NPConnectionString: $(SQL_NP_CONN_STRING) - SupportsIntegratedSecurity: false - ManagedIdentitySupported: false - LocalDbAppName: $(LocalDbAppName) - LocalDbSharedInstanceName: $(LocalDbSharedInstanceName) diff --git a/eng/pipelines/dotnet-sqlclient-ci-package-reference-pipeline.yml b/eng/pipelines/dotnet-sqlclient-ci-package-reference-pipeline.yml index 336bd97ab5..e6da796d05 100644 --- a/eng/pipelines/dotnet-sqlclient-ci-package-reference-pipeline.yml +++ b/eng/pipelines/dotnet-sqlclient-ci-package-reference-pipeline.yml @@ -62,6 +62,11 @@ parameters: # parameters are shown up in ADO UI in a build queue time type: object default: [1, 2, 3] +- name: abstractionsPackageVersion + displayName: Abstractions Package Version Override + type: string + default: 1.0.0 + - name: useManagedSNI displayName: | Use Managed/Native SNI on Windows, @@ -74,13 +79,6 @@ parameters: # parameters are shown up in ADO UI in a build queue time type: object default: [net462, net8.0] -- name: buildType - displayName: 'Build Type' - default: Package - values: - - Project - - Package - - name: buildConfiguration displayName: 'Build Configuration' default: Release @@ -107,9 +105,10 @@ extends: targetFrameworksLinux: ${{ parameters.targetFrameworksLinux }} buildPlatforms: ${{ parameters.buildPlatforms }} testSets: ${{ parameters.testSets }} + abstractionsPackageVersion: ${{ parameters.abstractionsPackageVersion }} useManagedSNI: ${{ parameters.useManagedSNI }} codeCovTargetFrameworks: ${{ parameters.codeCovTargetFrameworks }} - buildType: ${{ parameters.buildType }} + buildType: Package buildConfiguration: ${{ parameters.buildConfiguration }} enableStressTests: ${{ parameters.enableStressTests }} testsTimeout: ${{ parameters.testsTimeout }} diff --git a/eng/pipelines/dotnet-sqlclient-ci-project-reference-pipeline.yml b/eng/pipelines/dotnet-sqlclient-ci-project-reference-pipeline.yml index 38325d38ca..ba17cf1fa5 100644 --- a/eng/pipelines/dotnet-sqlclient-ci-project-reference-pipeline.yml +++ b/eng/pipelines/dotnet-sqlclient-ci-project-reference-pipeline.yml @@ -54,6 +54,11 @@ parameters: # parameters are shown up in ADO UI in a build queue time type: object default: [1, 2, 3] +- name: abstractionsPackageVersion + displayName: Abstractions Package Version Override + type: string + default: 1.0.0 + - name: useManagedSNI displayName: | Use Managed/Native SNI on Windows, @@ -66,13 +71,6 @@ parameters: # parameters are shown up in ADO UI in a build queue time type: object default: [net462, net8.0] -- name: buildType - displayName: 'Build Type' - default: Project - values: - - Project - - Package - - name: buildConfiguration displayName: 'Build Configuration' default: Release @@ -99,9 +97,10 @@ extends: targetFrameworksLinux: ${{ parameters.targetFrameworksLinux }} buildPlatforms: ${{ parameters.buildPlatforms }} testSets: ${{ parameters.testSets }} + abstractionsPackageVersion: ${{ parameters.abstractionsPackageVersion }} useManagedSNI: ${{ parameters.useManagedSNI }} codeCovTargetFrameworks: ${{ parameters.codeCovTargetFrameworks }} - buildType: ${{ parameters.buildType }} + buildType: Project buildConfiguration: ${{ parameters.buildConfiguration }} enableStressTests: ${{ parameters.enableStressTests }} testsTimeout: ${{ parameters.testsTimeout }} diff --git a/eng/pipelines/stages/build-abstractions-package-ci-stage.yml b/eng/pipelines/stages/build-abstractions-package-ci-stage.yml new file mode 100644 index 0000000000..4a8b0087df --- /dev/null +++ b/eng/pipelines/stages/build-abstractions-package-ci-stage.yml @@ -0,0 +1,351 @@ +################################################################################ +# Licensed to the .NET Foundation under one or more agreements. The .NET +# Foundation licenses this file to you under the MIT license. See the LICENSE +# file in the project root for more information. +################################################################################ + +# This stage builds the Abstractions package, runs tests, and publishes the +# resulting NuGet packages as pipeline artifacts. +# +# The NuGet packages have the following properties: +# +# Name: Microsoft.Data.SqlClient.Extensions.Abstractions Version: +# . +# +# Where and are the values of the +# 'packageVersion' and 'buildNumber' parameters, respectively. +# +# The following NuGet packages are published: +# +# Microsoft.Data.SqlClient.Extensions.Abstractions..nupkg +# Microsoft.Data.SqlClient.Extensions.Abstractions..snupkg (symbols) +# +# The packages are published to pipeline artifacts with the name specified by +# the 'artifactName' parameter. +# +# This template defines a stage named 'build_abstractions_package_stage' that +# can be depended on by downstream stages. + +parameters: + # The type of build to produce (Release or Debug) + - name: buildConfiguration + displayName: Build Configuration + type: string + default: Release + values: + - Release + - Debug + + # The version (Major.Minor.Patch) to apply to the package. + - name: packageVersion + displayName: Package Version Override + type: string + default: '' + + # The build number of the pipeline. + - name: buildNumber + displayName: Build Number + type: string + default: $(Build.BuildNumber) + + # The name of the pipeline artifact to publish. + - name: artifactName + displayName: Pipeline Artifact Name + type: string + default: Abstractions.Artifact + + # The list of .NET runtimes to test against. + - name: netTestRuntimes + displayName: .NET Test Runtimes + type: object + default: [net8.0, net9.0] + + # The list of .NET Framework runtimes to test against. + - name: netFrameworkTestRuntimes + displayName: .NET Framework Test Runtimes + type: object + default: [net462, net47, net471, net472, net48, net481] + + # The verbosity level for the dotnet CLI commands. + - name: verbosity + displayName: Dotnet CLI verbosity + type: string + default: normal + values: + - quiet + - minimal + - normal + - detailed + - diagnostic + +stages: + - stage: build_abstractions_package_stage + displayName: Build Abstractions Package + + variables: + # The directory where dotnet artifacts will be staged. Not to be + # confused with pipeline artifact. + - name: dotnetArtifactsDir + value: $(Build.StagingDirectory)/dotnetArtifacts + + # The directory where the NuGet packages will be staged before being + # published as pipeline artifacts. + - name: dotnetPackagesDir + value: $(Build.StagingDirectory)/dotnetPackages + + # The Abstractions solution file to use for all dotnet CLI commands. + - name: project + value: src/Microsoft.Data.SqlClient.Extensions/Abstractions/Abstractions.slnx + + # dotnet CLI arguments common to all commands. + - name: commonArguments + value: >- + --verbosity ${{parameters.verbosity}} + --artifacts-path $(dotnetArtifactsDir) + + # dotnet CLI arguments for build/test/pack commands + - name: buildArguments + value: >- + $(commonArguments) + --configuration ${{parameters.buildConfiguration}} + -p:BuildNumber=$(Build.BuildNumber) + -p:AbstractionsPackageVersion=${{parameters.packageVersion}} + + # Explicitly unset the $PLATFORM environment variable that is set by the + # 'ADO Build properties' Library in the ADO SqlClientDrivers public + # project. This is defined with a non-standard Platform of 'AnyCPU', + # and will fail the builds if left defined. The Abstractions package does + # not require any specific Platform, and so its solution file doesn't + # support any non-standard platforms. + # + # Note that Azure Pipelines will inject this variable as PLATFORM into + # the environment of all tasks in this job. + # + # See: + # https://learn.microsoft.com/en-us/azure/devops/pipelines/process/variables?view=azure-devops&tabs=yaml%2Cbatch + # + - name: Platform + value: '' + + # Do the same for $CONFIGURATION since we explicitly set it using our + # 'buildConfiguration' parameter, and we don't want the environment to + # override us. + - name: Configuration + value: '' + + jobs: + + # -------------------------------------------------------------------------- + # Build and test on Linux. + + - job: build_abstractions_package_job_linux + displayName: '[Linux] Build Abstractions Package' + pool: + name: Azure Pipelines + vmImage: ubuntu-latest + + steps: + + - task: UseDotNet@2 + displayName: Install .NET 9.0 SDK + inputs: + packageType: sdk + version: 9.x + + - task: UseDotNet@2 + displayName: Install .NET 8.0 Runtime + inputs: + packageType: runtime + version: 8.x + + # We use the 'custom' command because the DotNetCoreCLI@2 task doesn't + # support all of our argument combinations for the different build steps. + - task: DotNetCoreCLI@2 + displayName: Restore Solution + inputs: + command: custom + custom: restore + projects: $(project) + arguments: $(commonArguments) + + - task: DotNetCoreCLI@2 + displayName: Build Solution + inputs: + command: custom + custom: build + projects: $(project) + arguments: $(buildArguments) --no-restore + + - ${{ each runtime in parameters.netTestRuntimes }}: + - task: DotNetCoreCLI@2 + displayName: Test [${{runtime}}] + inputs: + command: custom + custom: test + projects: $(project) + arguments: $(buildArguments) --no-build -f ${{runtime}} + + # -------------------------------------------------------------------------- + # Build and test on Windows. + + - job: build_abstractions_package_job_windows + displayName: '[Win] Build Abstractions Package' + pool: + name: Azure Pipelines + # The Windows images include a suitable .NET Framework runtime, so we + # don't have to install one explicitly below. + vmImage: windows-latest + + steps: + + - task: UseDotNet@2 + displayName: Install .NET 9.0 SDK + inputs: + packageType: sdk + version: 9.x + + - task: UseDotNet@2 + displayName: Install .NET 8.0 Runtime + inputs: + packageType: runtime + version: 8.x + + - task: DotNetCoreCLI@2 + displayName: Restore Solution + inputs: + command: custom + custom: restore + projects: $(project) + arguments: $(commonArguments) + + - task: DotNetCoreCLI@2 + displayName: Build Solution + inputs: + command: custom + custom: build + projects: $(project) + arguments: $(buildArguments) --no-restore + + - ${{ each runtime in parameters.netTestRuntimes }}: + - task: DotNetCoreCLI@2 + displayName: Test [${{runtime}}] + inputs: + command: custom + custom: test + projects: $(project) + arguments: $(buildArguments) --no-build -f ${{runtime}} + + - ${{ each runtime in parameters.netFrameworkTestRuntimes }}: + - task: DotNetCoreCLI@2 + displayName: Test [${{runtime}}] + inputs: + command: custom + custom: test + projects: $(project) + arguments: $(buildArguments) --no-build -f ${{runtime}} + + # -------------------------------------------------------------------------- + # Build and test on macOS + + - job: build_abstractions_package_job_macos + displayName: '[macOS] Build Abstractions Package' + pool: + name: Azure Pipelines + vmImage: macos-latest + + steps: + + - task: UseDotNet@2 + displayName: Install .NET 9.0 SDK + inputs: + packageType: sdk + version: 9.x + + - task: UseDotNet@2 + displayName: Install .NET 8.0 Runtime + inputs: + packageType: runtime + version: 8.x + + - task: DotNetCoreCLI@2 + displayName: Restore Solution + inputs: + command: custom + custom: restore + projects: $(project) + arguments: $(commonArguments) + + - task: DotNetCoreCLI@2 + displayName: Build Solution + inputs: + command: custom + custom: build + projects: $(project) + arguments: $(buildArguments) --no-restore + + - ${{ each runtime in parameters.netTestRuntimes }}: + - task: DotNetCoreCLI@2 + displayName: Test [${{runtime}}] + inputs: + command: custom + custom: test + projects: $(project) + arguments: $(buildArguments) --no-build -f ${{runtime}} + + # -------------------------------------------------------------------------- + # Create and publish the NuGet package. + + - job: publish_abstractions_package_job + displayName: Publish Abstractions Package + dependsOn: + # We depend on all of the build jobs to ensure the tests pass before + # producing the NuGet package. + - build_abstractions_package_job_linux + - build_abstractions_package_job_windows + - build_abstractions_package_job_macos + pool: + name: Azure Pipelines + vmImage: ubuntu-latest + + steps: + + - task: UseDotNet@2 + displayName: Install .NET 9.0 SDK + inputs: + packageType: sdk + version: 9.x + + # There is probably a way to avoid this restore and build, and just re-use + # the dotnet artifacts from a previous build job. Downloading the dotnet + # artifacts didn't work (further investigation TBD), so we just build them + # again. + - task: DotNetCoreCLI@2 + displayName: Restore Solution + inputs: + command: custom + custom: restore + projects: $(project) + arguments: $(commonArguments) + + - task: DotNetCoreCLI@2 + displayName: Build Solution + inputs: + command: custom + custom: build + projects: $(project) + arguments: $(buildArguments) --no-restore + + - task: DotNetCoreCLI@2 + displayName: Create NuGet Package + inputs: + command: custom + custom: pack + projects: $(project) + arguments: $(buildArguments) --no-build -o $(dotnetPackagesDir) + + - task: PublishPipelineArtifact@1 + displayName: Publish Pipeline Artifact + inputs: + targetPath: $(dotnetPackagesDir) + artifactName: ${{parameters.artifactName}} + publishLocation: pipeline diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 73570b80df..14a4c1fa8c 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -20,6 +20,21 @@ > msbuild -p:configuration=Release --> Project + + + $(AllowedOutputExtensionsInPackageBuildOutputFolder) + $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props index 4e4c30ae4a..49db0c4b1a 100644 --- a/src/Directory.Packages.props +++ b/src/Directory.Packages.props @@ -15,6 +15,7 @@ + diff --git a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/Abstractions.slnx b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/Abstractions.slnx new file mode 100644 index 0000000000..9632efff88 --- /dev/null +++ b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/Abstractions.slnx @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/README.md b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/README.md new file mode 100644 index 0000000000..d2a24b898c --- /dev/null +++ b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/README.md @@ -0,0 +1,285 @@ +# MDS Azure Extension Design + +## Overview + +For the MDS 7.0.0 release, we are proposing the following package architecture +changes that will decouple several large dependencies from MDS and move them +into a new `Azure` extension package: + +- Create a new `Abstractions` package that all other MDS packages depend on. + - This will contain types and definitions common to the other MDS packages, + such as base classes, enums, delegates, etc. +- Create a new `Azure` package that will own the following implementations: + - Azure Authentication + - Azure Attestation + - Azure Key Vault interactions +- Move the above implementations out of MDS and into the new `Azure` package. +- Move the existing `AzureKeyVaultProvider` (AKV) implementation into the new + `Azure` extension package. + +This will reduce the main MDS package dependency tree along with a moderate +package size reduction. + +## Motivation + +Issue: [#1108](https://github.com/dotnet/SqlClient/issues/1108) + +Customers and the developer community have voiced concerns with MDS being +tightly coupled to Azure dependencies. Many customers do not use Azure and do +not want to deploy unnecessary DLLs with their applications. + +Moving the Azure dependent implementations into a separate `Azure` extension +package achieves two goals: + +- Remove Azure packages as direct dependencies of MDS and reduce the MDS + dependency tree. +- Clearly expose existing MDS extension points, prove their functionality, and + demonstrate how to use them. + +The following dependencies will be removed from the main MDS package: + +- `Azure.Identity` + - `Azure.Core` (transitive) + - `Microsoft.Identity.Client` (transitive) +- `Microsoft.IdentityModel.JsonWebTokens` + - `Microsoft.IdentityModel.Tokens` (transitive) + - `Microsoft.IdentityModel.Logging` (transitive) +- `Microsoft.IdentityModel.Protocols.OpenIdConnect` + - `Microsoft.IdentityModel.Protocols` (transitive) + +The following dependencies will be removed from the AKV Provider package: + +- `Azure.Core` +- `Azure.Security.KeyVault.Keys` + +## Package Architecture + +```mermaid +classDiagram +class MDS +class MDS.Extensions.Abstractions +class MDS.Extensions.Azure +class AKV Provider + +MDS --> MDS.Extensions.Abstractions +MDS ..> MDS.Extensions.Azure +MDS ..> AKV Provider +MDS.Extensions.Azure --> MDS.Extensions.Abstractions +AKV Provider --> MDS.Extensions.Azure + +MDS: Depend on MDS.Extensions.Abstractions +MDS: Load Azure or AKV assembly +MDS.Extensions.Abstractions: Azure Authentication Types +MDS.Extensions.Abstractions: Azure Attestation Types +MDS.Extensions.Abstractions: Azure Key Vault Types +MDS.Extensions.Azure: Depend on MDS.Extensions.Abstractions +MDS.Extensions.Azure: Authentication Implementation +MDS.Extensions.Azure: Attestation Implementation +MDS.Extensions.Azure: Key Vault Implementation +AKV Provider: Depend on MDS.Extensions.Azure +``` + +In previous MDS versions, the AKV package depended directly on the main MDS +package through a ranged version (for example [6.0.0, 7.0.0) - all 6.x +versions). With the new package architecture this is no longer the case. +Extension packages will not depend on the main MDS package, nor will the main +MDS package depend on any extension packages. All dependencies between MDS and +its extensions will occur through the `Abstractions` package. + +This new looser coupling gives applications the flexibility to depend on only +the main MDS package, or on MDS and a subset of it extension packages if +desired. + +## Consuming + +There are several ways that applications may consume MDS and its extensions: + +- MDS with without Azure features +- MDS with MDS-supplied Azure features +- MDS with externally supplied Azure features + +Applications never need to directly depend on the `Abstractions` base package. +This will be transitively depended on by other MDS packages. + +### Without Azure Features + +Applications that do not use any Azure features will no longer bring in those +unwanted dependencies transitively. Simply include the main MDS package by +itself: + +```xml + + + +``` + +Calls to MDS APIs that require Azure features will throw an exception, since +no Azure feature implementation is present. + +### With MDS Azure Features + +Applications that wish to use MDS-supplied Azure features will need to include +the new `Azure` extension package as a direct dependency alongside the main MDS +package: + +```xml + + + + +``` + +MDS will automatically detect the `Azure` extension assemblies and load them. + +### With External Azure Features + +Applications that wish to use Azure features supplied by another (non-MDS) +package will need to include that package as a direct dependency alongside the +main MDS package: + +```xml + + + + +``` + +Additionally, applications will need to instruct MDS to use the external Azure +feature implementations via the appropriate APIs at runtime: + +- Authentication: [SqlAuthenticationProvider](https://learn.microsoft.com/en-us/dotnet/api/microsoft.data.sqlclient.sqlauthenticationprovider?view=sqlclient-dotnet-core-6.0) +- Attestation: _**New API will be exposed.**_ +- Key Valut: [SqlColumnEncryptionKeyStoreProvider](https://learn.microsoft.com/en-us/dotnet/api/microsoft.data.sqlclient.sqlcolumnencryptionkeystoreprovider?view=sqlclient-dotnet-core-6.0) + +## Versioning Strategy + +The MDS suite of packages will be versioned independently. This provides +flexibility to update APIs and implementations for packages as needed, avoiding +unnecessary version bumps and releases. The initial release of these packages +will have the following versions: + +|Package|Version|Comment| +|-|-|-| +|`Microsoft.Data.SqlClient.Extensions.Abstractions`|1.0.0|First version of this package.| +|`Microsoft.Data.SqlClient`|7.0.0|Major version bump due to breaking changes described in this document.| +|`Microsoft.Data.SqlClient.Extensions.Azure`|1.0.0|First version of this package.| +|`Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider`|7.0.0|_**Deprecated.**_| + +Going forward, each package will be versioned appropriately based on the nature +of the changes included with subsequent releases. + +**Note**: The `AzureKeyVaultProvider` package will remain at 7.0.0. It will be +deprecated and eventually removed, as it has been replaced by the `Azure` +extension package. + +## Intradependence + +The main MDS package and the new `Azure` package will depend on the +`Abstractions` package. When APIs are added, modified, or removed from the +`Abstractions` package, corresponding changes will be made to the dependent +packages as well. Those dependent packages will then take a strict dependency +on the appropriate `Abstractions` package version. This ensures that only +compatible extensions package versions can co-exist with the main MDS package. + +For example, imagine that a new extensible conenction pooling feature is added +to MDS. The `Abstractions` package would be updated to include any new pooling +APIs, the main MDS package would be updated to accept extensible pooling, and +the new pooling implementation would be included in a new `ConnectionPooling` +extension package. The versions of these packages would look something like +this: + +|Package|Version| +|-|-| +|`Microsoft.Data.SqlClient.Extensions.Abstractions`|1.1.0| +|`Microsoft.Data.SqlClient`|7.1.0| +|`Microsoft.Data.SqlClient.Extensions.ConnectionPooling`|1.0.0| + +Both the main MDS package and the new `ConnectionPooling` package would depend +on `Abstractions` v1.1.0. + +An application wishing to use the new `ConnectionPooling` v1.0.0 package must +also update the main MDS package to v7.1.0. The applictaion would not be able +to use `ConnectionPooling` v1.0.0 and MDS v7.0.0. + +## Backwards Compatibility + +There are several backwards compatibility scenarios to consider for applications +that rely on MDS Azure features currently implemented in the main MDS package +and the AKV package. The new extensions package architecture aims to reduce the +friction for these apps, but not all scenarios will be seamless. + +All of the scenarios below assume that the application is upgrading to the +latest versions of MDS packages. + +### Apps using MDS Azure Authentication + +Applications currently using the MDS-supplied Azure Authentication features will +need to add a dependency on the `Azure` extension package to their project +alongside the main MDS package: + +```xml + + + + +``` + +All Azure Authentication namespaces and types will remain the same, so this +should be the only change necessary for applications. + +### Apps using MDS Azure Attestation + +Applications currently using the MDS-supplied Azure Attestation features will +need to add a dependency on the `Azure` extension package to their project +alongside the main MDS package: + +```xml + + + + +``` + +All Azure Attestation namespaces and types will remain the same, so this should +be the only change necessary for applications. + +### Apps using AKV Provider + +Applications currently using the MDS-supplied AKV provider will have two options +when upgrading to MDS v7.0.0. Both options rely on the main MDS package finding +and loading an appropriate DLL (assembly) at runtime. The absence of an +appropriate DLL will cause Azure Key Vault operations to throw an exception. + +#### Use Azure Extension + +This is the preferred approach. The application would be updated to depend +on the main MDS package and the `Azure` extension package: + +```xml + + + + +``` + +The `Azure` extension package will contain the same namespaces and types as the +current AKV provider and will be a drop-in replacement. The main MDS v7.0.0 +package will look for the `Azure` extension assembly and automatically load it. + +#### Use AKV Provider v7.0.0 + +This is a temporary solution. The AKV provider v7.0.0 will be marked as +deprecated and removed entirely at some point in the future. The applictaion +would remain dependent on the AKV provider, but must update to the v7.0.0 +package. Previous AKV package versions do not support main MDS package versions +beyond the v6.x range. + +```xml + + + + +``` + +This AKV Provider v7.0.0 package will be empty and simply depend on the `Azure` +extension package to transitively provide the Azure Key Vault features. diff --git a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/doc/Sample.xml b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/doc/Sample.xml new file mode 100644 index 0000000000..8d5f5c44d5 --- /dev/null +++ b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/doc/Sample.xml @@ -0,0 +1,18 @@ + + + + + + Sample class to demonstrate packaging and pipelines. + + + + Construct with a name. + The name. + + + Gets the name. + The name. + + + diff --git a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/Abstractions.csproj b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/Abstractions.csproj new file mode 100644 index 0000000000..1537c33630 --- /dev/null +++ b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/Abstractions.csproj @@ -0,0 +1,95 @@ + + + + + + + + + $(AbstractionsPackageVersion) + + $(PackageVersion).$(BuildNumber) + + + + + netstandard2.0 + + + + + enable + enable + + + + + Microsoft.Data.SqlClient.Extensions.Abstractions + + $(AbstractionsPackageAssemblyVersion) + $(PackageVersion) + $(AssemblyFileVersion) + + Microsoft.Data.SqlClient.Extensions.Abstractions + + + + + <_Parameter1>true + + + + + + + + + + + + + $(PackagesDir) + true + snupkg + + + $(OriginalAllowedOutputExtensions) + + Microsoft Corporation + Microsoft Corporation + Microsoft.Data.SqlClient Extensions Abstractions + https://github.com/dotnet/SqlClient + MIT + dotnet.png + + + + + + diff --git a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/Sample.cs b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/Sample.cs new file mode 100644 index 0000000000..bf22119436 --- /dev/null +++ b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/Sample.cs @@ -0,0 +1,20 @@ +namespace Microsoft.Data.SqlClient.Extensions.Abstractions; + +/// +public class Sample +{ + /// + public Sample(string name) + { + Name = name; + } + + /// + public string Name { get; private set; } + + // Update the name. + internal void SetName(string name) + { + Name = name; + } +} diff --git a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/test/Abstractions.Test.csproj b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/test/Abstractions.Test.csproj new file mode 100644 index 0000000000..118b215737 --- /dev/null +++ b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/test/Abstractions.Test.csproj @@ -0,0 +1,26 @@ + + + + net462;net47;net471;net472;net48;net481;net8.0;net9.0 + enable + enable + false + true + Microsoft.Data.SqlClient.Extensions.Abstractions.Test + + + + + + + + + + + + + + + + + diff --git a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/test/SampleTest.cs b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/test/SampleTest.cs new file mode 100644 index 0000000000..ab8e9da052 --- /dev/null +++ b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/test/SampleTest.cs @@ -0,0 +1,19 @@ +namespace Microsoft.Data.SqlClient.Extensions.Abstractions.Test; + +public class SampleTest +{ + [Fact] + public void Construction() + { + Assert.Equal("test", new Sample("test").Name); + } + + [Fact] + public void SetName() + { + var sample = new Sample("test"); + Assert.Equal("test", sample.Name); + sample.SetName("new name"); + Assert.Equal("new name", sample.Name); + } +} diff --git a/src/Microsoft.Data.SqlClient.sln b/src/Microsoft.Data.SqlClient.sln index e4d29d999c..3947c0e5a6 100644 --- a/src/Microsoft.Data.SqlClient.sln +++ b/src/Microsoft.Data.SqlClient.sln @@ -1,6 +1,7 @@ + Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 -VisualStudioVersion = 17.0.31912.275 +VisualStudioVersion = 17.14.36203.30 d17.14 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Data.SqlClient", "Microsoft.Data.SqlClient\netfx\src\Microsoft.Data.SqlClient.csproj", "{407890AC-9876-4FEF-A6F1-F36A876BAADE}" EndProject @@ -571,6 +572,30 @@ Global {67128EC0-30F5-6A98-448B-55F88A1DE707}.Release|x64.Build.0 = Release|x64 {67128EC0-30F5-6A98-448B-55F88A1DE707}.Release|x86.ActiveCfg = Release|x86 {67128EC0-30F5-6A98-448B-55F88A1DE707}.Release|x86.Build.0 = Release|x86 + {AB71787B-C474-24D1-5EDF-345386CA2460}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AB71787B-C474-24D1-5EDF-345386CA2460}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AB71787B-C474-24D1-5EDF-345386CA2460}.Debug|x64.ActiveCfg = Debug|Any CPU + {AB71787B-C474-24D1-5EDF-345386CA2460}.Debug|x64.Build.0 = Debug|Any CPU + {AB71787B-C474-24D1-5EDF-345386CA2460}.Debug|x86.ActiveCfg = Debug|Any CPU + {AB71787B-C474-24D1-5EDF-345386CA2460}.Debug|x86.Build.0 = Debug|Any CPU + {AB71787B-C474-24D1-5EDF-345386CA2460}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AB71787B-C474-24D1-5EDF-345386CA2460}.Release|Any CPU.Build.0 = Release|Any CPU + {AB71787B-C474-24D1-5EDF-345386CA2460}.Release|x64.ActiveCfg = Release|Any CPU + {AB71787B-C474-24D1-5EDF-345386CA2460}.Release|x64.Build.0 = Release|Any CPU + {AB71787B-C474-24D1-5EDF-345386CA2460}.Release|x86.ActiveCfg = Release|Any CPU + {AB71787B-C474-24D1-5EDF-345386CA2460}.Release|x86.Build.0 = Release|Any CPU + {3028DECE-90B8-2F58-6167-98722A3964D4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3028DECE-90B8-2F58-6167-98722A3964D4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3028DECE-90B8-2F58-6167-98722A3964D4}.Debug|x64.ActiveCfg = Debug|Any CPU + {3028DECE-90B8-2F58-6167-98722A3964D4}.Debug|x64.Build.0 = Debug|Any CPU + {3028DECE-90B8-2F58-6167-98722A3964D4}.Debug|x86.ActiveCfg = Debug|Any CPU + {3028DECE-90B8-2F58-6167-98722A3964D4}.Debug|x86.Build.0 = Debug|Any CPU + {3028DECE-90B8-2F58-6167-98722A3964D4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3028DECE-90B8-2F58-6167-98722A3964D4}.Release|Any CPU.Build.0 = Release|Any CPU + {3028DECE-90B8-2F58-6167-98722A3964D4}.Release|x64.ActiveCfg = Release|Any CPU + {3028DECE-90B8-2F58-6167-98722A3964D4}.Release|x64.Build.0 = Release|Any CPU + {3028DECE-90B8-2F58-6167-98722A3964D4}.Release|x86.ActiveCfg = Release|Any CPU + {3028DECE-90B8-2F58-6167-98722A3964D4}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -621,6 +646,12 @@ Global {AD738BD4-6A02-4B88-8F93-FBBBA49A74C8} = {4CAE9195-4F1A-4D48-854C-1C9FBC512C66} {4461063D-2F2B-274C-7E6F-F235119D258E} = {0CC4817A-12F3-4357-912C-09315FAAD008} {67128EC0-30F5-6A98-448B-55F88A1DE707} = {0CC4817A-12F3-4357-912C-09315FAAD008} + {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} = {4F3CD363-B1E6-4D6D-9466-97D78A56BE45} + {5612FCAA-05D3-4E79-94E5-EEDB2DC70524} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} + {827E0CD3-B72D-47B6-A68D-7590B98EB39B} = {5612FCAA-05D3-4E79-94E5-EEDB2DC70524} + {AB71787B-C474-24D1-5EDF-345386CA2460} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B} + {0C88DD14-F956-CE84-757C-A364CCF449FC} = {5612FCAA-05D3-4E79-94E5-EEDB2DC70524} + {3028DECE-90B8-2F58-6167-98722A3964D4} = {0C88DD14-F956-CE84-757C-A364CCF449FC} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {01D48116-37A2-4D33-B9EC-94793C702431} diff --git a/src/Microsoft.Data.SqlClient/NuGet.config b/src/Microsoft.Data.SqlClient/NuGet.config new file mode 100644 index 0000000000..3bfab46bfa --- /dev/null +++ b/src/Microsoft.Data.SqlClient/NuGet.config @@ -0,0 +1,13 @@ + + + + + + + diff --git a/src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.csproj index 0944a4aea0..2539ff8402 100644 --- a/src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.csproj @@ -35,6 +35,7 @@ + diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj index 383c97cd6c..d5d5897e9c 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj @@ -1047,6 +1047,7 @@ + diff --git a/src/Microsoft.Data.SqlClient/netfx/ref/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netfx/ref/Microsoft.Data.SqlClient.csproj index 445fcca7a7..de5b162026 100644 --- a/src/Microsoft.Data.SqlClient/netfx/ref/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netfx/ref/Microsoft.Data.SqlClient.csproj @@ -35,6 +35,7 @@ + All runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj index 746925de3c..4b42356608 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj @@ -962,6 +962,7 @@ + All runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/tools/props/Versions.props b/tools/props/Versions.props index ad42c4964a..a3b807b1fb 100644 --- a/tools/props/Versions.props +++ b/tools/props/Versions.props @@ -1,29 +1,62 @@ - + + + - 7.0.0 0 + + + + + + + 1 - $(MdsVersionDefault).$(BuildNumber) + $(AbstractionsPackageMajorVersion).0.0 + + $(AbstractionsPackageMajorVersion).0.0.0 + + + + + 7.0.0 + + + $(MdsVersionDefault).$(BuildNumber)-dev + + + $(MdsVersionDefault).$(BuildNumber) + + 7.0.0.0 $(AssemblyFileVersion) - $(MdsVersionDefault)-dev $(NugetPackageVersion) + + @@ -33,6 +66,8 @@ 1.0.0-dev $(SqlServerPackageVersion) + + $(NugetPackageVersion) diff --git a/tools/specs/Microsoft.Data.SqlClient.nuspec b/tools/specs/Microsoft.Data.SqlClient.nuspec index bc177256cb..a1b8ef129e 100644 --- a/tools/specs/Microsoft.Data.SqlClient.nuspec +++ b/tools/specs/Microsoft.Data.SqlClient.nuspec @@ -32,6 +32,7 @@ + @@ -46,6 +47,7 @@ + @@ -59,6 +61,7 @@ + @@ -72,6 +75,7 @@ + From a9aaf951db5ad94d218ce1891e059db469430cc5 Mon Sep 17 00:00:00 2001 From: Paul Medynski <31868385+paulmedynski@users.noreply.github.com> Date: Mon, 15 Sep 2025 10:36:41 -0300 Subject: [PATCH 02/30] User Story 37654: Create Abstractions package - Addressed some of the review comments. --- NuGet.config | 20 +- .../build-abstractions-package-ci-stage.yml | 470 +++++++++--------- packages/.gitignore | 12 + tools/props/Versions.props | 5 +- 4 files changed, 269 insertions(+), 238 deletions(-) create mode 100644 packages/.gitignore diff --git a/NuGet.config b/NuGet.config index 32e4905f6d..53f672d23b 100644 --- a/NuGet.config +++ b/NuGet.config @@ -1,14 +1,30 @@  + + - + + + + + - + diff --git a/eng/pipelines/stages/build-abstractions-package-ci-stage.yml b/eng/pipelines/stages/build-abstractions-package-ci-stage.yml index 4a8b0087df..5517850296 100644 --- a/eng/pipelines/stages/build-abstractions-package-ci-stage.yml +++ b/eng/pipelines/stages/build-abstractions-package-ci-stage.yml @@ -27,6 +27,13 @@ # can be depended on by downstream stages. parameters: + + # The name of the pipeline artifact to publish. + - name: artifactName + displayName: Pipeline Artifact Name + type: string + default: Abstractions.Artifact + # The type of build to produce (Release or Debug) - name: buildConfiguration displayName: Build Configuration @@ -36,23 +43,17 @@ parameters: - Release - Debug - # The version (Major.Minor.Patch) to apply to the package. - - name: packageVersion - displayName: Package Version Override - type: string - default: '' - # The build number of the pipeline. - name: buildNumber displayName: Build Number type: string default: $(Build.BuildNumber) - # The name of the pipeline artifact to publish. - - name: artifactName - displayName: Pipeline Artifact Name - type: string - default: Abstractions.Artifact + # The list of .NET Framework runtimes to test against. + - name: netFrameworkTestRuntimes + displayName: .NET Framework Test Runtimes + type: object + default: [net462, net47, net471, net472, net48, net481] # The list of .NET runtimes to test against. - name: netTestRuntimes @@ -60,11 +61,11 @@ parameters: type: object default: [net8.0, net9.0] - # The list of .NET Framework runtimes to test against. - - name: netFrameworkTestRuntimes - displayName: .NET Framework Test Runtimes - type: object - default: [net462, net47, net471, net472, net48, net481] + # The version (Major.Minor.Patch) to apply to the package. + - name: packageVersion + displayName: Package Version Override + type: string + default: '' # The verbosity level for the dotnet CLI commands. - name: verbosity @@ -79,10 +80,12 @@ parameters: - diagnostic stages: + - stage: build_abstractions_package_stage displayName: Build Abstractions Package variables: + # The directory where dotnet artifacts will be staged. Not to be # confused with pipeline artifact. - name: dotnetArtifactsDir @@ -100,16 +103,16 @@ stages: # dotnet CLI arguments common to all commands. - name: commonArguments value: >- - --verbosity ${{parameters.verbosity}} + --verbosity ${{ parameters.verbosity }} --artifacts-path $(dotnetArtifactsDir) # dotnet CLI arguments for build/test/pack commands - name: buildArguments value: >- $(commonArguments) - --configuration ${{parameters.buildConfiguration}} + --configuration ${{ parameters.buildConfiguration }} -p:BuildNumber=$(Build.BuildNumber) - -p:AbstractionsPackageVersion=${{parameters.packageVersion}} + -p:AbstractionsPackageVersion=${{ parameters.packageVersion }} # Explicitly unset the $PLATFORM environment variable that is set by the # 'ADO Build properties' Library in the ADO SqlClientDrivers public @@ -135,217 +138,218 @@ stages: jobs: - # -------------------------------------------------------------------------- - # Build and test on Linux. - - - job: build_abstractions_package_job_linux - displayName: '[Linux] Build Abstractions Package' - pool: - name: Azure Pipelines - vmImage: ubuntu-latest - - steps: - - - task: UseDotNet@2 - displayName: Install .NET 9.0 SDK - inputs: - packageType: sdk - version: 9.x - - - task: UseDotNet@2 - displayName: Install .NET 8.0 Runtime - inputs: - packageType: runtime - version: 8.x - - # We use the 'custom' command because the DotNetCoreCLI@2 task doesn't - # support all of our argument combinations for the different build steps. - - task: DotNetCoreCLI@2 - displayName: Restore Solution - inputs: - command: custom - custom: restore - projects: $(project) - arguments: $(commonArguments) - - - task: DotNetCoreCLI@2 - displayName: Build Solution - inputs: - command: custom - custom: build - projects: $(project) - arguments: $(buildArguments) --no-restore - - - ${{ each runtime in parameters.netTestRuntimes }}: - - task: DotNetCoreCLI@2 - displayName: Test [${{runtime}}] - inputs: - command: custom - custom: test - projects: $(project) - arguments: $(buildArguments) --no-build -f ${{runtime}} - - # -------------------------------------------------------------------------- - # Build and test on Windows. - - - job: build_abstractions_package_job_windows - displayName: '[Win] Build Abstractions Package' - pool: - name: Azure Pipelines - # The Windows images include a suitable .NET Framework runtime, so we - # don't have to install one explicitly below. - vmImage: windows-latest - - steps: - - - task: UseDotNet@2 - displayName: Install .NET 9.0 SDK - inputs: - packageType: sdk - version: 9.x - - - task: UseDotNet@2 - displayName: Install .NET 8.0 Runtime - inputs: - packageType: runtime - version: 8.x - - - task: DotNetCoreCLI@2 - displayName: Restore Solution - inputs: - command: custom - custom: restore - projects: $(project) - arguments: $(commonArguments) - - - task: DotNetCoreCLI@2 - displayName: Build Solution - inputs: - command: custom - custom: build - projects: $(project) - arguments: $(buildArguments) --no-restore - - - ${{ each runtime in parameters.netTestRuntimes }}: - - task: DotNetCoreCLI@2 - displayName: Test [${{runtime}}] - inputs: - command: custom - custom: test - projects: $(project) - arguments: $(buildArguments) --no-build -f ${{runtime}} - - - ${{ each runtime in parameters.netFrameworkTestRuntimes }}: - - task: DotNetCoreCLI@2 - displayName: Test [${{runtime}}] - inputs: - command: custom - custom: test - projects: $(project) - arguments: $(buildArguments) --no-build -f ${{runtime}} - - # -------------------------------------------------------------------------- - # Build and test on macOS - - - job: build_abstractions_package_job_macos - displayName: '[macOS] Build Abstractions Package' - pool: - name: Azure Pipelines - vmImage: macos-latest - - steps: - - - task: UseDotNet@2 - displayName: Install .NET 9.0 SDK - inputs: - packageType: sdk - version: 9.x - - - task: UseDotNet@2 - displayName: Install .NET 8.0 Runtime - inputs: - packageType: runtime - version: 8.x - - - task: DotNetCoreCLI@2 - displayName: Restore Solution - inputs: - command: custom - custom: restore - projects: $(project) - arguments: $(commonArguments) - - - task: DotNetCoreCLI@2 - displayName: Build Solution - inputs: - command: custom - custom: build - projects: $(project) - arguments: $(buildArguments) --no-restore - - - ${{ each runtime in parameters.netTestRuntimes }}: - - task: DotNetCoreCLI@2 - displayName: Test [${{runtime}}] - inputs: - command: custom - custom: test - projects: $(project) - arguments: $(buildArguments) --no-build -f ${{runtime}} - - # -------------------------------------------------------------------------- - # Create and publish the NuGet package. - - - job: publish_abstractions_package_job - displayName: Publish Abstractions Package - dependsOn: - # We depend on all of the build jobs to ensure the tests pass before - # producing the NuGet package. - - build_abstractions_package_job_linux - - build_abstractions_package_job_windows - - build_abstractions_package_job_macos - pool: - name: Azure Pipelines - vmImage: ubuntu-latest - - steps: - - - task: UseDotNet@2 - displayName: Install .NET 9.0 SDK - inputs: - packageType: sdk - version: 9.x - - # There is probably a way to avoid this restore and build, and just re-use - # the dotnet artifacts from a previous build job. Downloading the dotnet - # artifacts didn't work (further investigation TBD), so we just build them - # again. - - task: DotNetCoreCLI@2 - displayName: Restore Solution - inputs: - command: custom - custom: restore - projects: $(project) - arguments: $(commonArguments) - - - task: DotNetCoreCLI@2 - displayName: Build Solution - inputs: - command: custom - custom: build - projects: $(project) - arguments: $(buildArguments) --no-restore - - - task: DotNetCoreCLI@2 - displayName: Create NuGet Package - inputs: - command: custom - custom: pack - projects: $(project) - arguments: $(buildArguments) --no-build -o $(dotnetPackagesDir) - - - task: PublishPipelineArtifact@1 - displayName: Publish Pipeline Artifact - inputs: - targetPath: $(dotnetPackagesDir) - artifactName: ${{parameters.artifactName}} - publishLocation: pipeline + # ------------------------------------------------------------------------ + # Build and test on Linux. + + - job: build_abstractions_package_job_linux + displayName: '[Linux] Build Abstractions Package' + pool: + name: Azure Pipelines + vmImage: ubuntu-latest + + steps: + + - task: UseDotNet@2 + displayName: Install .NET 9.0 SDK + inputs: + packageType: sdk + version: 9.x + + - task: UseDotNet@2 + displayName: Install .NET 8.0 Runtime + inputs: + packageType: runtime + version: 8.x + + # We use the 'custom' command because the DotNetCoreCLI@2 task doesn't + # support all of our argument combinations for the different build + # steps. + - task: DotNetCoreCLI@2 + displayName: Restore Solution + inputs: + command: custom + custom: restore + projects: $(project) + arguments: $(commonArguments) + + - task: DotNetCoreCLI@2 + displayName: Build Solution + inputs: + command: custom + custom: build + projects: $(project) + arguments: $(buildArguments) --no-restore + + - ${{ each runtime in parameters.netTestRuntimes }}: + - task: DotNetCoreCLI@2 + displayName: Test [${{ runtime }}] + inputs: + command: custom + custom: test + projects: $(project) + arguments: $(buildArguments) --no-build -f ${{ runtime }} + + # ------------------------------------------------------------------------ + # Build and test on Windows. + + - job: build_abstractions_package_job_windows + displayName: '[Win] Build Abstractions Package' + pool: + name: Azure Pipelines + # The Windows images include a suitable .NET Framework runtime, so we + # don't have to install one explicitly below. + vmImage: windows-latest + + steps: + + - task: UseDotNet@2 + displayName: Install .NET 9.0 SDK + inputs: + packageType: sdk + version: 9.x + + - task: UseDotNet@2 + displayName: Install .NET 8.0 Runtime + inputs: + packageType: runtime + version: 8.x + + - task: DotNetCoreCLI@2 + displayName: Restore Solution + inputs: + command: custom + custom: restore + projects: $(project) + arguments: $(commonArguments) + + - task: DotNetCoreCLI@2 + displayName: Build Solution + inputs: + command: custom + custom: build + projects: $(project) + arguments: $(buildArguments) --no-restore + + - ${{ each runtime in parameters.netTestRuntimes }}: + - task: DotNetCoreCLI@2 + displayName: Test [${{ runtime }}] + inputs: + command: custom + custom: test + projects: $(project) + arguments: $(buildArguments) --no-build -f ${{ runtime }} + + - ${{ each runtime in parameters.netFrameworkTestRuntimes }}: + - task: DotNetCoreCLI@2 + displayName: Test [${{ runtime }}] + inputs: + command: custom + custom: test + projects: $(project) + arguments: $(buildArguments) --no-build -f ${{ runtime }} + + # ------------------------------------------------------------------------ + # Build and test on macOS + + - job: build_abstractions_package_job_macos + displayName: '[macOS] Build Abstractions Package' + pool: + name: Azure Pipelines + vmImage: macos-latest + + steps: + + - task: UseDotNet@2 + displayName: Install .NET 9.0 SDK + inputs: + packageType: sdk + version: 9.x + + - task: UseDotNet@2 + displayName: Install .NET 8.0 Runtime + inputs: + packageType: runtime + version: 8.x + + - task: DotNetCoreCLI@2 + displayName: Restore Solution + inputs: + command: custom + custom: restore + projects: $(project) + arguments: $(commonArguments) + + - task: DotNetCoreCLI@2 + displayName: Build Solution + inputs: + command: custom + custom: build + projects: $(project) + arguments: $(buildArguments) --no-restore + + - ${{ each runtime in parameters.netTestRuntimes }}: + - task: DotNetCoreCLI@2 + displayName: Test [${{ runtime }}] + inputs: + command: custom + custom: test + projects: $(project) + arguments: $(buildArguments) --no-build -f ${{ runtime }} + + # ------------------------------------------------------------------------ + # Create and publish the NuGet package. + + - job: publish_abstractions_package_job + displayName: Publish Abstractions Package + dependsOn: + # We depend on all of the build jobs to ensure the tests pass before + # producing the NuGet package. + - build_abstractions_package_job_linux + - build_abstractions_package_job_windows + - build_abstractions_package_job_macos + pool: + name: Azure Pipelines + vmImage: ubuntu-latest + + steps: + + - task: UseDotNet@2 + displayName: Install .NET 9.0 SDK + inputs: + packageType: sdk + version: 9.x + + # There is probably a way to avoid this restore and build, and just + # re-use the dotnet artifacts from a previous build job. Downloading + # the dotnet artifacts didn't work (further investigation TBD), so we + # just build them again. + - task: DotNetCoreCLI@2 + displayName: Restore Solution + inputs: + command: custom + custom: restore + projects: $(project) + arguments: $(commonArguments) + + - task: DotNetCoreCLI@2 + displayName: Build Solution + inputs: + command: custom + custom: build + projects: $(project) + arguments: $(buildArguments) --no-restore + + - task: DotNetCoreCLI@2 + displayName: Create NuGet Package + inputs: + command: custom + custom: pack + projects: $(project) + arguments: $(buildArguments) --no-build -o $(dotnetPackagesDir) + + - task: PublishPipelineArtifact@1 + displayName: Publish Pipeline Artifact + inputs: + targetPath: $(dotnetPackagesDir) + artifactName: ${{ parameters.artifactName }} + publishLocation: pipeline diff --git a/packages/.gitignore b/packages/.gitignore new file mode 100644 index 0000000000..b275e0d002 --- /dev/null +++ b/packages/.gitignore @@ -0,0 +1,12 @@ +# The packages/ directory must exist for local development due to the various +# NuGet.config files that refer to it. However, we never want any files in +# this directory to be included in source control. +# +# Git doesn't track directories, only files, so we need this .gitignore file +# to force Git into tracking the packages/ directory itself. + +# Ignore everything in this directory +* + +# Except this file +!.gitignore diff --git a/tools/props/Versions.props b/tools/props/Versions.props index a3b807b1fb..7981910485 100644 --- a/tools/props/Versions.props +++ b/tools/props/Versions.props @@ -13,9 +13,8 @@ 1 + From 1b1ddec734777940dfa29fdc92473d7cebd771dc Mon Sep 17 00:00:00 2001 From: Yusuf Mohammed <67040622+SAY14489@users.noreply.github.com> Date: Tue, 16 Sep 2025 07:52:27 -0700 Subject: [PATCH 04/30] Optimization: Use Environment.TickCount for SqlStatistics execution timing (#3609) --- .../src/Microsoft/Data/Common/AdapterUtil.cs | 7 +++ .../Microsoft/Data/SqlClient/SqlStatistics.cs | 21 +++---- .../SQL/SqlBulkCopyTest/CopyAllFromReader.cs | 2 - .../Data/SqlClient/TickCountElapsedTest.cs | 56 +++++++++++++++++++ 4 files changed, 74 insertions(+), 12 deletions(-) create mode 100644 src/Microsoft.Data.SqlClient/tests/UnitTests/Microsoft/Data/SqlClient/TickCountElapsedTest.cs diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/AdapterUtil.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/AdapterUtil.cs index 41f2c571ff..60ea8cbc7b 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/AdapterUtil.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/AdapterUtil.cs @@ -629,6 +629,13 @@ internal static Delegate FindBuilder(MulticastDelegate mcd) internal static long TimerCurrent() => DateTime.UtcNow.ToFileTimeUtc(); + internal static long FastTimerCurrent() => Environment.TickCount; + + internal static uint CalculateTickCountElapsed(long startTick, long endTick) + { + return (uint)(endTick - startTick); + } + internal static long TimerFromSeconds(int seconds) { long result = checked((long)seconds * TimeSpan.TicksPerSecond); diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlStatistics.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlStatistics.cs index 4152245971..e03630bafb 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlStatistics.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlStatistics.cs @@ -38,7 +38,7 @@ internal static ValueSqlStatisticsScope TimedScope(SqlStatistics statistics) // internal values that are not exposed through properties internal long _closeTimestamp; internal long _openTimestamp; - internal long _startExecutionTimestamp; + internal long? _startExecutionTimestamp; internal long _startFetchTimestamp; internal long _startNetworkServerTimestamp; @@ -80,7 +80,7 @@ internal bool WaitForDoneAfterRow internal void ContinueOnNewConnection() { - _startExecutionTimestamp = 0; + _startExecutionTimestamp = null; _startFetchTimestamp = 0; _waitForDoneAfterRow = false; _waitForReply = false; @@ -108,7 +108,7 @@ internal IDictionary GetDictionary() { "UnpreparedExecs", _unpreparedExecs }, { "ConnectionTime", ADP.TimerToMilliseconds(_connectionTime) }, - { "ExecutionTime", ADP.TimerToMilliseconds(_executionTime) }, + { "ExecutionTime", _executionTime }, { "NetworkServerTime", ADP.TimerToMilliseconds(_networkServerTime) } }; Debug.Assert(dictionary.Count == Count); @@ -117,9 +117,9 @@ internal IDictionary GetDictionary() internal bool RequestExecutionTimer() { - if (_startExecutionTimestamp == 0) + if (!_startExecutionTimestamp.HasValue) { - _startExecutionTimestamp = ADP.TimerCurrent(); + _startExecutionTimestamp = ADP.FastTimerCurrent(); return true; } return false; @@ -127,7 +127,7 @@ internal bool RequestExecutionTimer() internal void RequestNetworkServerTimer() { - Debug.Assert(_startExecutionTimestamp != 0, "No network time expected outside execution period"); + Debug.Assert(_startExecutionTimestamp.HasValue, "No network time expected outside execution period"); if (_startNetworkServerTimestamp == 0) { _startNetworkServerTimestamp = ADP.TimerCurrent(); @@ -137,10 +137,11 @@ internal void RequestNetworkServerTimer() internal void ReleaseAndUpdateExecutionTimer() { - if (_startExecutionTimestamp > 0) + if (_startExecutionTimestamp.HasValue) { - _executionTime += (ADP.TimerCurrent() - _startExecutionTimestamp); - _startExecutionTimestamp = 0; + uint elapsed = ADP.CalculateTickCountElapsed(_startExecutionTimestamp.Value, ADP.FastTimerCurrent()); + _executionTime += elapsed; + _startExecutionTimestamp = null; } } @@ -176,7 +177,7 @@ internal void Reset() _unpreparedExecs = 0; _waitForDoneAfterRow = false; _waitForReply = false; - _startExecutionTimestamp = 0; + _startExecutionTimestamp = null; _startNetworkServerTimestamp = 0; } diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlBulkCopyTest/CopyAllFromReader.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlBulkCopyTest/CopyAllFromReader.cs index 4d1dd14cfb..beb8df7992 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlBulkCopyTest/CopyAllFromReader.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlBulkCopyTest/CopyAllFromReader.cs @@ -52,8 +52,6 @@ public static void Test(string srcConstr, string dstConstr, string dstTable) Assert.True(0 < (long)stats["BytesReceived"], "BytesReceived is non-positive."); Assert.True(0 < (long)stats["BytesSent"], "BytesSent is non-positive."); - Assert.True((long)stats["ConnectionTime"] >= (long)stats["ExecutionTime"], "Connection Time is less than Execution Time."); - Assert.True((long)stats["ExecutionTime"] >= (long)stats["NetworkServerTime"], "Execution Time is less than Network Server Time."); DataTestUtility.AssertEqualsWithDescription((long)0, (long)stats["UnpreparedExecs"], "Non-zero UnpreparedExecs value: " + (long)stats["UnpreparedExecs"]); DataTestUtility.AssertEqualsWithDescription((long)0, (long)stats["PreparedExecs"], "Non-zero PreparedExecs value: " + (long)stats["PreparedExecs"]); DataTestUtility.AssertEqualsWithDescription((long)0, (long)stats["Prepares"], "Non-zero Prepares value: " + (long)stats["Prepares"]); diff --git a/src/Microsoft.Data.SqlClient/tests/UnitTests/Microsoft/Data/SqlClient/TickCountElapsedTest.cs b/src/Microsoft.Data.SqlClient/tests/UnitTests/Microsoft/Data/SqlClient/TickCountElapsedTest.cs new file mode 100644 index 0000000000..38a555d356 --- /dev/null +++ b/src/Microsoft.Data.SqlClient/tests/UnitTests/Microsoft/Data/SqlClient/TickCountElapsedTest.cs @@ -0,0 +1,56 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.Data.Common; +using Xunit; + +namespace Microsoft.Data.SqlClient.UnitTests; + +/// +/// Tests for Environment.TickCount elapsed time calculation with wraparound handling. +/// +public sealed class TickCountElapsedTest +{ + /// + /// Verifies that normal elapsed time calculation works correctly. + /// + [Fact] + public void CalculateTickCountElapsed_NormalCase_ReturnsCorrectElapsed() + { + uint elapsed = ADP.CalculateTickCountElapsed(1000, 1500); + Assert.Equal(500u, elapsed); + } + + /// + /// Verifies that wraparound from int.MaxValue to int.MinValue is handled correctly. + /// + [Fact] + public void CalculateTickCountElapsed_MaxWraparound_ReturnsOne() + { + uint elapsed = ADP.CalculateTickCountElapsed(int.MaxValue, int.MinValue); + Assert.Equal(1u, elapsed); + } + + /// + /// Verifies that partial wraparound scenarios work correctly. + /// + [Theory] + [InlineData(2147483600, -2147483600, 96u)] + [InlineData(2147483647, -2147483647, 2u)] + public void CalculateTickCountElapsed_PartialWraparound_ReturnsCorrectElapsed(long start, long end, uint expected) + { + uint elapsed = ADP.CalculateTickCountElapsed(start, end); + Assert.Equal(expected, elapsed); + } + + /// + /// Verifies that zero elapsed time returns zero. + /// + [Fact] + public void CalculateTickCountElapsed_ZeroElapsed_ReturnsZero() + { + uint elapsed = ADP.CalculateTickCountElapsed(1000, 1000); + Assert.Equal(0u, elapsed); + } +} From 780db7309dc9ab1188ea7a4393e20be06036a2b0 Mon Sep 17 00:00:00 2001 From: Paul Medynski <31868385+paulmedynski@users.noreply.github.com> Date: Tue, 16 Sep 2025 12:54:12 -0300 Subject: [PATCH 05/30] [7.0.0-preview1] Prepare release notes (#3616) * Task 38530: Prepare release notes - Added 7.0.0 Preview 1 release notes. * Task 38530: Prepare release notes - Addressed review comments. * Task 38530: Prepare release notes - Filled in actual build number. --- CHANGELOG.md | 62 +++++++++++++ release-notes/7.0/7.0.0-preview1.md | 139 ++++++++++++++++++++++++++++ release-notes/7.0/README.md | 7 ++ release-notes/README.md | 1 + 4 files changed, 209 insertions(+) create mode 100644 release-notes/7.0/7.0.0-preview1.md create mode 100644 release-notes/7.0/README.md diff --git a/CHANGELOG.md b/CHANGELOG.md index ddcb3e38bd..04afcc4446 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,68 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) +## [Preview Release 7.0.0-preview1.25257.1] - 2025-09-12 + +This update brings the following changes since the [6.1.0](release-notes/6.1/6.1.0.md) +release: + +### Breaking Changes + +- Removed `Constrained Execution Region` error handling blocks and associated + `SqlConnection` cleanup which may affect how potentially-broken connections + are expunged from the pool. + ([#3535](https://github.com/dotnet/SqlClient/pull/3535)) + +### Bug Fixes + +- Packet multiplexing disabled by default, and several bug fixes. + ([#3534](https://github.com/dotnet/SqlClient/pull/3534), + [#3537](https://github.com/dotnet/SqlClient/pull/3537)) + +### Added + +- `SqlColumnEncryptionCertificateStoreProvider` now works on Windows, Linux, + and macOS. + ([#3014](https://github.com/dotnet/SqlClient/pull/3014)) + +### Changed + +- Updated `SqlVector.Null` to return a nullable `SqlVector` instance in the + reference API to match the implementation. + ([#3521](https://github.com/dotnet/SqlClient/pull/3521)) + +- Performance improvements for all built-in + `SqlColumnEncryptionKeyStoreProvider` implementations. + ([#3554](https://github.com/dotnet/SqlClient/pull/3554)) + +- Various test improvements. + ([#3456](https://github.com/dotnet/SqlClient/pull/3456), + [#2968](https://github.com/dotnet/SqlClient/pull/2968), + [#3458](https://github.com/dotnet/SqlClient/pull/3458), + [#3494](https://github.com/dotnet/SqlClient/pull/3494), + [#3559](https://github.com/dotnet/SqlClient/pull/3559), + [#3575](https://github.com/dotnet/SqlClient/pull/3575)) + +- Codebase merge project and related cleanup. + ([#3436](https://github.com/dotnet/SqlClient/pull/3436), + [#3434](https://github.com/dotnet/SqlClient/pull/3434), + [#3448](https://github.com/dotnet/SqlClient/pull/3448), + [#3454](https://github.com/dotnet/SqlClient/pull/3454), + [#3462](https://github.com/dotnet/SqlClient/pull/3462), + [#3435](https://github.com/dotnet/SqlClient/pull/3435), + [#3492](https://github.com/dotnet/SqlClient/pull/3492), + [#3473](https://github.com/dotnet/SqlClient/pull/3473), + [#3469](https://github.com/dotnet/SqlClient/pull/3469), + [#3394](https://github.com/dotnet/SqlClient/pull/3394), + [#3493](https://github.com/dotnet/SqlClient/pull/3493), + [#3593](https://github.com/dotnet/SqlClient/pull/3593)) + +- Documentation improvements. + ([#3490](https://github.com/dotnet/SqlClient/pull/3490)) + +- Updated `Azure.Identity` dependency to v1.14.2. + ([#3538](https://github.com/dotnet/SqlClient/pull/3538)) + ## [Stable Release 6.1.1] - 2025-08-14 This update includes the following changes since the [6.1.0](6.1.0.md) release: diff --git a/release-notes/7.0/7.0.0-preview1.md b/release-notes/7.0/7.0.0-preview1.md new file mode 100644 index 0000000000..045d3e9857 --- /dev/null +++ b/release-notes/7.0/7.0.0-preview1.md @@ -0,0 +1,139 @@ +# Release Notes + +## Preview Release 7.0.0-preview1.25257.1 - 2025-09-12 + +This update brings the following changes since the [6.1.0](../6.1/6.1.0.md) +release: + +### Breaking Changes + +- Removed `Constrained Execution Region` error handling blocks and associated + `SqlConnection` cleanup which may affect how potentially-broken connections + are expunged from the pool. + ([#3535](https://github.com/dotnet/SqlClient/pull/3535)) + +### Bug Fixes + +- Packet multiplexing disabled by default, and several bug fixes. + ([#3534](https://github.com/dotnet/SqlClient/pull/3534), + [#3537](https://github.com/dotnet/SqlClient/pull/3537)) + +### Added + +- `SqlColumnEncryptionCertificateStoreProvider` now works on Windows, Linux, + and macOS. + ([#3014](https://github.com/dotnet/SqlClient/pull/3014)) + +### Changed + +- Updated `SqlVector.Null` to return a nullable `SqlVector` instance in the + reference API to match the implementation. + ([#3521](https://github.com/dotnet/SqlClient/pull/3521)) + +- Performance improvements for all built-in + `SqlColumnEncryptionKeyStoreProvider` implementations. + ([#3554](https://github.com/dotnet/SqlClient/pull/3554)) + +- Various test improvements. + ([#3456](https://github.com/dotnet/SqlClient/pull/3456), + [#2968](https://github.com/dotnet/SqlClient/pull/2968), + [#3458](https://github.com/dotnet/SqlClient/pull/3458), + [#3494](https://github.com/dotnet/SqlClient/pull/3494), + [#3559](https://github.com/dotnet/SqlClient/pull/3559), + [#3575](https://github.com/dotnet/SqlClient/pull/3575)) + +- Codebase merge project and related cleanup. + ([#3436](https://github.com/dotnet/SqlClient/pull/3436), + [#3434](https://github.com/dotnet/SqlClient/pull/3434), + [#3448](https://github.com/dotnet/SqlClient/pull/3448), + [#3454](https://github.com/dotnet/SqlClient/pull/3454), + [#3462](https://github.com/dotnet/SqlClient/pull/3462), + [#3435](https://github.com/dotnet/SqlClient/pull/3435), + [#3492](https://github.com/dotnet/SqlClient/pull/3492), + [#3473](https://github.com/dotnet/SqlClient/pull/3473), + [#3469](https://github.com/dotnet/SqlClient/pull/3469), + [#3394](https://github.com/dotnet/SqlClient/pull/3394), + [#3493](https://github.com/dotnet/SqlClient/pull/3493), + [#3593](https://github.com/dotnet/SqlClient/pull/3593)) + +- Documentation improvements. + ([#3490](https://github.com/dotnet/SqlClient/pull/3490)) + +- Updated `Azure.Identity` dependency to v1.14.2. + ([#3538](https://github.com/dotnet/SqlClient/pull/3538)) + +## Contributors + +We thank the following public contributors. Their efforts toward this project +are very much appreciated. + +- [edwardneal](https://github.com/edwardneal) +- [emmanuel-ferdman](https://github.com/emmanuel-ferdman) +- [ErikEJ](https://github.com/ErikEJ) +- [twsouthwick](https://github.com/twsouthwick) +- [Wraith2](https://github.com/Wraith2) + +### New Contributors + +- [frankbuckley](https://github.com/frankbuckley) made their first contribution + in [#3521](https://github.com/dotnet/SqlClient/pull/3521) + +## Target Platform Support + +- .NET Framework 4.6.2+ (Windows ARM64, Windows x86, Windows x64) +- .NET 8.0+ (Windows x86, Windows x64, Windows ARM64, Windows ARM, Linux, macOS) + +### Dependencies + +#### .NET Standard 2.0 + +- Azure.Identity 1.14.2 +- Microsoft.Bcl.Cryptography 9.0.5 +- Microsoft.Data.SqlClient.SNI.runtime 6.0.2 +- Microsoft.Extensions.Caching.Memory 9.0.5 +- Microsoft.IdentityModel.JsonWebTokens 7.7.1 +- Microsoft.IdentityModel.Protocols.OpenIdConnect 7.7.1 +- Microsoft.SqlServer.Server 1.0.0 +- System.Configuration.ConfigurationManager 9.0.5 +- System.Security.Cryptography.Pkcs 9.0.5 +- System.Text.Json 9.0.5 + +#### .NET Framework 4.6.2+ + +- Azure.Identity 1.14.2 +- Microsoft.Bcl.Cryptography 8.0.0 +- Microsoft.Data.SqlClient.SNI 6.0.2 +- Microsoft.Extensions.Caching.Memory 8.0.1 +- Microsoft.IdentityModel.JsonWebTokens 7.7.1 +- Microsoft.IdentityModel.Protocols.OpenIdConnect 7.7.1 +- System.Buffers 4.5.1 +- System.Data.Common 4.3.0 +- System.Security.Cryptography.Pkcs 8.0.1 +- System.Text.Encodings.Web 8.0.0 +- System.Text.Json 8.0.5 + +#### .NET 8.0 + +- Azure.Identity 1.14.2 +- Microsoft.Bcl.Cryptography 8.0.0 +- Microsoft.Data.SqlClient.SNI.runtime 6.0.2 +- Microsoft.Extensions.Caching.Memory 8.0.1 +- Microsoft.IdentityModel.JsonWebTokens 7.7.1 +- Microsoft.IdentityModel.Protocols.OpenIdConnect 7.7.1 +- Microsoft.SqlServer.Server 1.0.0 +- System.Configuration.ConfigurationManager 8.0.1 +- System.Security.Cryptography.Pkcs 8.0.1 +- System.Text.Json 8.0.5 + +#### .NET 9.0 + +- Azure.Identity 1.14.2 +- Microsoft.Bcl.Cryptography 9.0.5 +- Microsoft.Data.SqlClient.SNI.runtime 6.0.2 +- Microsoft.Extensions.Caching.Memory 9.0.5 +- Microsoft.IdentityModel.JsonWebTokens 7.7.1 +- Microsoft.IdentityModel.Protocols.OpenIdConnect 7.7.1 +- Microsoft.SqlServer.Server 1.0.0 +- System.Configuration.ConfigurationManager 9.0.5 +- System.Security.Cryptography.Pkcs 9.0.5 +- System.Text.Json 9.0.5 diff --git a/release-notes/7.0/README.md b/release-notes/7.0/README.md new file mode 100644 index 0000000000..6cbd345392 --- /dev/null +++ b/release-notes/7.0/README.md @@ -0,0 +1,7 @@ +# Microsoft.Data.SqlClient 7.0 Releases + +The following Microsoft.Data.SqlClient 7.0 releases have been shipped: + +| Release Date | Version | Notes | +| :-- | :-- | :--: | +| 2025-09-12 | 7.0.0-preview1.25257.1 | [Release Notes](7.0.0-preview1.md) | diff --git a/release-notes/README.md b/release-notes/README.md index 612316204e..f2d7c0b452 100644 --- a/release-notes/README.md +++ b/release-notes/README.md @@ -4,6 +4,7 @@ The latest stable release is [Microsoft.Data.SqlClient 6.0](6.0). ## Release Information +- [Microsoft.Data.SqlClient 7.0](7.0) - [Microsoft.Data.SqlClient 6.1](6.1) - [Microsoft.Data.SqlClient 6.0](6.0) - [Microsoft.Data.SqlClient 5.2](5.2) From 1765de5988e2ad0981d00f82365b6ab64b693c0d Mon Sep 17 00:00:00 2001 From: Edward Neal <55035479+edwardneal@users.noreply.github.com> Date: Tue, 16 Sep 2025 23:39:41 +0100 Subject: [PATCH 06/30] Merge | TdsParser functional changes (#3555) * netcore, netfx: sync declarations of TdsOperationStatus variables * netcore: reorder TryProcessUDTMetadata * netfx: reorder WriteTceFeatureRequest * netfx: reorder WriteAzureSQLSupportFeatureRequest * netcore, netfx: merge WriteInt and SerializeInt netcore: removed a simple WriteInt which did nothing besides call BinaryPrimitives. netcore: when there's space in the packet buffer, WriteInt will now write to it directly (rather than write to a stack-allocated span and copy.) * netcore: remove ConstructGuid method * netcore, netfx: refactor and sync serialization of guids * netcore, netfx: refactor and sync serialization of floats and doubles This removes the need for TdsParser.netcore.cs. * netfx: adjust TraceString - parameter was being passed to it which was never referenced in the format string * netcore: sync exception messages with netfx Messages of the netfx exceptions are more detailed * netfx, netcore: centralise masking of received server options Added mask to netcore logic. Also removed mask on _encryptionOption from netfx - this will never be outside the range of EncryptionOptions.OPTIONS_MASK. * netcore: enforce server certificate validation if AccessTokenCallback is set and certificate is not automatically trusted * netfx: add static lambda to TdsExecuteSQLBatch * netfx: remove failed attempt at static lambda This passed state around, but never passed enough state to remove the state machine. Sync with netcore. * netfx: sync reference to length of JSON metadata substitution sequence * netfx: pre-PR correction: match previous behaviour when writing Guid instances from WriteUnterminatedSqlValue * Flip order of debug assertion * Next round of code review Remove unnecessary conditional compilation. Add XML documentation to clarify SerializeShort, WriteShort et al. * netcore, netfx: sync TraceString Both platforms will now show the TransparentNetworkIPResolution status. This is always disabled on netcore. * Expand ParametersTest to include SqlGuid (including null value) * netfx: port RequestContinue call from netcore --- .../src/Microsoft.Data.SqlClient.csproj | 1 - .../src/Microsoft/Data/SqlClient/TdsParser.cs | 501 +++++++++++------- .../Data/SqlClient/TdsParser.netcore.cs | 25 - .../src/Microsoft/Data/SqlClient/TdsParser.cs | 442 +++++++++------ .../SQL/ParameterTest/ParametersTest.cs | 9 + 5 files changed, 575 insertions(+), 403 deletions(-) delete mode 100644 src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.netcore.cs diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj index 395f3df11d..50b04819ba 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj @@ -822,7 +822,6 @@ - diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs index 8fbeb3050c..4d1eb4e75e 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs @@ -833,13 +833,13 @@ private void SendPreLoginHandshake( break; case (int)PreLoginOptions.TRACEID: - FillGuidBytes(_connHandler._clientConnectionId, payload.AsSpan(payloadLength, GUID_SIZE)); + SerializeGuid(_connHandler._clientConnectionId, payload.AsSpan(payloadLength, GUID_SIZE)); payloadLength += GUID_SIZE; offset += GUID_SIZE; optionDataSize = GUID_SIZE; ActivityCorrelator.ActivityId actId = ActivityCorrelator.Next(); - FillGuidBytes(actId.Id, payload.AsSpan(payloadLength, GUID_SIZE)); + SerializeGuid(actId.Id, payload.AsSpan(payloadLength, GUID_SIZE)); payloadLength += GUID_SIZE; payload[payloadLength++] = (byte)(0x000000ff & actId.Sequence); payload[payloadLength++] = (byte)((0x0000ff00 & actId.Sequence) >> 8); @@ -968,7 +968,7 @@ private PreLoginHandshakeStatus ConsumePreLoginHandshake( if (_physicalStateObj._inBytesPacket > TdsEnums.MAX_PACKET_SIZE || _physicalStateObj._inBytesPacket <= 0) { - throw SQL.ParsingError(); + throw SQL.ParsingError(ParsingErrorState.CorruptedTdsStream); } byte[] payload = new byte[_physicalStateObj._inBytesPacket]; @@ -1017,7 +1017,7 @@ private PreLoginHandshakeStatus ConsumePreLoginHandshake( payloadOffset = payload[offset++] << 8 | payload[offset++]; payloadLength = payload[offset++] << 8 | payload[offset++]; - EncryptionOptions serverOption = (EncryptionOptions)payload[payloadOffset]; + EncryptionOptions serverOption = ((EncryptionOptions)payload[payloadOffset]) & EncryptionOptions.OPTIONS_MASK; /* internal enum EncryptionOptions { OFF, @@ -1160,7 +1160,8 @@ private PreLoginHandshakeStatus ConsumePreLoginHandshake( // Validate Certificate if Trust Server Certificate=false and Encryption forced (EncryptionOptions.ON) from Server. bool shouldValidateServerCert = (_encryptionOption == EncryptionOptions.ON && !trustServerCert) || - (_connHandler._accessTokenInBytes != null && !trustServerCert); + ((_connHandler._accessTokenInBytes != null || _connHandler._accessTokenCallback != null) && !trustServerCert); + uint info = (shouldValidateServerCert ? TdsEnums.SNI_SSL_VALIDATE_CERTIFICATE : 0) | TdsEnums.SNI_SSL_USE_SCHANNEL_CACHE; @@ -1679,9 +1680,12 @@ internal void CheckResetConnection(TdsParserStateObject stateObj) #endif } - // - // Takes a 16 bit short and writes it to the returned buffer. - // + /// + /// Serializes a 16 bit short to the returned buffer. + /// + /// The value to serialize. + /// containing the cached buffer bytes. + /// The serialized 16 bit short. internal byte[] SerializeShort(int v, TdsParserStateObject stateObj) { if (stateObj._bShortBytes == null) @@ -1700,9 +1704,11 @@ internal byte[] SerializeShort(int v, TdsParserStateObject stateObj) return bytes; } - // - // Takes a 16 bit short and writes it. - // + /// + /// Writes a 16 bit short to the wire. + /// + /// The value to write. + /// containing the wire buffer. internal void WriteShort(int v, TdsParserStateObject stateObj) { if ((stateObj._outBytesUsed + 2) > stateObj._outBuff.Length) @@ -1720,27 +1726,97 @@ internal void WriteShort(int v, TdsParserStateObject stateObj) } } + /// + /// Writes a 16 bit unsigned short to the wire. + /// + /// The value to write. + /// containing the wire buffer. internal void WriteUnsignedShort(ushort us, TdsParserStateObject stateObj) { WriteShort((short)us, stateObj); } - // - // Takes a long and writes out an unsigned int - // + /// + /// Serializes a Guid to the specified buffer. + /// + /// The value to serialize. + /// The buffer to serialize to. The size of this buffer must be 16 bytes or larger. + private static void SerializeGuid(in Guid v, Span buffer) + { + Debug.Assert(buffer.Length >= GUID_SIZE); +#if NET + v.TryWriteBytes(buffer, bigEndian: false, out _); +#else + byte[] guidBytes = v.ToByteArray(); + guidBytes.AsSpan().CopyTo(buffer); +#endif + } + + /// + /// Writes a SqlGuid to the wire. + /// + /// The value to write. + /// containing the wire buffer. + private static void WriteGuid(in SqlGuid v, TdsParserStateObject stateObj) + { + Guid innerValue = v.IsNull ? Guid.Empty : v.Value; + + WriteGuid(in innerValue, stateObj); + } + + /// + /// Writes a Guid to the wire. + /// + /// The value to write. + /// containing the wire buffer. + private static void WriteGuid(in Guid v, TdsParserStateObject stateObj) + { + if ((stateObj._outBytesUsed + GUID_SIZE) > stateObj._outBuff.Length) + { + Span buffer = stackalloc byte[GUID_SIZE]; + + SerializeGuid(in v, buffer); + // if all of the guid doesn't fit into the buffer + for (int index = 0; index < buffer.Length; index++) + { + stateObj.WriteByte(buffer[index]); + } + } + else + { + // all of the guid fits into the buffer + SerializeGuid(in v, stateObj._outBuff.AsSpan(stateObj._outBytesUsed, GUID_SIZE)); + stateObj._outBytesUsed += GUID_SIZE; + } + } + + /// + /// Serializes an unsigned 32 bit integer to the returned buffer. + /// + /// The value to serialize. + /// containing the cached buffer bytes. + /// The serialized unsigned 32 bit integer. internal byte[] SerializeUnsignedInt(uint i, TdsParserStateObject stateObj) { return SerializeInt((int)i, stateObj); } + /// + /// Writes an unsigned 32 bit integer to the wire. + /// + /// The value to write. + /// containing the wire buffer. internal void WriteUnsignedInt(uint i, TdsParserStateObject stateObj) { WriteInt((int)i, stateObj); } - // - // Takes an int and writes it as an int. - // + /// + /// Serializes a signed 32 bit integer to the returned buffer. + /// + /// The value to serialize. + /// containing the cached buffer bytes. + /// The serialized signed 32 bit integer. internal byte[] SerializeInt(int v, TdsParserStateObject stateObj) { if (stateObj._bIntBytes == null) @@ -1752,16 +1828,22 @@ internal byte[] SerializeInt(int v, TdsParserStateObject stateObj) Debug.Assert(sizeof(int) == stateObj._bIntBytes.Length); } - WriteInt(stateObj._bIntBytes.AsSpan(), v); + BinaryPrimitives.WriteInt32LittleEndian(stateObj._bIntBytes, v); return stateObj._bIntBytes; } + /// + /// Writes a signed 32 bit integer to the wire. + /// + /// The value to write. + /// containing the wire buffer. internal void WriteInt(int v, TdsParserStateObject stateObj) { - Span buffer = stackalloc byte[sizeof(int)]; - WriteInt(buffer, v); if ((stateObj._outBytesUsed + 4) > stateObj._outBuff.Length) { + Span buffer = stackalloc byte[sizeof(int)]; + + BinaryPrimitives.WriteInt32LittleEndian(buffer, v); // if all of the int doesn't fit into the buffer for (int index = 0; index < sizeof(int); index++) { @@ -1771,19 +1853,16 @@ internal void WriteInt(int v, TdsParserStateObject stateObj) else { // all of the int fits into the buffer - buffer.CopyTo(stateObj._outBuff.AsSpan(stateObj._outBytesUsed, sizeof(int))); + BinaryPrimitives.WriteInt32LittleEndian(stateObj._outBuff.AsSpan(stateObj._outBytesUsed, sizeof(int)), v); stateObj._outBytesUsed += 4; } } - internal static void WriteInt(Span buffer, int value) - { - BinaryPrimitives.TryWriteInt32LittleEndian(buffer, value); - } - - // - // Takes a float and writes it as a 32 bit float. - // + /// + /// Serializes a float to the returned buffer. + /// + /// The value to serialize. + /// The serialized float. internal byte[] SerializeFloat(float v) { if (Single.IsInfinity(v) || Single.IsNaN(v)) @@ -1796,16 +1875,24 @@ internal byte[] SerializeFloat(float v) return bytes; } + /// + /// Writes a float to the wire. + /// + /// The value to write. + /// containing the wire buffer. internal void WriteFloat(float v, TdsParserStateObject stateObj) { Span bytes = stackalloc byte[sizeof(float)]; - FillFloatBytes(v, bytes); + BinaryPrimitives.WriteInt32LittleEndian(bytes, BitConverterCompatible.SingleToInt32Bits(v)); stateObj.WriteByteSpan(bytes); } - // - // Takes a long and writes it as a long. - // + /// + /// Serializes a signed 64 bit long to the returned buffer. + /// + /// The value to serialize. + /// containing the cached buffer bytes. + /// The serialized signed 64 bit long. internal byte[] SerializeLong(long v, TdsParserStateObject stateObj) { int current = 0; @@ -1829,6 +1916,11 @@ internal byte[] SerializeLong(long v, TdsParserStateObject stateObj) return bytes; } + /// + /// Writes a signed 64 bit long to the wire. + /// + /// The value to write. + /// containing the wire buffer. internal void WriteLong(long v, TdsParserStateObject stateObj) { if ((stateObj._outBytesUsed + 8) > stateObj._outBuff.Length) @@ -1855,9 +1947,12 @@ internal void WriteLong(long v, TdsParserStateObject stateObj) } } - // - // Takes a long and writes part of it - // + /// + /// Serializes the first bytes of a signed 64 bit long to the returned buffer. + /// + /// The value to serialize. + /// The number of bytes to serialize. + /// The serialized signed 64 bit long. internal byte[] SerializePartialLong(long v, int length) { Debug.Assert(length <= 8, "Length specified is longer than the size of a long"); @@ -1874,6 +1969,12 @@ internal byte[] SerializePartialLong(long v, int length) return bytes; } + /// + /// Writes the first bytes of a signed 64 bit long to the wire. + /// + /// The value to write. + /// The number of bytes to serialize. + /// containing the wire buffer. internal void WritePartialLong(long v, int length, TdsParserStateObject stateObj) { Debug.Assert(length <= 8, "Length specified is longer than the size of a long"); @@ -1898,17 +1999,21 @@ internal void WritePartialLong(long v, int length, TdsParserStateObject stateObj } } - // - // Takes a ulong and writes it as a ulong. - // + /// + /// Writes an unsigned 64 bit long to the wire. + /// + /// The value to write. + /// containing the wire buffer. internal void WriteUnsignedLong(ulong uv, TdsParserStateObject stateObj) { WriteLong((long)uv, stateObj); } - // - // Takes a double and writes it as a 64 bit double. - // + /// + /// Serializes a double to the returned buffer. + /// + /// The value to serialize. + /// The serialized double. internal byte[] SerializeDouble(double v) { if (double.IsInfinity(v) || double.IsNaN(v)) @@ -1921,10 +2026,15 @@ internal byte[] SerializeDouble(double v) return bytes; } + /// + /// Writes a double to the wire. + /// + /// The value to write. + /// containing the wire buffer. internal void WriteDouble(double v, TdsParserStateObject stateObj) { Span bytes = stackalloc byte[sizeof(double)]; - FillDoubleBytes(v, bytes); + BinaryPrimitives.WriteInt64LittleEndian(bytes, BitConverter.DoubleToInt64Bits(v)); stateObj.WriteByteSpan(bytes); } @@ -2071,7 +2181,7 @@ internal TdsOperationStatus TryRun(RunBehavior runBehavior, SqlCommand cmdHandle #if DEBUG throw new InvalidOperationException(message); #else - throw SQL.ParsingError(); + throw SQL.ParsingErrorToken(ParsingErrorState.InvalidTdsTokenReceived, token); // MDAC 82443 #endif } @@ -2728,14 +2838,13 @@ private TdsOperationStatus TryProcessEnvChange(int tokenLength, TdsParserStateOb int processedLength = 0; SqlEnvChange head = null; SqlEnvChange tail = null; - TdsOperationStatus result; sqlEnvChange = null; while (tokenLength > processedLength) { SqlEnvChange env = new SqlEnvChange(); - result = stateObj.TryReadByte(out env._type); + TdsOperationStatus result = stateObj.TryReadByte(out env._type); if (result != TdsOperationStatus.Done) { return result; @@ -3641,7 +3750,7 @@ private TdsOperationStatus TryProcessSessionState(TdsParserStateObject stateObj, { if (length < 5) { - throw SQL.ParsingError(); + throw SQL.ParsingErrorLength(ParsingErrorState.SessionStateLengthTooShort, length); } uint seqNum; TdsOperationStatus result = stateObj.TryReadUInt32(out seqNum); @@ -3661,7 +3770,7 @@ private TdsOperationStatus TryProcessSessionState(TdsParserStateObject stateObj, } if (status > 1) { - throw SQL.ParsingError(); + throw SQL.ParsingErrorStatus(ParsingErrorState.SessionStateInvalidStatus, status); } bool recoverable = status != 0; length -= 5; @@ -4670,9 +4779,11 @@ internal void DrainData(TdsParserStateObject stateObj) if (sharedState != null && sharedState._dataReady) { _SqlMetaDataSet metadata = stateObj._cleanupMetaData; + TdsOperationStatus result; if (stateObj._partialHeaderBytesRead > 0) { - if (stateObj.TryProcessHeader() != TdsOperationStatus.Done) + result = stateObj.TryProcessHeader(); + if (result != TdsOperationStatus.Done) { throw SQL.SynchronousCallMayNotPend(); } @@ -4680,7 +4791,8 @@ internal void DrainData(TdsParserStateObject stateObj) if (0 == sharedState._nextColumnHeaderToRead) { // i. user called read but didn't fetch anything - if (stateObj.Parser.TrySkipRow(stateObj._cleanupMetaData, stateObj) != TdsOperationStatus.Done) + result = stateObj.Parser.TrySkipRow(stateObj._cleanupMetaData, stateObj); + if (result != TdsOperationStatus.Done) { throw SQL.SynchronousCallMayNotPend(); } @@ -4694,7 +4806,8 @@ internal void DrainData(TdsParserStateObject stateObj) { if (stateObj._longlen != 0) { - if (TrySkipPlpValue(ulong.MaxValue, stateObj, out _) != TdsOperationStatus.Done) + result = TrySkipPlpValue(ulong.MaxValue, stateObj, out _); + if (result != TdsOperationStatus.Done) { throw SQL.SynchronousCallMayNotPend(); } @@ -4703,7 +4816,8 @@ internal void DrainData(TdsParserStateObject stateObj) else if (0 < sharedState._columnDataBytesRemaining) { - if (stateObj.TrySkipLongBytes(sharedState._columnDataBytesRemaining) != TdsOperationStatus.Done) + result = stateObj.TrySkipLongBytes(sharedState._columnDataBytesRemaining); + if (result != TdsOperationStatus.Done) { throw SQL.SynchronousCallMayNotPend(); } @@ -4712,7 +4826,8 @@ internal void DrainData(TdsParserStateObject stateObj) // Read the remaining values off the wire for this row - if (stateObj.Parser.TrySkipRow(metadata, sharedState._nextColumnHeaderToRead, stateObj) != TdsOperationStatus.Done) + result = stateObj.Parser.TrySkipRow(metadata, sharedState._nextColumnHeaderToRead, stateObj); + if (result != TdsOperationStatus.Done) { throw SQL.SynchronousCallMayNotPend(); } @@ -5303,6 +5418,85 @@ private TdsOperationStatus TryCommonProcessMetaData(TdsParserStateObject stateOb return TdsOperationStatus.Done; } + private TdsOperationStatus TryProcessUDTMetaData(SqlMetaDataPriv metaData, TdsParserStateObject stateObj) + { + ushort shortLength; + byte byteLength; + + // max byte size + TdsOperationStatus result = stateObj.TryReadUInt16(out shortLength); + if (result != TdsOperationStatus.Done) + { + return result; + } + metaData.length = shortLength; + + // database name + result = stateObj.TryReadByte(out byteLength); + if (result != TdsOperationStatus.Done) + { + return result; + } + if (metaData.udt is null) + { + metaData.udt = new SqlMetaDataUdt(); + } + if (byteLength != 0) + { + result = stateObj.TryReadString(byteLength, out metaData.udt.DatabaseName); + if (result != TdsOperationStatus.Done) + { + return result; + } + } + + // schema name + result = stateObj.TryReadByte(out byteLength); + if (result != TdsOperationStatus.Done) + { + return result; + } + if (byteLength != 0) + { + result = stateObj.TryReadString(byteLength, out metaData.udt.SchemaName); + if (result != TdsOperationStatus.Done) + { + return result; + } + } + + // type name + result = stateObj.TryReadByte(out byteLength); + if (result != TdsOperationStatus.Done) + { + return result; + } + if (byteLength != 0) + { + result = stateObj.TryReadString(byteLength, out metaData.udt.TypeName); + if (result != TdsOperationStatus.Done) + { + return result; + } + } + + result = stateObj.TryReadUInt16(out shortLength); + if (result != TdsOperationStatus.Done) + { + return result; + } + if (shortLength != 0) + { + result = stateObj.TryReadString(shortLength, out metaData.udt.AssemblyQualifiedName); + if (result != TdsOperationStatus.Done) + { + return result; + } + } + + return TdsOperationStatus.Done; + } + private void WriteUDTMetaData(object value, string database, string schema, string type, TdsParserStateObject stateObj) { @@ -6536,9 +6730,8 @@ internal TdsOperationStatus TryReadSqlValue(SqlBuffer value, private TdsOperationStatus TryReadSqlDateTime(SqlBuffer value, byte tdsType, int length, byte scale, TdsParserStateObject stateObj) { Span datetimeBuffer = ((uint)length <= 16) ? stackalloc byte[16] : new byte[length]; - TdsOperationStatus result; - result = stateObj.TryReadByteArray(datetimeBuffer, length); + TdsOperationStatus result = stateObj.TryReadByteArray(datetimeBuffer, length); if (result != TdsOperationStatus.Done) { return result; @@ -6770,13 +6963,17 @@ internal TdsOperationStatus TryReadSqlValueInternal(SqlBuffer value, byte tdsTyp { Debug.Assert(length == GUID_SIZE, "invalid length for SqlGuid type!"); +#if NET Span b = stackalloc byte[GUID_SIZE]; +#else + byte[] b = (_tempGuidBytes ??= new byte[GUID_SIZE]); +#endif result = stateObj.TryReadByteArray(b, length); if (result != TdsOperationStatus.Done) { return result; } - value.Guid = ConstructGuid(b); + value.Guid = new Guid(b); break; } @@ -7122,12 +7319,8 @@ internal Task WriteSqlVariantValue(object value, int length, int offset, TdsPars case TdsEnums.SQLUNIQUEID: { - System.Guid guid = (System.Guid)value; - Span b = stackalloc byte[16]; - TdsParser.FillGuidBytes(guid, b); - - Debug.Assert((length == b.Length) && (length == 16), "Invalid length for guid type in com+ object"); - stateObj.WriteByteSpan(b); + Debug.Assert(length == 16, "Invalid length for guid type in com+ object"); + WriteGuid((Guid)value, stateObj); break; } @@ -7280,14 +7473,8 @@ internal Task WriteSqlVariantDataRowValue(object value, TdsParserStateObject sta case TdsEnums.SQLUNIQUEID: { - System.Guid guid = (System.Guid)value; - Span b = stackalloc byte[16]; - FillGuidBytes(guid, b); - - length = b.Length; - Debug.Assert(length == 16, "Invalid length for guid type in com+ object"); WriteSqlVariantHeader(18, metatype.TDSType, metatype.PropBytes, stateObj); - stateObj.WriteByteSpan(b); + WriteGuid((Guid)value, stateObj); break; } @@ -8060,47 +8247,45 @@ internal TdsOperationStatus TryGetTokenLength(byte token, TdsParserStateObject s return stateObj.TryReadInt32(out tokenLength); } + if (token == TdsEnums.SQLUDT) + { // special case for UDTs + tokenLength = -1; // Should we return -1 or not call GetTokenLength for UDTs? + return TdsOperationStatus.Done; + } + else if (token == TdsEnums.SQLRETURNVALUE) { - if (token == TdsEnums.SQLUDT) - { // special case for UDTs - tokenLength = -1; // Should we return -1 or not call GetTokenLength for UDTs? - return TdsOperationStatus.Done; - } - else if (token == TdsEnums.SQLRETURNVALUE) - { - tokenLength = -1; // In 2005, the RETURNVALUE token stream no longer has length - return TdsOperationStatus.Done; - } - else if (token == TdsEnums.SQLXMLTYPE) - { - ushort value; - result = stateObj.TryReadUInt16(out value); - if (result != TdsOperationStatus.Done) - { - tokenLength = 0; - return result; - } - tokenLength = (int)value; - Debug.Assert(tokenLength == TdsEnums.SQL_USHORTVARMAXLEN, "Invalid token stream for xml datatype"); - return TdsOperationStatus.Done; - } - else if (token == TdsEnums.SQLJSON) + tokenLength = -1; // In 2005, the RETURNVALUE token stream no longer has length + return TdsOperationStatus.Done; + } + else if (token == TdsEnums.SQLXMLTYPE) + { + ushort value; + result = stateObj.TryReadUInt16(out value); + if (result != TdsOperationStatus.Done) { - tokenLength = -1; - return TdsOperationStatus.Done; + tokenLength = 0; + return result; } - else if (token == TdsEnums.SQLVECTOR) + tokenLength = (int)value; + Debug.Assert(tokenLength == TdsEnums.SQL_USHORTVARMAXLEN, "Invalid token stream for xml datatype"); + return TdsOperationStatus.Done; + } + else if (token == TdsEnums.SQLJSON) + { + tokenLength = -1; + return TdsOperationStatus.Done; + } + else if (token == TdsEnums.SQLVECTOR) + { + ushort value; + result = stateObj.TryReadUInt16(out value); + if (result != TdsOperationStatus.Done) { - ushort value; - result = stateObj.TryReadUInt16(out value); - if (result != TdsOperationStatus.Done) - { - tokenLength = 0; - return result; - } - tokenLength = value; - return TdsOperationStatus.Done; + tokenLength = 0; + return result; } + tokenLength = value; + return TdsOperationStatus.Done; } switch (token & TdsEnums.SQLLenMask) @@ -11664,26 +11849,16 @@ private Task WriteUnterminatedSqlValue(object value, MetaType type, int actualLe case TdsEnums.SQLUNIQUEID: { Debug.Assert(actualLength == 16, "Invalid length for guid type in com+ object"); - Span b = stackalloc byte[16]; if (value is Guid guid) { - FillGuidBytes(guid, b); + WriteGuid(in guid, stateObj); } else { SqlGuid sqlGuid = (SqlGuid)value; - if (sqlGuid.IsNull) - { - b.Clear(); // this is needed because initlocals may be supressed in framework assemblies meaning the memory is not automaticaly zeroed - } - else - { - FillGuidBytes(sqlGuid.Value, b); - } + WriteGuid(in sqlGuid, stateObj); } - stateObj.WriteByteSpan(b); break; - } case TdsEnums.SQLBITN: @@ -12340,9 +12515,7 @@ private Task WriteUnterminatedValue(object value, MetaType type, byte scale, int case TdsEnums.SQLUNIQUEID: { Debug.Assert(actualLength == 16, "Invalid length for guid type in com+ object"); - Span b = stackalloc byte[16]; - FillGuidBytes((System.Guid)value, b); - stateObj.WriteByteSpan(b); + WriteGuid((Guid)value, stateObj); break; } @@ -13541,86 +13714,6 @@ internal ulong PlpBytesTotalLength(TdsParserStateObject stateObj) return stateObj._longlen; } - private TdsOperationStatus TryProcessUDTMetaData(SqlMetaDataPriv metaData, TdsParserStateObject stateObj) - { - - ushort shortLength; - byte byteLength; - // max byte size - - TdsOperationStatus result = stateObj.TryReadUInt16(out shortLength); - if (result != TdsOperationStatus.Done) - { - return result; - } - metaData.length = shortLength; - - // database name - result = stateObj.TryReadByte(out byteLength); - if (result != TdsOperationStatus.Done) - { - return result; - } - if (metaData.udt is null) - { - metaData.udt = new SqlMetaDataUdt(); - } - if (byteLength != 0) - { - result = stateObj.TryReadString(byteLength, out metaData.udt.DatabaseName); - if (result != TdsOperationStatus.Done) - { - return result; - } - } - - // schema name - result = stateObj.TryReadByte(out byteLength); - if (result != TdsOperationStatus.Done) - { - return result; - } - if (byteLength != 0) - { - result = stateObj.TryReadString(byteLength, out metaData.udt.SchemaName); - if (result != TdsOperationStatus.Done) - { - return result; - } - } - - // type name - result = stateObj.TryReadByte(out byteLength); - if (result != TdsOperationStatus.Done) - { - return result; - } - if (byteLength != 0) - { - result = stateObj.TryReadString(byteLength, out metaData.udt.TypeName); - if (result != TdsOperationStatus.Done) - { - return result; - } - } - - result = stateObj.TryReadUInt16(out shortLength); - if (result != TdsOperationStatus.Done) - { - return result; - } - if (shortLength != 0) - { - result = stateObj.TryReadString(shortLength, out metaData.udt.AssemblyQualifiedName); - if (result != TdsOperationStatus.Done) - { - return result; - } - } - - return TdsOperationStatus.Done; - } - const string StateTraceFormatString = "\n\t" + " _physicalStateObj = {0}\n\t" + " _pMarsPhysicalConObj = {1}\n\t" @@ -13645,8 +13738,9 @@ private TdsOperationStatus TryProcessUDTMetaData(SqlMetaDataPriv metaData, TdsPa + " _attentionWarnings = {20}\n\t" + " _statistics = {21}\n\t" + " _statisticsIsInTransaction = {22}\n\t" - + " _fPreserveTransaction = {23}" - + " _fParallel = {24}" + + " _fPreserveTransaction = {23}\n\t" + + " _multiSubnetFailover = {24}\n\t" + + " _transparentNetworkIPResolution = {25}" ; internal string TraceString() { @@ -13676,7 +13770,8 @@ internal string TraceString() _statistics == null ? bool.TrueString : bool.FalseString, _statisticsIsInTransaction ? bool.TrueString : bool.FalseString, _fPreserveTransaction ? bool.TrueString : bool.FalseString, - _connHandler == null ? "(null)" : _connHandler.ConnectionOptions.MultiSubnetFailover.ToString((IFormatProvider)null)); + _connHandler == null ? "(null)" : _connHandler.ConnectionOptions.MultiSubnetFailover.ToString((IFormatProvider)null), + _connHandler == null ? "(null)" : bool.FalseString); } private string TraceObjectClass(object instance) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.netcore.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.netcore.cs deleted file mode 100644 index 95dd0d9731..0000000000 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.netcore.cs +++ /dev/null @@ -1,25 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Diagnostics; -using System.Buffers.Binary; - -namespace Microsoft.Data.SqlClient -{ - internal sealed partial class TdsParser - { - internal static void FillGuidBytes(Guid guid, Span buffer) => guid.TryWriteBytes(buffer); - - internal static void FillDoubleBytes(double value, Span buffer) => BinaryPrimitives.TryWriteInt64LittleEndian(buffer, BitConverter.DoubleToInt64Bits(value)); - - internal static void FillFloatBytes(float value, Span buffer) => BinaryPrimitives.TryWriteInt32LittleEndian(buffer, BitConverterCompatible.SingleToInt32Bits(value)); - - internal static Guid ConstructGuid(ReadOnlySpan bytes) - { - Debug.Assert(bytes.Length >= 16, "not enough bytes to set guid"); - return new Guid(bytes); - } - } -} diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs index d38190a359..670ed07dac 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs @@ -885,16 +885,13 @@ private void SendPreLoginHandshake( break; case (int)PreLoginOptions.TRACEID: - byte[] connectionIdBytes = _connHandler._clientConnectionId.ToByteArray(); - Debug.Assert(GUID_SIZE == connectionIdBytes.Length); - Buffer.BlockCopy(connectionIdBytes, 0, payload, payloadLength, GUID_SIZE); + SerializeGuid(_connHandler._clientConnectionId, payload.AsSpan(payloadLength, GUID_SIZE)); payloadLength += GUID_SIZE; offset += GUID_SIZE; optionDataSize = GUID_SIZE; ActivityCorrelator.ActivityId actId = ActivityCorrelator.Next(); - connectionIdBytes = actId.Id.ToByteArray(); - Buffer.BlockCopy(connectionIdBytes, 0, payload, payloadLength, GUID_SIZE); + SerializeGuid(actId.Id, payload.AsSpan(payloadLength, GUID_SIZE)); payloadLength += GUID_SIZE; payload[payloadLength++] = (byte)(0x000000ff & actId.Sequence); payload[payloadLength++] = (byte)((0x0000ff00 & actId.Sequence) >> 8); @@ -1085,7 +1082,7 @@ private PreLoginHandshakeStatus ConsumePreLoginHandshake( payloadOffset = payload[offset++] << 8 | payload[offset++]; payloadLength = payload[offset++] << 8 | payload[offset++]; - EncryptionOptions serverOption = (EncryptionOptions)payload[payloadOffset]; + EncryptionOptions serverOption = ((EncryptionOptions)payload[payloadOffset]) & EncryptionOptions.OPTIONS_MASK; /* internal enum EncryptionOptions { OFF, @@ -1097,26 +1094,26 @@ private PreLoginHandshakeStatus ConsumePreLoginHandshake( } */ // Any response other than NOT_SUP means the server supports encryption. - serverSupportsEncryption = (serverOption & EncryptionOptions.OPTIONS_MASK) != EncryptionOptions.NOT_SUP; + serverSupportsEncryption = serverOption != EncryptionOptions.NOT_SUP; - switch (_encryptionOption & EncryptionOptions.OPTIONS_MASK) + switch (_encryptionOption) { case (EncryptionOptions.OFF): - if ((serverOption & EncryptionOptions.OPTIONS_MASK) == EncryptionOptions.OFF) + if (serverOption == EncryptionOptions.OFF) { // Only encrypt login. - _encryptionOption = EncryptionOptions.LOGIN | (_encryptionOption & ~EncryptionOptions.OPTIONS_MASK); + _encryptionOption = EncryptionOptions.LOGIN; } - else if ((serverOption & EncryptionOptions.OPTIONS_MASK) == EncryptionOptions.REQ) + else if (serverOption == EncryptionOptions.REQ) { // Encrypt all. - _encryptionOption = EncryptionOptions.ON | (_encryptionOption & ~EncryptionOptions.OPTIONS_MASK); + _encryptionOption = EncryptionOptions.ON; } // NOT_SUP: No encryption. break; case (EncryptionOptions.NOT_SUP): - if ((serverOption & EncryptionOptions.OPTIONS_MASK) == EncryptionOptions.REQ) + if (serverOption == EncryptionOptions.REQ) { // Server requires encryption, but client does not support it. _physicalStateObj.AddError(new SqlError(TdsEnums.ENCRYPTION_NOT_SUPPORTED, (byte)0x00, TdsEnums.FATAL_ERROR_CLASS, _server, SQLMessage.EncryptionNotSupportedByClient(), "", 0)); @@ -1127,7 +1124,7 @@ private PreLoginHandshakeStatus ConsumePreLoginHandshake( break; default: // Any other client option needs encryption - if ((serverOption & EncryptionOptions.OPTIONS_MASK) == EncryptionOptions.NOT_SUP) + if (serverOption == EncryptionOptions.NOT_SUP) { _physicalStateObj.AddError(new SqlError(TdsEnums.ENCRYPTION_NOT_SUPPORTED, (byte)0x00, TdsEnums.FATAL_ERROR_CLASS, _server, SQLMessage.EncryptionNotSupportedByServer(), "", 0)); _physicalStateObj.Dispose(); @@ -1216,8 +1213,8 @@ private PreLoginHandshakeStatus ConsumePreLoginHandshake( } } - if ((_encryptionOption & EncryptionOptions.OPTIONS_MASK) == EncryptionOptions.ON || - (_encryptionOption & EncryptionOptions.OPTIONS_MASK) == EncryptionOptions.LOGIN) + if (_encryptionOption == EncryptionOptions.ON || + _encryptionOption == EncryptionOptions.LOGIN) { if (!serverSupportsEncryption) { @@ -1227,7 +1224,8 @@ private PreLoginHandshakeStatus ConsumePreLoginHandshake( } // Validate Certificate if Trust Server Certificate=false and Encryption forced (EncryptionOptions.ON) from Server. - bool shouldValidateServerCert = (_encryptionOption == EncryptionOptions.ON && !trustServerCert) || ((_connHandler._accessTokenInBytes != null || _connHandler._accessTokenCallback != null) && !trustServerCert); + bool shouldValidateServerCert = (_encryptionOption == EncryptionOptions.ON && !trustServerCert) || + ((_connHandler._accessTokenInBytes != null || _connHandler._accessTokenCallback != null) && !trustServerCert); uint info = (shouldValidateServerCert ? TdsEnums.SNI_SSL_VALIDATE_CERTIFICATE : 0) | TdsEnums.SNI_SSL_USE_SCHANNEL_CACHE; @@ -1708,9 +1706,12 @@ internal void CheckResetConnection(TdsParserStateObject stateObj) #endif } - // - // Takes a 16 bit short and writes it to the returned buffer. - // + /// + /// Serializes a 16 bit short to the returned buffer. + /// + /// The value to serialize. + /// containing the cached buffer bytes. + /// The serialized 16 bit short. internal byte[] SerializeShort(int v, TdsParserStateObject stateObj) { if (stateObj._bShortBytes == null) @@ -1729,9 +1730,11 @@ internal byte[] SerializeShort(int v, TdsParserStateObject stateObj) return bytes; } - // - // Takes a 16 bit short and writes it. - // + /// + /// Writes a 16 bit short to the wire. + /// + /// The value to write. + /// containing the wire buffer. internal void WriteShort(int v, TdsParserStateObject stateObj) { if ((stateObj._outBytesUsed + 2) > stateObj._outBuff.Length) @@ -1749,27 +1752,97 @@ internal void WriteShort(int v, TdsParserStateObject stateObj) } } + /// + /// Writes a 16 bit unsigned short to the wire. + /// + /// The value to write. + /// containing the wire buffer. internal void WriteUnsignedShort(ushort us, TdsParserStateObject stateObj) { WriteShort((short)us, stateObj); } - // - // Takes a long and writes out an unsigned int - // + /// + /// Serializes a Guid to the specified buffer. + /// + /// The value to serialize. + /// The buffer to serialize to. The size of this buffer must be 16 bytes or larger. + private static void SerializeGuid(in Guid v, Span buffer) + { + Debug.Assert(buffer.Length >= GUID_SIZE); +#if NET + v.TryWriteBytes(buffer, bigEndian: false, out _); +#else + byte[] guidBytes = v.ToByteArray(); + guidBytes.AsSpan().CopyTo(buffer); +#endif + } + + /// + /// Writes a SqlGuid to the wire. + /// + /// The value to write. + /// containing the wire buffer. + private static void WriteGuid(in SqlGuid v, TdsParserStateObject stateObj) + { + Guid innerValue = v.IsNull ? Guid.Empty : v.Value; + + WriteGuid(in innerValue, stateObj); + } + + /// + /// Writes a Guid to the wire. + /// + /// The value to write. + /// containing the wire buffer. + private static void WriteGuid(in Guid v, TdsParserStateObject stateObj) + { + if ((stateObj._outBytesUsed + GUID_SIZE) > stateObj._outBuff.Length) + { + Span buffer = stackalloc byte[GUID_SIZE]; + + SerializeGuid(in v, buffer); + // if all of the guid doesn't fit into the buffer + for (int index = 0; index < buffer.Length; index++) + { + stateObj.WriteByte(buffer[index]); + } + } + else + { + // all of the guid fits into the buffer + SerializeGuid(in v, stateObj._outBuff.AsSpan(stateObj._outBytesUsed, GUID_SIZE)); + stateObj._outBytesUsed += GUID_SIZE; + } + } + + /// + /// Serializes an unsigned 32 bit integer to the returned buffer. + /// + /// The value to serialize. + /// containing the cached buffer bytes. + /// The serialized unsigned 32 bit integer. internal byte[] SerializeUnsignedInt(uint i, TdsParserStateObject stateObj) { return SerializeInt((int)i, stateObj); } + /// + /// Writes an unsigned 32 bit integer to the wire. + /// + /// The value to write. + /// containing the wire buffer. internal void WriteUnsignedInt(uint i, TdsParserStateObject stateObj) { WriteInt((int)i, stateObj); } - // - // Takes an int and writes it as an int. - // + /// + /// Serializes a signed 32 bit integer to the returned buffer. + /// + /// The value to serialize. + /// containing the cached buffer bytes. + /// The serialized signed 32 bit integer. internal byte[] SerializeInt(int v, TdsParserStateObject stateObj) { if (stateObj._bIntBytes == null) @@ -1781,40 +1854,41 @@ internal byte[] SerializeInt(int v, TdsParserStateObject stateObj) Debug.Assert(sizeof(int) == stateObj._bIntBytes.Length); } - int current = 0; - byte[] bytes = stateObj._bIntBytes; - bytes[current++] = (byte)(v & 0xff); - bytes[current++] = (byte)((v >> 8) & 0xff); - bytes[current++] = (byte)((v >> 16) & 0xff); - bytes[current++] = (byte)((v >> 24) & 0xff); - return bytes; + BinaryPrimitives.WriteInt32LittleEndian(stateObj._bIntBytes, v); + return stateObj._bIntBytes; } + /// + /// Writes a signed 32 bit integer to the wire. + /// + /// The value to write. + /// containing the wire buffer. internal void WriteInt(int v, TdsParserStateObject stateObj) { if ((stateObj._outBytesUsed + 4) > stateObj._outBuff.Length) { + Span buffer = stackalloc byte[sizeof(int)]; + + BinaryPrimitives.WriteInt32LittleEndian(buffer, v); // if all of the int doesn't fit into the buffer - for (int shiftValue = 0; shiftValue < sizeof(int) * 8; shiftValue += 8) + for (int index = 0; index < sizeof(int); index++) { - stateObj.WriteByte((byte)((v >> shiftValue) & 0xff)); + stateObj.WriteByte(buffer[index]); } } else { // all of the int fits into the buffer - // NOTE: We don't use a loop here for performance - stateObj._outBuff[stateObj._outBytesUsed] = (byte)(v & 0xff); - stateObj._outBuff[stateObj._outBytesUsed + 1] = (byte)((v >> 8) & 0xff); - stateObj._outBuff[stateObj._outBytesUsed + 2] = (byte)((v >> 16) & 0xff); - stateObj._outBuff[stateObj._outBytesUsed + 3] = (byte)((v >> 24) & 0xff); + BinaryPrimitives.WriteInt32LittleEndian(stateObj._outBuff.AsSpan(stateObj._outBytesUsed, sizeof(int)), v); stateObj._outBytesUsed += 4; } } - // - // Takes a float and writes it as a 32 bit float. - // + /// + /// Serializes a float to the returned buffer. + /// + /// The value to serialize. + /// The serialized float. internal byte[] SerializeFloat(float v) { if (Single.IsInfinity(v) || Single.IsNaN(v)) @@ -1825,16 +1899,24 @@ internal byte[] SerializeFloat(float v) return BitConverter.GetBytes(v); } + /// + /// Writes a float to the wire. + /// + /// The value to write. + /// containing the wire buffer. internal void WriteFloat(float v, TdsParserStateObject stateObj) { - byte[] bytes = BitConverter.GetBytes(v); - - stateObj.WriteByteArray(bytes, bytes.Length, 0); + Span bytes = stackalloc byte[sizeof(float)]; + BinaryPrimitives.WriteInt32LittleEndian(bytes, BitConverterCompatible.SingleToInt32Bits(v)); + stateObj.WriteByteSpan(bytes); } - // - // Takes a long and writes it as a long. - // + /// + /// Serializes a signed 64 bit long to the returned buffer. + /// + /// The value to serialize. + /// containing the cached buffer bytes. + /// The serialized signed 64 bit long. internal byte[] SerializeLong(long v, TdsParserStateObject stateObj) { int current = 0; @@ -1858,6 +1940,11 @@ internal byte[] SerializeLong(long v, TdsParserStateObject stateObj) return bytes; } + /// + /// Writes a signed 64 bit long to the wire. + /// + /// The value to write. + /// containing the wire buffer. internal void WriteLong(long v, TdsParserStateObject stateObj) { if ((stateObj._outBytesUsed + 8) > stateObj._outBuff.Length) @@ -1884,9 +1971,12 @@ internal void WriteLong(long v, TdsParserStateObject stateObj) } } - // - // Takes a long and writes part of it - // + /// + /// Serializes the first bytes of a signed 64 bit long to the returned buffer. + /// + /// The value to serialize. + /// The number of bytes to serialize. + /// The serialized signed 64 bit long. internal byte[] SerializePartialLong(long v, int length) { Debug.Assert(length <= 8, "Length specified is longer than the size of a long"); @@ -1903,6 +1993,12 @@ internal byte[] SerializePartialLong(long v, int length) return bytes; } + /// + /// Writes the first bytes of a signed 64 bit long to the wire. + /// + /// The value to write. + /// The number of bytes to serialize. + /// containing the wire buffer. internal void WritePartialLong(long v, int length, TdsParserStateObject stateObj) { Debug.Assert(length <= 8, "Length specified is longer than the size of a long"); @@ -1927,17 +2023,21 @@ internal void WritePartialLong(long v, int length, TdsParserStateObject stateObj } } - // - // Takes a ulong and writes it as a ulong. - // + /// + /// Writes an unsigned 64 bit long to the wire. + /// + /// The value to write. + /// containing the wire buffer. internal void WriteUnsignedLong(ulong uv, TdsParserStateObject stateObj) { WriteLong((long)uv, stateObj); } - // - // Takes a double and writes it as a 64 bit double. - // + /// + /// Serializes a double to the returned buffer. + /// + /// The value to serialize. + /// The serialized double. internal byte[] SerializeDouble(double v) { if (double.IsInfinity(v) || double.IsNaN(v)) @@ -1948,11 +2048,16 @@ internal byte[] SerializeDouble(double v) return BitConverter.GetBytes(v); } + /// + /// Writes a double to the wire. + /// + /// The value to write. + /// containing the wire buffer. internal void WriteDouble(double v, TdsParserStateObject stateObj) { - byte[] bytes = BitConverter.GetBytes(v); - - stateObj.WriteByteArray(bytes, bytes.Length, 0); + Span bytes = stackalloc byte[sizeof(double)]; + BinaryPrimitives.WriteInt64LittleEndian(bytes, BitConverter.DoubleToInt64Bits(v)); + stateObj.WriteByteSpan(bytes); } internal void PrepareResetConnection(bool preserveTransaction) @@ -4139,11 +4244,10 @@ internal TdsOperationStatus TryProcessReturnValue(int length, out SqlReturnValue returnValue, SqlCommandColumnEncryptionSetting columnEncryptionSetting) { - TdsOperationStatus result; returnValue = null; SqlReturnValue rec = new SqlReturnValue(); rec.length = length; // In 2005 this length is -1 - result = stateObj.TryReadUInt16(out rec.parmIndex); + TdsOperationStatus result = stateObj.TryReadUInt16(out rec.parmIndex); if (result != TdsOperationStatus.Done) { return result; @@ -4695,9 +4799,10 @@ internal void DrainData(TdsParserStateObject stateObj) if (sharedState != null && sharedState._dataReady) { var metadata = stateObj._cleanupMetaData; + TdsOperationStatus result; if (stateObj._partialHeaderBytesRead > 0) { - TdsOperationStatus result = stateObj.TryProcessHeader(); + result = stateObj.TryProcessHeader(); if (result != TdsOperationStatus.Done) { throw SQL.SynchronousCallMayNotPend(); @@ -4706,7 +4811,7 @@ internal void DrainData(TdsParserStateObject stateObj) if (0 == sharedState._nextColumnHeaderToRead) { // i. user called read but didn't fetch anything - TdsOperationStatus result = stateObj.Parser.TrySkipRow(stateObj._cleanupMetaData, stateObj); + result = stateObj.Parser.TrySkipRow(stateObj._cleanupMetaData, stateObj); if (result != TdsOperationStatus.Done) { throw SQL.SynchronousCallMayNotPend(); @@ -4721,7 +4826,7 @@ internal void DrainData(TdsParserStateObject stateObj) { if (stateObj._longlen != 0) { - TdsOperationStatus result = TrySkipPlpValue(UInt64.MaxValue, stateObj, out _); + result = TrySkipPlpValue(ulong.MaxValue, stateObj, out _); if (result != TdsOperationStatus.Done) { throw SQL.SynchronousCallMayNotPend(); @@ -4731,7 +4836,7 @@ internal void DrainData(TdsParserStateObject stateObj) else if (0 < sharedState._columnDataBytesRemaining) { - TdsOperationStatus result = stateObj.TrySkipLongBytes(sharedState._columnDataBytesRemaining); + result = stateObj.TrySkipLongBytes(sharedState._columnDataBytesRemaining); if (result != TdsOperationStatus.Done) { throw SQL.SynchronousCallMayNotPend(); @@ -4742,7 +4847,8 @@ internal void DrainData(TdsParserStateObject stateObj) // Read the remaining values off the wire for this row - if (stateObj.Parser.TrySkipRow(metadata, sharedState._nextColumnHeaderToRead, stateObj) != TdsOperationStatus.Done) + result = stateObj.Parser.TrySkipRow(metadata, sharedState._nextColumnHeaderToRead, stateObj); + if (result != TdsOperationStatus.Done) { throw SQL.SynchronousCallMayNotPend(); } @@ -5069,9 +5175,10 @@ internal TdsOperationStatus TryProcessMetaData(int cColumns, TdsParserStateObjec // Read the cipher info table first SqlTceCipherInfoTable cipherTable = null; + TdsOperationStatus result; if (IsColumnEncryptionSupported) { - TdsOperationStatus result = TryProcessCipherInfoTable(stateObj, out cipherTable); + result = TryProcessCipherInfoTable(stateObj, out cipherTable); if (result != TdsOperationStatus.Done) { metaData = null; @@ -5083,7 +5190,7 @@ internal TdsOperationStatus TryProcessMetaData(int cColumns, TdsParserStateObjec _SqlMetaDataSet newMetaData = new _SqlMetaDataSet(cColumns, cipherTable); for (int i = 0; i < cColumns; i++) { - TdsOperationStatus result = TryCommonProcessMetaData(stateObj, newMetaData[i], cipherTable, fColMD: true, columnEncryptionSetting: columnEncryptionSetting); + result = TryCommonProcessMetaData(stateObj, newMetaData[i], cipherTable, fColMD: true, columnEncryptionSetting: columnEncryptionSetting); if (result != TdsOperationStatus.Done) { metaData = null; @@ -5302,10 +5409,9 @@ private TdsOperationStatus TryCommonProcessMetaData(TdsParserStateObject stateOb { byte byteLen; uint userType; - TdsOperationStatus result; // read user type - 4 bytes 2005, 2 backwards - result = stateObj.TryReadUInt32(out userType); + TdsOperationStatus result = stateObj.TryReadUInt32(out userType); if (result != TdsOperationStatus.Done) { return result; @@ -5637,13 +5743,12 @@ private TdsOperationStatus TryProcessColInfo(_SqlMetaDataSet columns, SqlDataRea Debug.Assert(columns != null && columns.Length > 0, "no metadata available!"); metaData = null; - TdsOperationStatus result; for (int i = 0; i < columns.Length; i++) { _SqlMetaData col = columns[i]; - result = stateObj.TryReadByte(out _); + TdsOperationStatus result = stateObj.TryReadByte(out _); if (result != TdsOperationStatus.Done) { return result; @@ -6932,18 +7037,17 @@ internal TdsOperationStatus TryReadSqlValueInternal(SqlBuffer value, byte tdsTyp { Debug.Assert(length == GUID_SIZE, "invalid length for SqlGuid type!"); - byte[] b = _tempGuidBytes; - if (b is null) - { - b = new byte[GUID_SIZE]; - } +#if NET + Span b = stackalloc byte[GUID_SIZE]; +#else + byte[] b = (_tempGuidBytes ??= new byte[GUID_SIZE]); +#endif result = stateObj.TryReadByteArray(b, length); if (result != TdsOperationStatus.Done) { return result; } value.Guid = new Guid(b); - _tempGuidBytes = b; break; } @@ -7289,11 +7393,8 @@ internal Task WriteSqlVariantValue(object value, int length, int offset, TdsPars case TdsEnums.SQLUNIQUEID: { - System.Guid guid = (System.Guid)value; - byte[] b = guid.ToByteArray(); - - Debug.Assert((length == b.Length) && (length == 16), "Invalid length for guid type in com+ object"); - stateObj.WriteByteArray(b, length, 0); + Debug.Assert(length == 16, "Invalid length for guid type in com+ object"); + WriteGuid((Guid)value, stateObj); break; } @@ -7446,13 +7547,8 @@ internal Task WriteSqlVariantDataRowValue(object value, TdsParserStateObject sta case TdsEnums.SQLUNIQUEID: { - System.Guid guid = (System.Guid)value; - byte[] b = guid.ToByteArray(); - - length = b.Length; - Debug.Assert(length == 16, "Invalid length for guid type in com+ object"); WriteSqlVariantHeader(18, metatype.TDSType, metatype.PropBytes, stateObj); - stateObj.WriteByteArray(b, length, 0); + WriteGuid((Guid)value, stateObj); break; } @@ -8208,6 +8304,7 @@ internal TdsOperationStatus TryGetDataLength(SqlMetaDataPriv colmeta, TdsParserS internal TdsOperationStatus TryGetTokenLength(byte token, TdsParserStateObject stateObj, out int tokenLength) { Debug.Assert(token != 0, "0 length token!"); + TdsOperationStatus result; switch (token) { // rules about SQLLenMask no longer apply to new tokens (as of 7.4) @@ -8219,8 +8316,6 @@ internal TdsOperationStatus TryGetTokenLength(byte token, TdsParserStateObject s return stateObj.TryReadInt32(out tokenLength); } - TdsOperationStatus result; - if (token == TdsEnums.SQLUDT) { // special case for UDTs tokenLength = -1; // Should we return -1 or not call GetTokenLength for UDTs? @@ -8590,63 +8685,63 @@ internal int WriteFedAuthFeatureRequest(FederatedAuthenticationFeatureExtensionD return totalLen; } - internal int WriteDataClassificationFeatureRequest(bool write /* if false just calculates the length */) + internal int WriteTceFeatureRequest(bool write /* if false just calculates the length */) { int len = 6; // 1byte = featureID, 4bytes = featureData length, 1 bytes = Version if (write) { - // Write Feature ID, length of the version# field and Sensitivity Classification Version# - _physicalStateObj.WriteByte(TdsEnums.FEATUREEXT_DATACLASSIFICATION); + // Write Feature ID, length of the version# field and TCE Version# + _physicalStateObj.WriteByte(TdsEnums.FEATUREEXT_TCE); WriteInt(1, _physicalStateObj); - _physicalStateObj.WriteByte(TdsEnums.DATA_CLASSIFICATION_VERSION_MAX_SUPPORTED); + _physicalStateObj.WriteByte(TdsEnums.MAX_SUPPORTED_TCE_VERSION); } return len; // size of data written } - internal int WriteTceFeatureRequest(bool write /* if false just calculates the length */) + internal int WriteAzureSQLSupportFeatureRequest(bool write /* if false just calculates the length */) { - int len = 6; // 1byte = featureID, 4bytes = featureData length, 1 bytes = Version + int len = 6; // 1byte = featureID, 4bytes = featureData length, 1 bytes = featureData if (write) { - // Write Feature ID, length of the version# field and TCE Version# - _physicalStateObj.WriteByte(TdsEnums.FEATUREEXT_TCE); - WriteInt(1, _physicalStateObj); - _physicalStateObj.WriteByte(TdsEnums.MAX_SUPPORTED_TCE_VERSION); + // Write Feature ID + _physicalStateObj.WriteByte(TdsEnums.FEATUREEXT_AZURESQLSUPPORT); + + // Feature Data length + WriteInt(s_featureExtDataAzureSQLSupportFeatureRequest.Length, _physicalStateObj); + + _physicalStateObj.WriteByteArray(s_featureExtDataAzureSQLSupportFeatureRequest, s_featureExtDataAzureSQLSupportFeatureRequest.Length, 0); } - return len; // size of data written + return len; } - internal int WriteGlobalTransactionsFeatureRequest(bool write /* if false just calculates the length */) + internal int WriteDataClassificationFeatureRequest(bool write /* if false just calculates the length */) { - int len = 5; // 1byte = featureID, 4bytes = featureData length + int len = 6; // 1byte = featureID, 4bytes = featureData length, 1 bytes = Version if (write) { - // Write Feature ID - _physicalStateObj.WriteByte(TdsEnums.FEATUREEXT_GLOBALTRANSACTIONS); - WriteInt(0, _physicalStateObj); // we don't send any data + // Write Feature ID, length of the version# field and Sensitivity Classification Version# + _physicalStateObj.WriteByte(TdsEnums.FEATUREEXT_DATACLASSIFICATION); + WriteInt(1, _physicalStateObj); + _physicalStateObj.WriteByte(TdsEnums.DATA_CLASSIFICATION_VERSION_MAX_SUPPORTED); } - return len; + return len; // size of data written } - internal int WriteAzureSQLSupportFeatureRequest(bool write /* if false just calculates the length */) + internal int WriteGlobalTransactionsFeatureRequest(bool write /* if false just calculates the length */) { - int len = 6; // 1byte = featureID, 4bytes = featureData length, 1 bytes = featureData + int len = 5; // 1byte = featureID, 4bytes = featureData length if (write) { // Write Feature ID - _physicalStateObj.WriteByte(TdsEnums.FEATUREEXT_AZURESQLSUPPORT); - - // Feature Data length - WriteInt(s_featureExtDataAzureSQLSupportFeatureRequest.Length, _physicalStateObj); - - _physicalStateObj.WriteByteArray(s_featureExtDataAzureSQLSupportFeatureRequest, s_featureExtDataAzureSQLSupportFeatureRequest.Length, 0); + _physicalStateObj.WriteByte(TdsEnums.FEATUREEXT_GLOBALTRANSACTIONS); + WriteInt(0, _physicalStateObj); // we don't send any data } return len; @@ -9533,29 +9628,34 @@ internal Task TdsExecuteSQLBatch(string text, int timeout, SqlNotificationReques // Need to wait for flush - continuation will unlock the connection bool taskReleaseConnectionLock = releaseConnectionLock; releaseConnectionLock = false; - return executeTask.ContinueWith(t => - { - Debug.Assert(!t.IsCanceled, "Task should not be canceled"); - try - { - if (t.IsFaulted) - { - FailureCleanup(stateObj, t.Exception.InnerException); - throw t.Exception.InnerException; - } - else + return executeTask.ContinueWith( + static (Task task, object state) => + { + Debug.Assert(!task.IsCanceled, "Task should not be canceled"); + var parameters = (Tuple)state; + TdsParser parser = parameters.Item1; + TdsParserStateObject tdsParserStateObject = parameters.Item2; + SqlInternalConnectionTds internalConnectionTds = parameters.Item3; + try { - stateObj.SniContext = SniContext.Snix_Read; + if (task.IsFaulted) + { + parser.FailureCleanup(tdsParserStateObject, task.Exception.InnerException); + throw task.Exception.InnerException; + } + else + { + tdsParserStateObject.SniContext = SniContext.Snix_Read; + } } - } - finally - { - if (taskReleaseConnectionLock) + finally { - _connHandler._parserLock.Release(); + internalConnectionTds?._parserLock.Release(); } - } - }, TaskScheduler.Default); + }, + Tuple.Create(this, stateObj, taskReleaseConnectionLock ? _connHandler : null), + TaskScheduler.Default + ); } // Finished sync @@ -10329,27 +10429,23 @@ private Task TDSExecuteRPCAddParameter(TdsParserStateObject stateObj, SqlParamet // This is in its own method to avoid always allocating the lambda in TDSExecuteRPCParameter private void TDSExecuteRPCParameterSetupWriteCompletion(SqlCommand cmd, IList<_SqlRPC> rpcArray, int timeout, bool inSchema, SqlNotificationRequest notificationRequest, TdsParserStateObject stateObj, bool isCommandProc, bool sync, TaskCompletionSource completion, int startRpc, int startParam, Task writeParamTask) { - AsyncHelper.ContinueTaskWithState( + AsyncHelper.ContinueTask( writeParamTask, completion, - this, - (object state) => - { - TdsParser tdsParser = (TdsParser)state; - TdsExecuteRPC( - cmd, - rpcArray, - timeout, - inSchema, - notificationRequest, - stateObj, - isCommandProc, - sync, - completion, - startRpc, - startParam); - }, - onFailure: (Exception exc, object state) => ((TdsParser)state).TdsExecuteRPC_OnFailure(exc, stateObj), + () => TdsExecuteRPC( + cmd, + rpcArray, + timeout, + inSchema, + notificationRequest, + stateObj, + isCommandProc, + sync, + completion, + startRpc, + startParam + ), + onFailure: exc => TdsExecuteRPC_OnFailure(exc, stateObj), connectionToDoom: _connHandler ); } @@ -11110,7 +11206,7 @@ internal void WriteBulkCopyMetaData(_SqlMetaDataSet metadataCollection, int coun stateObj.WriteByte(md.scale); break; case SqlDbTypeExtensions.Json: - stateObj.WriteByteArray(s_jsonMetadataSubstituteSequence, s_xmlMetadataSubstituteSequence.Length, 0); + stateObj.WriteByteArray(s_jsonMetadataSubstituteSequence, s_jsonMetadataSubstituteSequence.Length, 0); break; case SqlDbTypeExtensions.Vector: stateObj.WriteByte(md.tdsType); @@ -11834,18 +11930,16 @@ private Task WriteUnterminatedSqlValue(object value, MetaType type, int actualLe case TdsEnums.SQLUNIQUEID: { - byte[] b; + Debug.Assert(actualLength == 16, "Invalid length for guid type in com+ object"); if (value is Guid guid) { - b = guid.ToByteArray(); + WriteGuid(in guid, stateObj); } else { - b = ((SqlGuid)value).ToByteArray(); + SqlGuid sqlGuid = (SqlGuid)value; + WriteGuid(in sqlGuid, stateObj); } - - Debug.Assert((actualLength == b.Length) && (actualLength == 16), "Invalid length for guid type in com+ object"); - stateObj.WriteByteArray(b, actualLength, 0); break; } @@ -12501,11 +12595,8 @@ private Task WriteUnterminatedValue(object value, MetaType type, byte scale, int case TdsEnums.SQLUNIQUEID: { - System.Guid guid = (System.Guid)value; - byte[] b = guid.ToByteArray(); - - Debug.Assert((actualLength == b.Length) && (actualLength == 16), "Invalid length for guid type in com+ object"); - stateObj.WriteByteArray(b, actualLength, 0); + Debug.Assert(actualLength == 16, "Invalid length for guid type in com+ object"); + WriteGuid((Guid)value, stateObj); break; } @@ -13218,6 +13309,8 @@ internal TdsOperationStatus TryReadPlpUnicodeCharsWithContinue(TdsParserStateObj char[] temp = null; bool buffIsRented = false; int startOffset = 0; + + stateObj.RequestContinue(true); (bool canContinue, bool isStarting, bool isContinuing) = stateObj.GetSnapshotStatuses(); if (canContinue) @@ -13626,8 +13719,8 @@ internal TdsOperationStatus TrySkipPlpValue(ulong cb, TdsParserStateObject state { // Read and skip cb bytes or until ReadPlpLength returns 0. int bytesSkipped; - totalBytesSkipped = 0; TdsOperationStatus result; + totalBytesSkipped = 0; if (stateObj._longlenleft == 0) { @@ -13727,8 +13820,9 @@ internal ulong PlpBytesTotalLength(TdsParserStateObject stateObj) + " _attentionWarnings = {20}\n\t" + " _statistics = {21}\n\t" + " _statisticsIsInTransaction = {22}\n\t" - + " _fPreserveTransaction = {23}" - + " _fParallel = {24}" + + " _fPreserveTransaction = {23}\n\t" + + " _multiSubnetFailover = {24}\n\t" + + " _transparentNetworkIPResolution = {25}" ; internal string TraceString() { diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/ParametersTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/ParametersTest.cs index 88f99a2f51..206387c185 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/ParametersTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/ParametersTest.cs @@ -244,8 +244,17 @@ public static void Test_WithGuidValue_ShouldReturnGuid() var expectedGuid = Guid.NewGuid(); var cmd = new SqlCommand("select @input", conn); cmd.Parameters.AddWithValue("@input", expectedGuid); + var result = cmd.ExecuteScalar(); Assert.Equal(expectedGuid, (Guid)result); + + cmd.Parameters[0].Value = new SqlGuid(expectedGuid); + result = cmd.ExecuteScalar(); + Assert.Equal(expectedGuid, (Guid)result); + + cmd.Parameters[0].Value = SqlGuid.Null; + result = cmd.ExecuteScalar(); + Assert.Equal(DBNull.Value, result); } // Synapse: Parse error at line: 1, column: 8: Incorrect syntax near 'TYPE'. From 6b0c5c2192edcfc87bf73d881809858019610b28 Mon Sep 17 00:00:00 2001 From: Shreya Laxminarayana Rao <147193825+ShreyaLaxminarayan@users.noreply.github.com> Date: Wed, 17 Sep 2025 15:02:37 +0530 Subject: [PATCH 07/30] Fix Debug Assertion in Connection Pool Due to Double Deactivation (#3587) Co-authored-by: Shreya Rao --- .../Data/ProviderBase/DbConnectionInternal.cs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/ProviderBase/DbConnectionInternal.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/ProviderBase/DbConnectionInternal.cs index e1a86fa0e7..472edf6888 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/ProviderBase/DbConnectionInternal.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/ProviderBase/DbConnectionInternal.cs @@ -520,8 +520,19 @@ internal void DeactivateConnection() SqlClientEventSource.Log.TryPoolerTraceEvent(" {0}, Deactivating", ObjectID); #if DEBUG - int activateCount = Interlocked.Decrement(ref _activateCount); - Debug.Assert(activateCount == 0, "activated multiple times?"); + int origCount, newCount; + do + { + origCount = _activateCount; + + if (origCount == 0) + { + break; + } + + newCount = origCount - 1; + } + while (Interlocked.CompareExchange(ref _activateCount, newCount, origCount) != origCount); #endif SqlClientEventSource.Metrics.ExitActiveConnection(); From 5d136ea8c88f5a1a3f0465815b1e0f7c63678fc2 Mon Sep 17 00:00:00 2001 From: Paul Medynski <31868385+paulmedynski@users.noreply.github.com> Date: Wed, 17 Sep 2025 08:59:04 -0300 Subject: [PATCH 08/30] User Story 37654: Create Abstractions package - Changed MDS to reference Abstractions via project or package depending on build parameters. - Removed obsolete package reference files. - Updated CI pipelines to build Abstractions in parallel for Project-based builds. --- BUILDGUIDE.md | 3 +- build.proj | 120 ++++++++++++------ eng/pipelines/dotnet-sqlclient-ci-core.yml | 8 +- packages/.gitignore | 12 -- src/Directory.Packages.props | 8 +- src/Microsoft.Data.SqlClient.sln | 73 ++++++----- src/Microsoft.Data.SqlClient/NuGet.config | 13 -- .../ref/Microsoft.Data.SqlClient.csproj | 16 ++- .../src/Microsoft.Data.SqlClient.csproj | 14 +- .../netfx/ref/Microsoft.Data.SqlClient.csproj | 15 ++- .../netfx/src/Microsoft.Data.SqlClient.csproj | 15 ++- 11 files changed, 191 insertions(+), 106 deletions(-) delete mode 100644 packages/.gitignore delete mode 100644 src/Microsoft.Data.SqlClient/NuGet.config diff --git a/BUILDGUIDE.md b/BUILDGUIDE.md index 62dc090372..178c3fc2d6 100644 --- a/BUILDGUIDE.md +++ b/BUILDGUIDE.md @@ -27,8 +27,7 @@ The following build targets are defined in `build.proj`: |`BuildNetFx`|Builds the .NET Framework driver for all target frameworks.| |`BuildTestsNetCore`|Builds tests for the .NET driver.| |`BuildTestsNetFx`|Builds tests for the .NET Framework driver.| -|`Clean`|Cleans generated files, except for NuGet packages published to `packages/`.| -|`CleanAll`|Cleans all generated files.| +|`Clean`|Cleans all generated files.| |`Restore`|Restores NuGet packages.| |`RunTests`|Runs the unit, functional, and manual tests for the .NET Framework and .NET drivers| |`RunUnitTests`|Runs just the unit tests for the .NET Framework and .NET drivers| diff --git a/build.proj b/build.proj index 0cf4efd4de..27aa557b54 100644 --- a/build.proj +++ b/build.proj @@ -29,7 +29,7 @@ true Configuration=$(Configuration);AssemblyVersion=$(SqlServerAssemblyVersion);AssemblyFileVersion=$(SqlServerAssemblyFileVersion);Version=$(SqlServerPackageVersion); Configuration=$(Configuration);AssemblyFileVersion=$(AssemblyFileVersion);TargetsWindows=$(TargetsWindows);TargetsUnix=$(TargetsUnix); - BuildProjectReferences=false;$(ProjectProperties);BuildForRelease=false;TargetNetCoreVersion=$(TargetNetCoreVersion);TargetNetFxVersion=$(TargetNetFxVersion) + $(ProjectProperties);BuildForRelease=false;TargetNetCoreVersion=$(TargetNetCoreVersion);TargetNetFxVersion=$(TargetNetFxVersion) TestResults - - + + - - - - - + + + + + - + - + - + - + @@ -149,7 +160,10 @@ - + @@ -166,27 +180,37 @@ - + - + + - + - - + + @@ -195,7 +219,9 @@ - + @@ -204,12 +230,18 @@ - + - + @@ -218,7 +250,10 @@ - + @@ -373,19 +408,15 @@ - + + - - - - - @@ -419,7 +450,10 @@ - + @@ -429,7 +463,9 @@ - + @@ -439,7 +475,9 @@ - + diff --git a/eng/pipelines/dotnet-sqlclient-ci-core.yml b/eng/pipelines/dotnet-sqlclient-ci-core.yml index 7415169212..a569581e80 100644 --- a/eng/pipelines/dotnet-sqlclient-ci-core.yml +++ b/eng/pipelines/dotnet-sqlclient-ci-core.yml @@ -119,7 +119,13 @@ stages: # Build MDS and its NuGet packages. - stage: build_nugets displayName: 'Build NuGet Packages' - dependsOn: build_abstractions_package_stage + + # When building MDS via packages, we must depend on the Abstractions + # package. + ${{ if eq(parameters.buildType, 'Package') }}: + dependsOn: + - build_abstractions_package_stage + jobs: - template: common/templates/jobs/ci-build-nugets-job.yml@self parameters: diff --git a/packages/.gitignore b/packages/.gitignore deleted file mode 100644 index b275e0d002..0000000000 --- a/packages/.gitignore +++ /dev/null @@ -1,12 +0,0 @@ -# The packages/ directory must exist for local development due to the various -# NuGet.config files that refer to it. However, we never want any files in -# this directory to be included in source control. -# -# Git doesn't track directories, only files, so we need this .gitignore file -# to force Git into tracking the packages/ directory itself. - -# Ignore everything in this directory -* - -# Except this file -!.gitignore diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props index b3b1a64547..6cf7a6bc93 100644 --- a/src/Directory.Packages.props +++ b/src/Directory.Packages.props @@ -7,11 +7,17 @@ + + + + + - diff --git a/src/Microsoft.Data.SqlClient.sln b/src/Microsoft.Data.SqlClient.sln index 3947c0e5a6..2b8e583a8d 100644 --- a/src/Microsoft.Data.SqlClient.sln +++ b/src/Microsoft.Data.SqlClient.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 -VisualStudioVersion = 17.14.36203.30 d17.14 +VisualStudioVersion = 17.14.36203.30 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Data.SqlClient", "Microsoft.Data.SqlClient\netfx\src\Microsoft.Data.SqlClient.csproj", "{407890AC-9876-4FEF-A6F1-F36A876BAADE}" EndProject @@ -304,6 +304,18 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Data.SqlClient.Un EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Common", "Microsoft.Data.SqlClient\tests\Common\Common.csproj", "{67128EC0-30F5-6A98-448B-55F88A1DE707}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Microsoft.Data.SqlClient.Extensions", "Microsoft.Data.SqlClient.Extensions", "{19F1F1E5-3013-7660-661A-2A15F7D606C1}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Abstractions", "Abstractions", "{556B486E-F9B0-7EA9-6A25-DA560C312761}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{210228A5-979A-DE06-EE1F-B35C65E1583C}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Abstractions", "Microsoft.Data.SqlClient.Extensions\Abstractions\src\Abstractions.csproj", "{B21E7C94-D805-427E-928A-8DE8EA2F08CC}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{59667E4C-0BD2-9F48-FB50-9E55DD8B1011}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Abstractions.Test", "Microsoft.Data.SqlClient.Extensions\Abstractions\test\Abstractions.Test.csproj", "{04ACBF75-CFF2-41AB-B652-776BC0533490}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -572,30 +584,30 @@ Global {67128EC0-30F5-6A98-448B-55F88A1DE707}.Release|x64.Build.0 = Release|x64 {67128EC0-30F5-6A98-448B-55F88A1DE707}.Release|x86.ActiveCfg = Release|x86 {67128EC0-30F5-6A98-448B-55F88A1DE707}.Release|x86.Build.0 = Release|x86 - {AB71787B-C474-24D1-5EDF-345386CA2460}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {AB71787B-C474-24D1-5EDF-345386CA2460}.Debug|Any CPU.Build.0 = Debug|Any CPU - {AB71787B-C474-24D1-5EDF-345386CA2460}.Debug|x64.ActiveCfg = Debug|Any CPU - {AB71787B-C474-24D1-5EDF-345386CA2460}.Debug|x64.Build.0 = Debug|Any CPU - {AB71787B-C474-24D1-5EDF-345386CA2460}.Debug|x86.ActiveCfg = Debug|Any CPU - {AB71787B-C474-24D1-5EDF-345386CA2460}.Debug|x86.Build.0 = Debug|Any CPU - {AB71787B-C474-24D1-5EDF-345386CA2460}.Release|Any CPU.ActiveCfg = Release|Any CPU - {AB71787B-C474-24D1-5EDF-345386CA2460}.Release|Any CPU.Build.0 = Release|Any CPU - {AB71787B-C474-24D1-5EDF-345386CA2460}.Release|x64.ActiveCfg = Release|Any CPU - {AB71787B-C474-24D1-5EDF-345386CA2460}.Release|x64.Build.0 = Release|Any CPU - {AB71787B-C474-24D1-5EDF-345386CA2460}.Release|x86.ActiveCfg = Release|Any CPU - {AB71787B-C474-24D1-5EDF-345386CA2460}.Release|x86.Build.0 = Release|Any CPU - {3028DECE-90B8-2F58-6167-98722A3964D4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3028DECE-90B8-2F58-6167-98722A3964D4}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3028DECE-90B8-2F58-6167-98722A3964D4}.Debug|x64.ActiveCfg = Debug|Any CPU - {3028DECE-90B8-2F58-6167-98722A3964D4}.Debug|x64.Build.0 = Debug|Any CPU - {3028DECE-90B8-2F58-6167-98722A3964D4}.Debug|x86.ActiveCfg = Debug|Any CPU - {3028DECE-90B8-2F58-6167-98722A3964D4}.Debug|x86.Build.0 = Debug|Any CPU - {3028DECE-90B8-2F58-6167-98722A3964D4}.Release|Any CPU.ActiveCfg = Release|Any CPU - {3028DECE-90B8-2F58-6167-98722A3964D4}.Release|Any CPU.Build.0 = Release|Any CPU - {3028DECE-90B8-2F58-6167-98722A3964D4}.Release|x64.ActiveCfg = Release|Any CPU - {3028DECE-90B8-2F58-6167-98722A3964D4}.Release|x64.Build.0 = Release|Any CPU - {3028DECE-90B8-2F58-6167-98722A3964D4}.Release|x86.ActiveCfg = Release|Any CPU - {3028DECE-90B8-2F58-6167-98722A3964D4}.Release|x86.Build.0 = Release|Any CPU + {B21E7C94-D805-427E-928A-8DE8EA2F08CC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B21E7C94-D805-427E-928A-8DE8EA2F08CC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B21E7C94-D805-427E-928A-8DE8EA2F08CC}.Debug|x64.ActiveCfg = Debug|Any CPU + {B21E7C94-D805-427E-928A-8DE8EA2F08CC}.Debug|x64.Build.0 = Debug|Any CPU + {B21E7C94-D805-427E-928A-8DE8EA2F08CC}.Debug|x86.ActiveCfg = Debug|Any CPU + {B21E7C94-D805-427E-928A-8DE8EA2F08CC}.Debug|x86.Build.0 = Debug|Any CPU + {B21E7C94-D805-427E-928A-8DE8EA2F08CC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B21E7C94-D805-427E-928A-8DE8EA2F08CC}.Release|Any CPU.Build.0 = Release|Any CPU + {B21E7C94-D805-427E-928A-8DE8EA2F08CC}.Release|x64.ActiveCfg = Release|Any CPU + {B21E7C94-D805-427E-928A-8DE8EA2F08CC}.Release|x64.Build.0 = Release|Any CPU + {B21E7C94-D805-427E-928A-8DE8EA2F08CC}.Release|x86.ActiveCfg = Release|Any CPU + {B21E7C94-D805-427E-928A-8DE8EA2F08CC}.Release|x86.Build.0 = Release|Any CPU + {04ACBF75-CFF2-41AB-B652-776BC0533490}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {04ACBF75-CFF2-41AB-B652-776BC0533490}.Debug|Any CPU.Build.0 = Debug|Any CPU + {04ACBF75-CFF2-41AB-B652-776BC0533490}.Debug|x64.ActiveCfg = Debug|Any CPU + {04ACBF75-CFF2-41AB-B652-776BC0533490}.Debug|x64.Build.0 = Debug|Any CPU + {04ACBF75-CFF2-41AB-B652-776BC0533490}.Debug|x86.ActiveCfg = Debug|Any CPU + {04ACBF75-CFF2-41AB-B652-776BC0533490}.Debug|x86.Build.0 = Debug|Any CPU + {04ACBF75-CFF2-41AB-B652-776BC0533490}.Release|Any CPU.ActiveCfg = Release|Any CPU + {04ACBF75-CFF2-41AB-B652-776BC0533490}.Release|Any CPU.Build.0 = Release|Any CPU + {04ACBF75-CFF2-41AB-B652-776BC0533490}.Release|x64.ActiveCfg = Release|Any CPU + {04ACBF75-CFF2-41AB-B652-776BC0533490}.Release|x64.Build.0 = Release|Any CPU + {04ACBF75-CFF2-41AB-B652-776BC0533490}.Release|x86.ActiveCfg = Release|Any CPU + {04ACBF75-CFF2-41AB-B652-776BC0533490}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -646,12 +658,11 @@ Global {AD738BD4-6A02-4B88-8F93-FBBBA49A74C8} = {4CAE9195-4F1A-4D48-854C-1C9FBC512C66} {4461063D-2F2B-274C-7E6F-F235119D258E} = {0CC4817A-12F3-4357-912C-09315FAAD008} {67128EC0-30F5-6A98-448B-55F88A1DE707} = {0CC4817A-12F3-4357-912C-09315FAAD008} - {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} = {4F3CD363-B1E6-4D6D-9466-97D78A56BE45} - {5612FCAA-05D3-4E79-94E5-EEDB2DC70524} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} - {827E0CD3-B72D-47B6-A68D-7590B98EB39B} = {5612FCAA-05D3-4E79-94E5-EEDB2DC70524} - {AB71787B-C474-24D1-5EDF-345386CA2460} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B} - {0C88DD14-F956-CE84-757C-A364CCF449FC} = {5612FCAA-05D3-4E79-94E5-EEDB2DC70524} - {3028DECE-90B8-2F58-6167-98722A3964D4} = {0C88DD14-F956-CE84-757C-A364CCF449FC} + {556B486E-F9B0-7EA9-6A25-DA560C312761} = {19F1F1E5-3013-7660-661A-2A15F7D606C1} + {210228A5-979A-DE06-EE1F-B35C65E1583C} = {556B486E-F9B0-7EA9-6A25-DA560C312761} + {B21E7C94-D805-427E-928A-8DE8EA2F08CC} = {210228A5-979A-DE06-EE1F-B35C65E1583C} + {59667E4C-0BD2-9F48-FB50-9E55DD8B1011} = {556B486E-F9B0-7EA9-6A25-DA560C312761} + {04ACBF75-CFF2-41AB-B652-776BC0533490} = {59667E4C-0BD2-9F48-FB50-9E55DD8B1011} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {01D48116-37A2-4D33-B9EC-94793C702431} diff --git a/src/Microsoft.Data.SqlClient/NuGet.config b/src/Microsoft.Data.SqlClient/NuGet.config deleted file mode 100644 index 3bfab46bfa..0000000000 --- a/src/Microsoft.Data.SqlClient/NuGet.config +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - diff --git a/src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.csproj index 2539ff8402..4b658f409a 100644 --- a/src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.csproj @@ -35,7 +35,6 @@ - @@ -47,7 +46,20 @@ - + + + + + + + diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj index bb83a62401..0032ba4bf6 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj @@ -1056,7 +1056,6 @@ - @@ -1069,6 +1068,19 @@ + + + + + + diff --git a/src/Microsoft.Data.SqlClient/netfx/ref/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netfx/ref/Microsoft.Data.SqlClient.csproj index 716a687c22..f73b8682a0 100644 --- a/src/Microsoft.Data.SqlClient/netfx/ref/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netfx/ref/Microsoft.Data.SqlClient.csproj @@ -35,7 +35,6 @@ - All runtime; build; native; contentfiles; analyzers; buildtransitive @@ -50,5 +49,19 @@ + + + + + + + diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj index 54d8d5c6d3..a378ef5f51 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj @@ -1025,7 +1025,6 @@ - All runtime; build; native; contentfiles; analyzers; buildtransitive @@ -1041,6 +1040,20 @@ + + + + + + + From beaf9c393eeaaad69e246e7c49a6abea21f48455 Mon Sep 17 00:00:00 2001 From: Paul Medynski <31868385+paulmedynski@users.noreply.github.com> Date: Wed, 17 Sep 2025 12:51:06 -0300 Subject: [PATCH 09/30] User Story 37654: Create Abstractions package - Modularized Abstractions CI templates. --- build.proj | 25 +- eng/pipelines/dotnet-sqlclient-ci-core.yml | 11 +- .../jobs/pack-abstractions-package-ci-job.yml | 143 ++++++++ eng/pipelines/jobs/stress-tests-ci-job.yml | 2 +- .../jobs/test-abstractions-package-ci-job.yml | 174 ++++++++++ .../build-abstractions-package-ci-stage.yml | 305 +++--------------- 6 files changed, 382 insertions(+), 278 deletions(-) create mode 100644 eng/pipelines/jobs/pack-abstractions-package-ci-job.yml create mode 100644 eng/pipelines/jobs/test-abstractions-package-ci-job.yml diff --git a/build.proj b/build.proj index 27aa557b54..082dd58f31 100644 --- a/build.proj +++ b/build.proj @@ -51,7 +51,8 @@ - + + @@ -120,6 +121,28 @@ Properties="$(BuildProperties)" /> + + + AbstractionsPackageVersion=$(AbstractionsPackageVersion) + + + + + + + + AbstractionsPackageVersion=$(AbstractionsPackageVersion) + + + + + diff --git a/eng/pipelines/dotnet-sqlclient-ci-core.yml b/eng/pipelines/dotnet-sqlclient-ci-core.yml index a569581e80..903f39d17d 100644 --- a/eng/pipelines/dotnet-sqlclient-ci-core.yml +++ b/eng/pipelines/dotnet-sqlclient-ci-core.yml @@ -117,8 +117,8 @@ stages: verbosity: diagnostic # Build MDS and its NuGet packages. - - stage: build_nugets - displayName: 'Build NuGet Packages' + - stage: build_mds_package + displayName: 'Build MDS Package' # When building MDS via packages, we must depend on the Abstractions # package. @@ -157,17 +157,12 @@ stages: testsTimeout: ${{ parameters.testsTimeout }} abstractionsPackageVersion: ${{parameters.abstractionsPackageVersion}} - # When testing MDS via packages, we must depend on the Abstractions _and_ + # When testing MDS via packages, we must depend on the Abstractions and # MDS packages. ${{ if eq(parameters.buildType, 'Package') }}: dependsOn: - build_abstractions_package_stage - build_nugets - # When testing MDS via projects, we only depend on the Abstrations - # package. - ${{ else }}: - dependsOn: - - build_abstractions_package_stage ${{if ne(parameters.SNIVersion, '')}}: prebuildSteps: # steps to run prior to building and running tests on each job diff --git a/eng/pipelines/jobs/pack-abstractions-package-ci-job.yml b/eng/pipelines/jobs/pack-abstractions-package-ci-job.yml new file mode 100644 index 0000000000..d7a6807474 --- /dev/null +++ b/eng/pipelines/jobs/pack-abstractions-package-ci-job.yml @@ -0,0 +1,143 @@ +################################################################################ +# Licensed to the .NET Foundation under one or more agreements. The .NET +# Foundation licenses this file to you under the MIT license. See the LICENSE +# file in the project root for more information. +################################################################################ + +# This job packs the Abstractions package into NuGet and symbols packages and +# publishes them as a named pipeline artifact. +# +# This template defines a job named 'pack_abstractions_package_job' that can be +# depended on by downstream jobs. + +parameters: + + # The name to apply to the published pipeline artifact. + - name: artifactName + type: string + default: Abstractions.Artifact + + # The type of build to test (Release or Debug) + - name: buildConfiguration + type: string + values: + - Release + - Debug + + # The list of upstream jobs to depend on. + - name: dependsOn + type: object + default: [] + + # The verbosity level for the dotnet CLI commands. + - name: verbosity + type: string + default: normal + values: + - quiet + - minimal + - normal + - detailed + - diagnostic + +jobs: + + - job: pack_abstractions_package_job + displayName: 'Pack Abstractions Package' + + dependsOn: ${{ parameters.dependsOn }} + + pool: + name: Azure Pipelines + vmImage: ubuntu-latest + + variables: + + # The Abstractions solution file to use for all dotnet CLI commands. + - name: solution + value: src/Microsoft.Data.SqlClient.Extensions/Abstractions/Abstractions.slnx + + # The directory where the NuGet packages will be staged before being + # published as pipeline artifacts. + - name: dotnetPackagesDir + value: $(Build.StagingDirectory)/dotnetPackages + + # dotnet CLI arguments common to all commands. + - name: commonArguments + value: >- + --verbosity ${{ parameters.verbosity }} + + # dotnet CLI arguments for build/test/pack commands + - name: buildArguments + value: >- + $(commonArguments) + --configuration ${{ parameters.buildConfiguration }} + + # Explicitly unset the $PLATFORM environment variable that is set by the + # 'ADO Build properties' Library in the ADO SqlClientDrivers public project. + # This is defined with a non-standard Platform of 'AnyCPU', and will fail + # the builds if left defined. The stress tests solution does not require + # any specific Platform, and so its solution file doesn't support any + # non-standard platforms. + # + # Note that Azure Pipelines will inject this variable as PLATFORM into the + # environment of all tasks in this job. + # + # See: + # https://learn.microsoft.com/en-us/azure/devops/pipelines/process/variables?view=azure-devops&tabs=yaml%2Cbatch + # + - name: Platform + value: '' + + # Do the same for $CONFIGURATION since we explicitly set it using our + # 'buildConfiguration' parameter, and we don't want the environment to + # override us. + - name: Configuration + value: '' + + steps: + + # Install the .NET 9.0 SDK. + - task: UseDotNet@2 + displayName: Install .NET 9.0 SDK + inputs: + packageType: sdk + version: 9.x + + # We use the 'custom' command because the DotNetCoreCLI@2 task doesn't + # support all of our argument combinations for the different build steps. + + # Restore the solution. + - task: DotNetCoreCLI@2 + displayName: Restore Solution + inputs: + command: custom + custom: restore + projects: $(solution) + arguments: $(commonArguments) + + # Build the solution. + - task: DotNetCoreCLI@2 + displayName: Build Solution + inputs: + command: custom + custom: build + projects: $(solution) + arguments: $(buildArguments) --no-restore + + # Create the NuGet packages. + - task: DotNetCoreCLI@2 + displayName: Create NuGet Package + inputs: + command: custom + custom: pack + projects: $(solution) + arguments: $(buildArguments) --no-build -o $(dotnetPackagesDir) + + # Publish the NuGet packages as a named pipeline artifact. + - task: PublishPipelineArtifact@1 + displayName: Publish Pipeline Artifact + inputs: + targetPath: $(dotnetPackagesDir) + artifactName: ${{ parameters.artifactName }} + publishLocation: pipeline diff --git a/eng/pipelines/jobs/stress-tests-ci-job.yml b/eng/pipelines/jobs/stress-tests-ci-job.yml index 2e01470fe5..cc2913c367 100644 --- a/eng/pipelines/jobs/stress-tests-ci-job.yml +++ b/eng/pipelines/jobs/stress-tests-ci-job.yml @@ -4,7 +4,7 @@ # file in the project root for more information. ################################################################################ -# This stage builds and runs stress tests against an MDS NuGet package available +# This job builds and runs stress tests against an MDS NuGet package available # as a pipeline artifact. # # The stress tests are located here: diff --git a/eng/pipelines/jobs/test-abstractions-package-ci-job.yml b/eng/pipelines/jobs/test-abstractions-package-ci-job.yml new file mode 100644 index 0000000000..a2b25966d4 --- /dev/null +++ b/eng/pipelines/jobs/test-abstractions-package-ci-job.yml @@ -0,0 +1,174 @@ +################################################################################ +# Licensed to the .NET Foundation under one or more agreements. The .NET +# Foundation licenses this file to you under the MIT license. See the LICENSE +# file in the project root for more information. +################################################################################ + +# This job builds the Abstractions package and runs its tests for a set of .NET +# runtimes. +# +# This template defines a job named 'test_abstractions_package_job_' +# that can be depended on by downstream jobs. + +parameters: + + # The type of build to test (Release or Debug) + - name: buildConfiguration + type: string + values: + - Release + - Debug + + # The prefix to prepend to the job's display name: + # + # [] Run Stress Tests + # + - name: displayNamePrefix + type: string + + # The suffix to append to the job name. + - name: jobNameSuffix + type: string + + # The list of .NET Framework runtimes to test against. + - name: netFrameworkRuntimes + type: object + default: [] + + # The list of .NET runtimes to test against. + - name: netRuntimes + type: object + default: [] + + # The name of the Azure Pipelines pool to use. + - name: poolName + type: string + + # The verbosity level for the dotnet CLI commands. + - name: verbosity + type: string + default: normal + values: + - quiet + - minimal + - normal + - detailed + - diagnostic + + # The pool VM image to use. + - name: vmImage + type: string + +jobs: + + - job: test_abstractions_package_job_${{ parameters.jobNameSuffix }} + displayName: '[${{ parameters.displayNamePrefix }}] Test Abstractions Package' + pool: + name: ${{ parameters.poolName }} + + # Images provided by Azure Pipelines must be selected using 'vmImage'. + ${{ if eq(parameters.poolName, 'Azure Pipelines') }}: + vmImage: ${{ parameters.vmImage }} + # Images provided by 1ES must be selected using a demand. + ${{ else }}: + demands: + - imageOverride -equals ${{ parameters.vmImage }} + + variables: + + # The Abstractions solution file to use for all dotnet CLI commands. + - name: solution + value: src/Microsoft.Data.SqlClient.Extensions/Abstractions/Abstractions.slnx + + # dotnet CLI arguments common to all commands. + - name: commonArguments + value: >- + --verbosity ${{ parameters.verbosity }} + + # dotnet CLI arguments for build/test/pack commands + - name: buildArguments + value: >- + $(commonArguments) + --configuration ${{ parameters.buildConfiguration }} + + # Explicitly unset the $PLATFORM environment variable that is set by the + # 'ADO Build properties' Library in the ADO SqlClientDrivers public project. + # This is defined with a non-standard Platform of 'AnyCPU', and will fail + # the builds if left defined. The stress tests solution does not require + # any specific Platform, and so its solution file doesn't support any + # non-standard platforms. + # + # Note that Azure Pipelines will inject this variable as PLATFORM into the + # environment of all tasks in this job. + # + # See: + # https://learn.microsoft.com/en-us/azure/devops/pipelines/process/variables?view=azure-devops&tabs=yaml%2Cbatch + # + - name: Platform + value: '' + + # Do the same for $CONFIGURATION since we explicitly set it using our + # 'buildConfiguration' parameter, and we don't want the environment to + # override us. + - name: Configuration + value: '' + + steps: + + # Install the .NET 9.0 SDK. + - task: UseDotNet@2 + displayName: Install .NET 9.0 SDK + inputs: + packageType: sdk + version: 9.x + + # Install the .NET 8.0 runtime. + - task: UseDotNet@2 + displayName: Install .NET 8.0 Runtime + inputs: + packageType: runtime + version: 8.x + + # The Windows agent images include a suitable .NET Framework runtime, so + # we don't have to install one explicitly. + + # We use the 'custom' command because the DotNetCoreCLI@2 task doesn't + # support all of our argument combinations for the different build steps. + + # Restore the solution. + - task: DotNetCoreCLI@2 + displayName: Restore Solution + inputs: + command: custom + custom: restore + projects: $(solution) + arguments: $(commonArguments) + + # Build the solution. + - task: DotNetCoreCLI@2 + displayName: Build Solution + inputs: + command: custom + custom: build + projects: $(solution) + arguments: $(buildArguments) --no-restore + + # Run the tests for each .NET runtime. + - ${{ each runtime in parameters.netRuntimes }}: + - task: DotNetCoreCLI@2 + displayName: Test [${{ runtime }}] + inputs: + command: custom + custom: test + projects: $(solution) + arguments: $(buildArguments) --no-build -f ${{ runtime }} + + # Run the tests for each .NET Framework runtime. + - ${{ each runtime in parameters.netFrameworkRuntimes }}: + - task: DotNetCoreCLI@2 + displayName: Test [${{ runtime }}] + inputs: + command: custom + custom: test + projects: $(solution) + arguments: $(buildArguments) --no-build -f ${{ runtime }} diff --git a/eng/pipelines/stages/build-abstractions-package-ci-stage.yml b/eng/pipelines/stages/build-abstractions-package-ci-stage.yml index 5517850296..8e71ffad66 100644 --- a/eng/pipelines/stages/build-abstractions-package-ci-stage.yml +++ b/eng/pipelines/stages/build-abstractions-package-ci-stage.yml @@ -30,13 +30,11 @@ parameters: # The name of the pipeline artifact to publish. - name: artifactName - displayName: Pipeline Artifact Name type: string default: Abstractions.Artifact # The type of build to produce (Release or Debug) - name: buildConfiguration - displayName: Build Configuration type: string default: Release values: @@ -45,31 +43,16 @@ parameters: # The build number of the pipeline. - name: buildNumber - displayName: Build Number type: string default: $(Build.BuildNumber) - # The list of .NET Framework runtimes to test against. - - name: netFrameworkTestRuntimes - displayName: .NET Framework Test Runtimes - type: object - default: [net462, net47, net471, net472, net48, net481] - - # The list of .NET runtimes to test against. - - name: netTestRuntimes - displayName: .NET Test Runtimes - type: object - default: [net8.0, net9.0] - # The version (Major.Minor.Patch) to apply to the package. - name: packageVersion - displayName: Package Version Override type: string default: '' # The verbosity level for the dotnet CLI commands. - name: verbosity - displayName: Dotnet CLI verbosity type: string default: normal values: @@ -84,272 +67,58 @@ stages: - stage: build_abstractions_package_stage displayName: Build Abstractions Package - variables: - - # The directory where dotnet artifacts will be staged. Not to be - # confused with pipeline artifact. - - name: dotnetArtifactsDir - value: $(Build.StagingDirectory)/dotnetArtifacts - - # The directory where the NuGet packages will be staged before being - # published as pipeline artifacts. - - name: dotnetPackagesDir - value: $(Build.StagingDirectory)/dotnetPackages - - # The Abstractions solution file to use for all dotnet CLI commands. - - name: project - value: src/Microsoft.Data.SqlClient.Extensions/Abstractions/Abstractions.slnx - - # dotnet CLI arguments common to all commands. - - name: commonArguments - value: >- - --verbosity ${{ parameters.verbosity }} - --artifacts-path $(dotnetArtifactsDir) - - # dotnet CLI arguments for build/test/pack commands - - name: buildArguments - value: >- - $(commonArguments) - --configuration ${{ parameters.buildConfiguration }} - -p:BuildNumber=$(Build.BuildNumber) - -p:AbstractionsPackageVersion=${{ parameters.packageVersion }} - - # Explicitly unset the $PLATFORM environment variable that is set by the - # 'ADO Build properties' Library in the ADO SqlClientDrivers public - # project. This is defined with a non-standard Platform of 'AnyCPU', - # and will fail the builds if left defined. The Abstractions package does - # not require any specific Platform, and so its solution file doesn't - # support any non-standard platforms. - # - # Note that Azure Pipelines will inject this variable as PLATFORM into - # the environment of all tasks in this job. - # - # See: - # https://learn.microsoft.com/en-us/azure/devops/pipelines/process/variables?view=azure-devops&tabs=yaml%2Cbatch - # - - name: Platform - value: '' - - # Do the same for $CONFIGURATION since we explicitly set it using our - # 'buildConfiguration' parameter, and we don't want the environment to - # override us. - - name: Configuration - value: '' - jobs: # ------------------------------------------------------------------------ # Build and test on Linux. - - job: build_abstractions_package_job_linux - displayName: '[Linux] Build Abstractions Package' - pool: - name: Azure Pipelines + - template: ../jobs/test-abstractions-package-ci-job.yml@self + parameters: + jobNameSuffix: linux + displayNamePrefix: Linux + poolName: Azure Pipelines vmImage: ubuntu-latest - - steps: - - - task: UseDotNet@2 - displayName: Install .NET 9.0 SDK - inputs: - packageType: sdk - version: 9.x - - - task: UseDotNet@2 - displayName: Install .NET 8.0 Runtime - inputs: - packageType: runtime - version: 8.x - - # We use the 'custom' command because the DotNetCoreCLI@2 task doesn't - # support all of our argument combinations for the different build - # steps. - - task: DotNetCoreCLI@2 - displayName: Restore Solution - inputs: - command: custom - custom: restore - projects: $(project) - arguments: $(commonArguments) - - - task: DotNetCoreCLI@2 - displayName: Build Solution - inputs: - command: custom - custom: build - projects: $(project) - arguments: $(buildArguments) --no-restore - - - ${{ each runtime in parameters.netTestRuntimes }}: - - task: DotNetCoreCLI@2 - displayName: Test [${{ runtime }}] - inputs: - command: custom - custom: test - projects: $(project) - arguments: $(buildArguments) --no-build -f ${{ runtime }} + buildConfiguration: ${{ parameters.buildConfiguration }} + netRuntimes: [net8.0, net9.0] + netFrameworkRuntimes: [] # ------------------------------------------------------------------------ - # Build and test on Windows. + # Build and test on Windows - - job: build_abstractions_package_job_windows - displayName: '[Win] Build Abstractions Package' - pool: - name: Azure Pipelines - # The Windows images include a suitable .NET Framework runtime, so we - # don't have to install one explicitly below. + - template: ../jobs/test-abstractions-package-ci-job.yml@self + parameters: + jobNameSuffix: windows + displayNamePrefix: Win + poolName: Azure Pipelines vmImage: windows-latest - - steps: - - - task: UseDotNet@2 - displayName: Install .NET 9.0 SDK - inputs: - packageType: sdk - version: 9.x - - - task: UseDotNet@2 - displayName: Install .NET 8.0 Runtime - inputs: - packageType: runtime - version: 8.x - - - task: DotNetCoreCLI@2 - displayName: Restore Solution - inputs: - command: custom - custom: restore - projects: $(project) - arguments: $(commonArguments) - - - task: DotNetCoreCLI@2 - displayName: Build Solution - inputs: - command: custom - custom: build - projects: $(project) - arguments: $(buildArguments) --no-restore - - - ${{ each runtime in parameters.netTestRuntimes }}: - - task: DotNetCoreCLI@2 - displayName: Test [${{ runtime }}] - inputs: - command: custom - custom: test - projects: $(project) - arguments: $(buildArguments) --no-build -f ${{ runtime }} - - - ${{ each runtime in parameters.netFrameworkTestRuntimes }}: - - task: DotNetCoreCLI@2 - displayName: Test [${{ runtime }}] - inputs: - command: custom - custom: test - projects: $(project) - arguments: $(buildArguments) --no-build -f ${{ runtime }} + buildConfiguration: ${{ parameters.buildConfiguration }} + netRuntimes: [net8.0, net9.0] + netFrameworkRuntimes: [net462, net47, net471, net472, net48, net481] # ------------------------------------------------------------------------ - # Build and test on macOS + # Build and test on macOS. - - job: build_abstractions_package_job_macos - displayName: '[macOS] Build Abstractions Package' - pool: - name: Azure Pipelines + - template: ../jobs/test-abstractions-package-ci-job.yml + parameters: + jobNameSuffix: macos + displayNamePrefix: macOS + poolName: Azure Pipelines vmImage: macos-latest - - steps: - - - task: UseDotNet@2 - displayName: Install .NET 9.0 SDK - inputs: - packageType: sdk - version: 9.x - - - task: UseDotNet@2 - displayName: Install .NET 8.0 Runtime - inputs: - packageType: runtime - version: 8.x - - - task: DotNetCoreCLI@2 - displayName: Restore Solution - inputs: - command: custom - custom: restore - projects: $(project) - arguments: $(commonArguments) - - - task: DotNetCoreCLI@2 - displayName: Build Solution - inputs: - command: custom - custom: build - projects: $(project) - arguments: $(buildArguments) --no-restore - - - ${{ each runtime in parameters.netTestRuntimes }}: - - task: DotNetCoreCLI@2 - displayName: Test [${{ runtime }}] - inputs: - command: custom - custom: test - projects: $(project) - arguments: $(buildArguments) --no-build -f ${{ runtime }} + buildConfiguration: ${{ parameters.buildConfiguration }} + netRuntimes: [net8.0, net9.0] + netFrameworkRuntimes: [] # ------------------------------------------------------------------------ # Create and publish the NuGet package. - - job: publish_abstractions_package_job - displayName: Publish Abstractions Package - dependsOn: - # We depend on all of the build jobs to ensure the tests pass before - # producing the NuGet package. - - build_abstractions_package_job_linux - - build_abstractions_package_job_windows - - build_abstractions_package_job_macos - pool: - name: Azure Pipelines - vmImage: ubuntu-latest - - steps: - - - task: UseDotNet@2 - displayName: Install .NET 9.0 SDK - inputs: - packageType: sdk - version: 9.x - - # There is probably a way to avoid this restore and build, and just - # re-use the dotnet artifacts from a previous build job. Downloading - # the dotnet artifacts didn't work (further investigation TBD), so we - # just build them again. - - task: DotNetCoreCLI@2 - displayName: Restore Solution - inputs: - command: custom - custom: restore - projects: $(project) - arguments: $(commonArguments) - - - task: DotNetCoreCLI@2 - displayName: Build Solution - inputs: - command: custom - custom: build - projects: $(project) - arguments: $(buildArguments) --no-restore - - - task: DotNetCoreCLI@2 - displayName: Create NuGet Package - inputs: - command: custom - custom: pack - projects: $(project) - arguments: $(buildArguments) --no-build -o $(dotnetPackagesDir) - - - task: PublishPipelineArtifact@1 - displayName: Publish Pipeline Artifact - inputs: - targetPath: $(dotnetPackagesDir) - artifactName: ${{ parameters.artifactName }} - publishLocation: pipeline + - template: ../jobs/pack-abstractions-package-ci-job.yml@self + parameters: + artifactName: ${{ parameters.artifactName }} + buildConfiguration: ${{ parameters.buildConfiguration }} + verbosity: ${{ parameters.verbosity }} + dependsOn: + # We depend on all of the test jobs to ensure the tests pass before + # producing the NuGet package. + - test_abstractions_package_job_linux + - test_abstractions_package_job_windows + - test_abstractions_package_job_macos From 66cd30990d1603468d8f86678f93fabe7491d3df Mon Sep 17 00:00:00 2001 From: Paul Medynski <31868385+paulmedynski@users.noreply.github.com> Date: Wed, 17 Sep 2025 15:20:59 -0300 Subject: [PATCH 10/30] User Story 37654: Create Abstractions package - Cleaned up the project vs package pathways. --- .../templates/jobs/ci-build-nugets-job.yml | 28 ++-- .../templates/jobs/ci-run-tests-job.yml | 121 ++++++++++-------- .../templates/stages/ci-run-tests-stage.yml | 53 +++++--- .../templates/steps/build-all-tests-step.yml | 49 +++---- .../templates/steps/ci-prebuild-step.yml | 31 +---- .../templates/steps/ci-project-build-step.yml | 3 +- .../update-nuget-config-local-feed-step.yml | 45 ------- eng/pipelines/dotnet-sqlclient-ci-core.yml | 46 ++++--- ...qlclient-ci-package-reference-pipeline.yml | 4 +- ...qlclient-ci-project-reference-pipeline.yml | 4 +- 10 files changed, 163 insertions(+), 221 deletions(-) diff --git a/eng/pipelines/common/templates/jobs/ci-build-nugets-job.yml b/eng/pipelines/common/templates/jobs/ci-build-nugets-job.yml index bd165dac31..fbb21b81e2 100644 --- a/eng/pipelines/common/templates/jobs/ci-build-nugets-job.yml +++ b/eng/pipelines/common/templates/jobs/ci-build-nugets-job.yml @@ -4,6 +4,13 @@ # See the LICENSE file in the project root for more information. # ################################################################################# parameters: + + - name: referenceType + type: string + values: + - Project + - Package + - name: poolName type: string default: $(ci_var_defaultPoolName) @@ -33,12 +40,11 @@ parameters: default: [] - name: abstractionsPackageVersion - displayName: Abstractions Package Version Override type: string - default: '' jobs: -- job: build_nugets +- job: build_mds_packages_job + displayName: Build MDS Packages pool: name: ${{parameters.poolName }} @@ -53,14 +59,14 @@ jobs: - ${{ if ne(parameters.prebuildSteps, '') }}: - ${{ parameters.prebuildSteps }} # extra steps to run before the build like downloading sni and the required configuration - # Download the Abstractions package artifacts and put them in the packages/ - # directory in the repo root. This is where the MDS NuGet.config file will - # look for local packages. - - task: DownloadPipelineArtifact@2 - displayName: Download Abstractions Package Artifact - inputs: - artifactName: ${{ parameters.abstractionsArtifactName }} - targetPath: $(Build.SourcesDirectory)/packages + # If we're testing in Package mode, download the Abstractions package + # artifacts and put them in the packages/ directory in the repo root. + - ${{ if eq(parameters.referenceType, 'Package') }}: + - task: DownloadPipelineArtifact@2 + displayName: Download Abstractions Package Artifact + inputs: + artifactName: ${{ parameters.abstractionsArtifactName }} + targetPath: $(Build.SourcesDirectory)/packages - template: ../steps/ci-project-build-step.yml@self parameters: diff --git a/eng/pipelines/common/templates/jobs/ci-run-tests-job.yml b/eng/pipelines/common/templates/jobs/ci-run-tests-job.yml index 20cf0cd33d..20b39095b5 100644 --- a/eng/pipelines/common/templates/jobs/ci-run-tests-job.yml +++ b/eng/pipelines/common/templates/jobs/ci-run-tests-job.yml @@ -4,12 +4,37 @@ # See the LICENSE file in the project root for more information. # ################################################################################# parameters: + - name: abstractionsArtifactName + type: string + + - name: abstractionsPackageVersion + type: string + + - name: referenceType + type: string + values: + - Project + - Package + + - name: configProperties + type: object + default: {} # - key: 'value' + + - name: configSqlFor + type: string # local, azure, or enclave + default: local + - name: debug type: boolean default: false - - name: poolName - type: string + - name: enableX64Test + type: boolean + default: true + + - name: enableX86Test + type: boolean + default: false - name: hostedPool type: boolean @@ -21,68 +46,45 @@ parameters: - name: jobDisplayName type: string - - name: usemanagedSNI - type: boolean - default: false - - - name: configProperties - type: object - default: {} # - key: 'value' - - - name: abstractionsPackageVersion - displayName: Abstractions Package Version Override + - name: mdsArtifactName type: string - default: '' - - - name: prebuildSteps - type: stepList - default: [] - - name: abstractionsArtifactName + - name: mdsPackageVersion type: string - default: Abstractions.Artifact - - name: targetFramework + - name: netcoreVersionTestUtils type: string + + - name: operatingSystem + type: string + default: '' - - name: netcoreVersionTestUtils + - name: poolName type: string - - name: enableX86Test + - name: prebuildSteps + type: stepList + default: [] + + - name: publishTestResults type: boolean default: false - - name: enableX64Test - type: boolean - default: true + - name: targetFramework + type: string - name: testSet type: string - - name: publishTestResults - type: boolean - default: false - - - name: configSqlFor - type: string # local, azure, or enclave - default: local - - - name: operatingSystem - type: string - default: '' - - - name: buildType - displayName: 'Build Type' - default: Project - values: - - Project - - Package - # The timeout, in minutes, for this job. - name: timeout type: string default: 90 + - name: usemanagedSNI + type: boolean + default: false + jobs: - job: ${{ format('{0}', coalesce(parameters.jobDisplayName, parameters.image, 'unknown_image')) }} @@ -104,14 +106,20 @@ jobs: steps: - # Download the Abstractions package artifacts and put them in the packages/ - # directory in the repo root. This is where the MDS NuGet.config file will - # look for local packages. - - task: DownloadPipelineArtifact@2 - displayName: Download Abstractions Package Artifact - inputs: - artifactName: ${{ parameters.abstractionsArtifactName }} - targetPath: $(Build.SourcesDirectory)/packages + # If we're testing in Package mode, download the Abstractions and MDS package + # artifacts and put them in the packages/ directory in the repo root. + - ${{ if eq(parameters.referenceType, 'Package') }}: + - task: DownloadPipelineArtifact@2 + displayName: Download Abstractions Package Artifact + inputs: + artifactName: ${{ parameters.abstractionsArtifactName }} + targetPath: $(Build.SourcesDirectory)/packages + + - task: DownloadPipelineArtifact@2 + displayName: Download MDS Package Artifact + inputs: + artifactName: ${{ parameters.mdsArtifactName }} + targetPath: $(Build.SourcesDirectory)/packages - ${{ if ne(parameters.prebuildSteps, '') }}: - ${{ parameters.prebuildSteps }} # extra steps to run before the build like downloading sni and the required configuration @@ -242,9 +250,10 @@ jobs: - template: ../steps/build-all-tests-step.yml@self # build tests parameters: targetFramework: ${{ parameters.targetFramework }} - referenceType: ${{ parameters.buildType }} + referenceType: ${{ parameters.referenceType }} testSet: ${{ parameters.testSet }} abstractionsPackageVersion: ${{ parameters.abstractionsPackageVersion }} + mdsPackageVersion: ${{ parameters.mdsPackageVersion }} ${{ if ne(parameters.operatingSystem, 'Windows') }}: OSGroup: Unix @@ -253,7 +262,7 @@ jobs: parameters: debug: ${{ parameters.debug }} targetFramework: ${{ parameters.targetFramework }} - referenceType: ${{ parameters.buildType }} + referenceType: ${{ parameters.referenceType }} testSet: ${{ parameters.testSet }} operatingSystem: ${{ parameters.operatingSystem }} @@ -295,13 +304,13 @@ jobs: parameters: debug: ${{ parameters.debug }} targetFramework: ${{ parameters.targetFramework }} - referenceType: ${{ parameters.buildType }} + referenceType: ${{ parameters.referenceType }} testSet: ${{ parameters.testSet }} msbuildArchitecture: x86 dotnetx86RootPath: $(dotnetx86RootPath) operatingSystem: ${{ parameters.operatingSystem }} - - ${{ if and(eq(parameters.publishTestResults, true), eq(parameters.buildType, 'Project')) }}: # publish test results if build type is project + - ${{ if and(eq(parameters.publishTestResults, true), eq(parameters.referenceType, 'Project')) }}: # publish test results if build type is project - template: ../steps/publish-test-results-step.yml@self parameters: debug: ${{ parameters.debug }} diff --git a/eng/pipelines/common/templates/stages/ci-run-tests-stage.yml b/eng/pipelines/common/templates/stages/ci-run-tests-stage.yml index da73ca4eb2..994bb4f345 100644 --- a/eng/pipelines/common/templates/stages/ci-run-tests-stage.yml +++ b/eng/pipelines/common/templates/stages/ci-run-tests-stage.yml @@ -4,37 +4,44 @@ # See the LICENSE file in the project root for more information. # ################################################################################# parameters: + - name: abstractionsArtifactName + type: string + + - name: abstractionsPackageVersion + type: string + + - name: referenceType + default: Project + values: + - Project + - Package + - name: debug type: boolean default: false - - name: testConfigurations - type: object - - name: dependsOn type: object default: [] - - name: buildType - displayName: 'Build Type' - default: Project - values: - - Project - - Package - - - name: abstractionsPackageVersion - displayName: Abstractions Package Version Override + - name: mdsArtifactName type: string - default: '' + default: MDS.Artifact - - name: prebuildSteps - type: stepList - default: [] + - name: mdsPackageVersion + type: string - name: postTestJobs type: jobList default: [] + - name: prebuildSteps + type: stepList + default: [] + + - name: testConfigurations + type: object + # The timeout, in minutes, for each test job. - name: testsTimeout type: string @@ -53,14 +60,17 @@ stages: - template: ../jobs/ci-run-tests-job.yml@self parameters: debug: ${{ parameters.debug }} - buildType: ${{ parameters.buildType }} + referenceType: ${{ parameters.referenceType }} timeout: ${{ parameters.testsTimeout }} poolName: ${{ config.value.pool }} hostedPool: ${{ eq(config.value.hostedPool, true) }} image: ${{ image.value }} jobDisplayName: ${{ format('{0}_{1}_{2}', replace(targetFramework, '.', '_'), platform, testSet) }} configProperties: ${{ config.value.configProperties }} - abstractionsPackageVersion: ${{ parameters.abstractionsPackageVersion }} + abstractionsArtifactName: ${{ parameters.abstractionsArtifactName }} + abstractionsPackageVersion: ${{parameters.abstractionsPackageVersion}} + mdsArtifactName: ${{ parameters.mdsArtifactName }} + mdsPackageVersion: ${{ parameters.mdsPackageVersion }} prebuildSteps: ${{ parameters.prebuildSteps }} targetFramework: ${{ targetFramework }} netcoreVersionTestUtils: ${{config.value.netcoreVersionTestUtils }} @@ -80,7 +90,7 @@ stages: - template: ../jobs/ci-run-tests-job.yml@self parameters: debug: ${{ parameters.debug }} - buildType: ${{ parameters.buildType }} + referenceType: ${{ parameters.referenceType }} timeout: ${{ parameters.testsTimeout }} poolName: ${{ config.value.pool }} hostedPool: ${{ eq(config.value.hostedPool, true) }} @@ -91,7 +101,10 @@ stages: jobDisplayName: ${{ format('{0}_{1}_{2}_{3}', replace(targetFramework, '.', '_'), platform, 'NativeSNI', testSet) }} configProperties: ${{ config.value.configProperties }} useManagedSNI: ${{ useManagedSNI }} - abstractionsPackageVersion: ${{ parameters.abstractionsPackageVersion }} + abstractionsArtifactName: ${{ parameters.abstractionsArtifactName }} + abstractionsPackageVersion: ${{parameters.abstractionsPackageVersion}} + mdsArtifactName: ${{ parameters.mdsArtifactName }} + mdsPackageVersion: ${{ parameters.mdsPackageVersion }} prebuildSteps: ${{ parameters.prebuildSteps }} targetFramework: ${{ targetFramework }} netcoreVersionTestUtils: ${{config.value.netcoreVersionTestUtils }} diff --git a/eng/pipelines/common/templates/steps/build-all-tests-step.yml b/eng/pipelines/common/templates/steps/build-all-tests-step.yml index a953d832d5..2742376c1f 100644 --- a/eng/pipelines/common/templates/steps/build-all-tests-step.yml +++ b/eng/pipelines/common/templates/steps/build-all-tests-step.yml @@ -4,38 +4,35 @@ # See the LICENSE file in the project root for more information. # ################################################################################# parameters: - - name: targetFramework + - name: abstractionsPackageVersion type: string + + - name: configuration + type: string + default: '$(Configuration)' - - name: nugetPackageVersion + - name: mdsPackageVersion type: string - default: $(NugetPackageVersion) + + - name: osGroup + type: string + default: '' - name: platform type: string default: $(Platform) - - - name: configuration - type: string - default: '$(Configuration)' - name: referenceType - default: Package + type: string values: - Project - Package - - - name: OSGroup - type: string - default: '' - - name: testSet + - name: targetFramework type: string - - - name: abstractionsPackageVersion - displayName: Abstractions Package Version Override + + - name: testSet type: string - default: '' steps: - ${{ if contains(parameters.targetFramework, 'net4') }}: # .NET Framework @@ -45,26 +42,16 @@ steps: solution: build.proj platform: '${{parameters.platform }}' configuration: '${{parameters.configuration }}' - msbuildArguments: '-t:BuildTestsNetFx -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.nugetPackageVersion }} -p:AbstractionsPackageVersion=${{ parameters.abstractionsPackageVersion }}.$(Build.BuildNumber)' - -# - ${{else if contains(parameters.targetFramework, 'netstandard')}}: # .NET Standard -# - task: MSBuild@1 -# displayName: 'Build Tests NetStandard' -# inputs: -# solution: build.proj -# platform: '${{parameters.platform }}' -# configuration: '${{parameters.configuration }}' -# msbuildArguments: '-t:BuildTestsNetCore -p:ReferenceType=NetStandard -p:TargetNetStandardVersion=${{parameters.targetNetStandardVersion }} -p:TF=${{parameters.targetFramework }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.nugetPackageVersion }}' -# condition: and(succeeded(), not(startsWith(variables['TF'], 'net4')), startsWith(variables['TargetNetStandardVersion'], 'netstandard')) + msbuildArguments: '-t:BuildTestsNetFx -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }} -p:AbstractionsPackageVersion=${{ parameters.abstractionsPackageVersion }}.$(Build.BuildNumber)' -- ${{elseif eq(parameters.OSGroup, '')}}: # .NET on Windows +- ${{elseif eq(parameters.osGroup, '')}}: # .NET on Windows - task: MSBuild@1 displayName: 'Build Tests NetCore [Win]' inputs: solution: build.proj platform: '${{parameters.platform }}' configuration: '${{parameters.configuration }}' - msbuildArguments: '-t:BuildTestsNetCore -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.nugetPackageVersion }} -p:AbstractionsPackageVersion=${{ parameters.abstractionsPackageVersion }}.$(Build.BuildNumber)' + msbuildArguments: '-t:BuildTestsNetCore -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }} -p:AbstractionsPackageVersion=${{ parameters.abstractionsPackageVersion }}.$(Build.BuildNumber)' condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT')) - ${{ else }}: # .NET on Unix @@ -74,7 +61,7 @@ steps: command: custom projects: build.proj custom: msbuild - arguments: '-t:BuildTestsNetCore -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.nugetPackageVersion }} -p:OSGroup=${{parameters.OSGroup }} -p:platform=${{parameters.platform }} -p:Configuration=${{parameters.configuration }} -p:AbstractionsPackageVersion=${{ parameters.abstractionsPackageVersion }}.$(Build.BuildNumber)' + arguments: '-t:BuildTestsNetCore -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }} -p:OSGroup=${{parameters.osGroup }} -p:platform=${{parameters.platform }} -p:Configuration=${{parameters.configuration }} -p:AbstractionsPackageVersion=${{ parameters.abstractionsPackageVersion }}.$(Build.BuildNumber)' verbosityRestore: Detailed verbosityPack: Detailed condition: and(succeeded(), ne(variables['Agent.OS'], 'Windows_NT')) diff --git a/eng/pipelines/common/templates/steps/ci-prebuild-step.yml b/eng/pipelines/common/templates/steps/ci-prebuild-step.yml index 48cab965ea..4eedd5dfd4 100644 --- a/eng/pipelines/common/templates/steps/ci-prebuild-step.yml +++ b/eng/pipelines/common/templates/steps/ci-prebuild-step.yml @@ -8,22 +8,12 @@ parameters: type: boolean default: false - - name: artifactName + - name: referenceType type: string - default: Artifacts - - - name: buildType - displayName: 'Build Type' - default: Project values: - Project - Package - - name: abstractionsPackageVersion - displayName: Abstractions Package Version Override - type: string - default: '' - steps: - template: ensure-dotnet-version.yml parameters: @@ -42,23 +32,8 @@ steps: Get-ChildItem env: | Sort-Object Name displayName: 'List Environment Variables [debug]' -- ${{if eq(parameters.buildType, 'Package')}}: - - task: DownloadPipelineArtifact@2 - displayName: 'Download NuGet Package' - inputs: - buildType: current - artifact: ${{parameters.artifactName }} - patterns: '**/*.nupkg' - targetPath: $(Pipeline.Workspace)/${{parameters.artifactName }} - +- ${{if eq(parameters.referenceType, 'Package')}}: - template: update-nuget-config-local-feed-step.yml@self parameters: - downloadedNugetPath: $(Pipeline.Workspace)\${{parameters.artifactName }} + downloadedNugetPath: $(Build.SourcesDirectory)/packages debug: ${{ parameters.debug }} - abstractionsPackageVersion: ${{ parameters.abstractionsPackageVersion }} - -- ${{ else }}: # project - - template: ci-project-build-step.yml@self - parameters: - build: allNoDocs - abstractionsPackageVersion: ${{parameters.abstractionsPackageVersion}} diff --git a/eng/pipelines/common/templates/steps/ci-project-build-step.yml b/eng/pipelines/common/templates/steps/ci-project-build-step.yml index 1edcdb1b51..fa6779616e 100644 --- a/eng/pipelines/common/templates/steps/ci-project-build-step.yml +++ b/eng/pipelines/common/templates/steps/ci-project-build-step.yml @@ -35,9 +35,8 @@ parameters: - allNoDocs - name: abstractionsPackageVersion - displayName: Abstractions Package Version Override + displayName: Abstractions Package Version type: string - default: '' steps: - template: ./ensure-dotnet-version.yml@self diff --git a/eng/pipelines/common/templates/steps/update-nuget-config-local-feed-step.yml b/eng/pipelines/common/templates/steps/update-nuget-config-local-feed-step.yml index 6753a14b48..f7bf252ebe 100644 --- a/eng/pipelines/common/templates/steps/update-nuget-config-local-feed-step.yml +++ b/eng/pipelines/common/templates/steps/update-nuget-config-local-feed-step.yml @@ -11,15 +11,6 @@ parameters: - name: downloadedNugetPath # path to the downloaded nuget files type: string - - name: abstractionsPackageVersion - displayName: Abstractions Package Version Override - type: string - default: '' - - - name: nugetPackageVersion - type: string - default: $(NugetPackageVersion) - steps: - powershell: | # Get a list of package sources available @@ -50,39 +41,3 @@ steps: # Display the content of the NuGet.config file Get-Content -Path "NuGet.config" displayName: 'Read NuGet.config [debug]' - -- task: DotNetCoreCLI@2 - displayName: 'Restore NuGets' - inputs: - command: 'custom' - custom: 'msbuild' - arguments: 'build.proj -t:restore -p:AbstractionsPackageVersion=${{parameters.abstractionsPackageVersion}}.$(buildNumber)' - feedsToUse: 'select' - -- powershell: | - $Doc = [xml](Get-Content "./Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider.csproj") - $parent_xpath = '/Project/ItemGroup/ProjectReference' - $node = $Doc.SelectSingleNode($parent_xpath) - $parentNode = $node.ParentNode - while($node -ne $null) { - $node.ParentNode.RemoveChild($node) - $node = $Doc.SelectSingleNode($parent_xpath) - } - - $parent_xpath = '/Project/ItemGroup/PackageReference[@Include="Microsoft.Data.SqlClient"]' - $node = $Doc.SelectSingleNode($parent_xpath) - - if($node -eq $null){ - $packagerefnode = $doc.createelement("packagereference") - $value = $doc.selectsinglenode('/project/itemgroup/projectreference') - $attrinclude = $doc.createattribute("include") - $attrinclude.value = "microsoft.data.sqlclient" - $packagerefnode.attributes.append($attrinclude) - $parentNode.AppendChild($packageRefNode) - } - - $currentFolder = Get-Location - $filePath = Join-Path $currentFolder "Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider.csproj" - $Doc.Save($filePath) - workingDirectory: 'src/Microsoft.Data.SqlClient/add-ons/AzureKeyVaultProvider' - displayName: 'Update AKV Project Ref to Package Ref (.NET Framework/Core)' diff --git a/eng/pipelines/dotnet-sqlclient-ci-core.yml b/eng/pipelines/dotnet-sqlclient-ci-core.yml index 903f39d17d..0a54fc894e 100644 --- a/eng/pipelines/dotnet-sqlclient-ci-core.yml +++ b/eng/pipelines/dotnet-sqlclient-ci-core.yml @@ -63,9 +63,12 @@ parameters: type: object default: [net462, net8.0] -- name: buildType - displayName: 'Build Type' - default: Project +# The way we will reference sibling projects in the .csproj files: +# Project - use references. +# Package - use references to NuGet packages in the +# packages/ directory. +- name: referenceType + displayName: 'Reference Type' values: - Project - Package @@ -122,13 +125,14 @@ stages: # When building MDS via packages, we must depend on the Abstractions # package. - ${{ if eq(parameters.buildType, 'Package') }}: + ${{ if eq(parameters.referenceType, 'Package') }}: dependsOn: - build_abstractions_package_stage jobs: - template: common/templates/jobs/ci-build-nugets-job.yml@self parameters: + referenceType: ${{ parameters.referenceType }} configuration: ${{ parameters.buildConfiguration }} abstractionsPackageVersion: ${{parameters.abstractionsPackageVersion}} abstractionsArtifactName: $(abstractionsArtifactName) @@ -144,7 +148,7 @@ stages: - template: stages/stress-tests-ci-stage.yml@self parameters: buildConfiguration: ${{ parameters.buildConfiguration }} - dependsOn: [build_nugets] + dependsOn: [build_mds_packages_job] pipelineArtifactName: $(artifactName) mdsPackageVersion: $(NugetPackageVersion) ${{ if eq(parameters.debug, 'true') }}: @@ -153,39 +157,33 @@ stages: - template: common/templates/stages/ci-run-tests-stage.yml@self parameters: debug: ${{ parameters.debug }} - buildType: ${{ parameters.buildType }} + referenceType: ${{ parameters.referenceType }} testsTimeout: ${{ parameters.testsTimeout }} + abstractionsArtifactName: $(abstractionsArtifactName) abstractionsPackageVersion: ${{parameters.abstractionsPackageVersion}} + mdsArtifactName: $(mdsArtifactName) + mdsPackageVersion: $(NugetPackageVersion) # When testing MDS via packages, we must depend on the Abstractions and # MDS packages. - ${{ if eq(parameters.buildType, 'Package') }}: + ${{ if eq(parameters.referenceType, 'Package') }}: dependsOn: - build_abstractions_package_stage - build_nugets - ${{if ne(parameters.SNIVersion, '')}}: - prebuildSteps: # steps to run prior to building and running tests on each job + prebuildSteps: # steps to run prior to building and running tests on each job + - ${{if ne(parameters.SNIVersion, '')}}: - template: common/templates/steps/override-sni-version.yml@self parameters: SNIVersion: ${{parameters.SNIVersion}} SNIValidationFeed: ${{parameters.SNIValidationFeed}} - - template: common/templates/steps/ci-prebuild-step.yml@self - parameters: - debug: ${{ parameters.debug }} - artifactName: $(mdsArtifactName) - buildType: ${{ parameters.buildType }} - abstractionsPackageVersion: ${{parameters.abstractionsPackageVersion}} - ${{else}}: - prebuildSteps: # steps to run prior to building and running tests on each job - - template: common/templates/steps/ci-prebuild-step.yml@self - parameters: - debug: ${{ parameters.debug }} - artifactName: $(mdsArtifactName) - buildType: ${{ parameters.buildType }} - abstractionsPackageVersion: ${{parameters.abstractionsPackageVersion}} - ${{ if eq(parameters.buildType, 'Project') }}: # only run the code coverage job if the build type is project + - template: common/templates/steps/ci-prebuild-step.yml@self + parameters: + debug: ${{ parameters.debug }} + referenceType: ${{ parameters.referenceType }} + + ${{ if eq(parameters.referenceType, 'Project') }}: # only run the code coverage job if the build type is project postTestJobs: # jobs to run after the tests are done - template: common/templates/jobs/ci-code-coverage-job.yml@self parameters: diff --git a/eng/pipelines/dotnet-sqlclient-ci-package-reference-pipeline.yml b/eng/pipelines/dotnet-sqlclient-ci-package-reference-pipeline.yml index e6da796d05..1ca58a910d 100644 --- a/eng/pipelines/dotnet-sqlclient-ci-package-reference-pipeline.yml +++ b/eng/pipelines/dotnet-sqlclient-ci-package-reference-pipeline.yml @@ -63,7 +63,7 @@ parameters: # parameters are shown up in ADO UI in a build queue time default: [1, 2, 3] - name: abstractionsPackageVersion - displayName: Abstractions Package Version Override + displayName: Abstractions Package Version type: string default: 1.0.0 @@ -108,7 +108,7 @@ extends: abstractionsPackageVersion: ${{ parameters.abstractionsPackageVersion }} useManagedSNI: ${{ parameters.useManagedSNI }} codeCovTargetFrameworks: ${{ parameters.codeCovTargetFrameworks }} - buildType: Package + referenceType: Package buildConfiguration: ${{ parameters.buildConfiguration }} enableStressTests: ${{ parameters.enableStressTests }} testsTimeout: ${{ parameters.testsTimeout }} diff --git a/eng/pipelines/dotnet-sqlclient-ci-project-reference-pipeline.yml b/eng/pipelines/dotnet-sqlclient-ci-project-reference-pipeline.yml index ba17cf1fa5..1217339c97 100644 --- a/eng/pipelines/dotnet-sqlclient-ci-project-reference-pipeline.yml +++ b/eng/pipelines/dotnet-sqlclient-ci-project-reference-pipeline.yml @@ -55,7 +55,7 @@ parameters: # parameters are shown up in ADO UI in a build queue time default: [1, 2, 3] - name: abstractionsPackageVersion - displayName: Abstractions Package Version Override + displayName: Abstractions Package Version type: string default: 1.0.0 @@ -100,7 +100,7 @@ extends: abstractionsPackageVersion: ${{ parameters.abstractionsPackageVersion }} useManagedSNI: ${{ parameters.useManagedSNI }} codeCovTargetFrameworks: ${{ parameters.codeCovTargetFrameworks }} - buildType: Project + referenceType: Project buildConfiguration: ${{ parameters.buildConfiguration }} enableStressTests: ${{ parameters.enableStressTests }} testsTimeout: ${{ parameters.testsTimeout }} From e472245d0d6c6f9e2fb27bf8615d57f5dbb0d731 Mon Sep 17 00:00:00 2001 From: Benjamin Russell Date: Wed, 17 Sep 2025 18:07:36 -0500 Subject: [PATCH 11/30] Merge | SqlCommand Public Properties (#3611) * Merge: * _parameters * _pendingCancel * _preparedConnectionCloseCount * _preparedConnectionReconnectCount * _prepareHandle * s_cachedInvalidPrepareHandle * Statistics * Merge Connection, DbConnection * Merging RetryLogicProvider and _retryLogicProvider # Conflicts: # src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlCommand.cs * Merge Transaction, DbTransaction * Merge CommandText * Replace "" with string.Empty * Merge CommandTimeout, _commandTimeout, and ADP.InvalidCommandTimeout * Merge CommandType * Removed temp storage of _commandType * Merge ColumnEncryptionSetting, _columnEncryptionSetting * Merge Parameters and DbParameterCollection * Merging DesignTimeVisible, _designTimeVisible * Merging EnableOptimizedParameterBinding, UpdatedRowSource, _updatedRowSource * Merge StatementCompleted and _statementCompletedEventHandler * Merging Notification, NotificationAutoEnlist, _notification, _notificationAutoEnlist, _sqlDep * Merge DefaultCommandTimeout, InternalTdsConnection, IsColumnEncryptionEnabled, InternalRecordsAffected, _rowsAffected, PropertyChanging() * merge _transaction and _batchRPCMode * Restore ResetCommandTimeout that got accidentally obliterated in a previous commit * Fix logic issue in IsColumnEncryptionEnabled, reinstate TypeDescriptor.Refresh on netfx --- .../Data/SqlClient/SqlCommand.netcore.cs | 447 +-------------- .../Data/SqlClient/SqlCommand.netfx.cs | 465 +-------------- .../src/Microsoft/Data/Common/AdapterUtil.cs | 17 +- .../Microsoft/Data/SqlClient/SqlCommand.cs | 541 +++++++++++++++++- 4 files changed, 540 insertions(+), 930 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlCommand.netcore.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlCommand.netcore.cs index d43b71ff32..5fd97e3b13 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlCommand.netcore.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlCommand.netcore.cs @@ -107,24 +107,11 @@ protected override void AfterCleared(SqlCommand owner) } } - private int? _commandTimeout; - private UpdateRowSource _updatedRowSource = UpdateRowSource.Both; - private bool _designTimeInvisible; - /// /// Indicates if the column encryption setting was set at-least once in the batch rpc mode, when using AddBatchCommand. /// private bool _wasBatchModeColumnEncryptionSettingSetOnce; - /// - /// Column Encryption Override. Defaults to SqlConnectionSetting, in which case - /// it will be Enabled if SqlConnectionOptions.IsColumnEncryptionSettingEnabled = true, Disabled if false. - /// This may also be used to set other behavior which overrides connection level setting. - /// - private SqlCommandColumnEncryptionSetting _columnEncryptionSetting = SqlCommandColumnEncryptionSetting.UseConnectionSetting; - - internal SqlDependency _sqlDep; - #if DEBUG /// /// Force the client to sleep during sp_describe_parameter_encryption in the function TryFetchInputParameterEncryptionInfo. @@ -157,10 +144,6 @@ protected override void AfterCleared(SqlCommand owner) internal static readonly Action s_cancelIgnoreFailure = CancelIgnoreFailureCallback; - private int _preparedConnectionCloseCount = -1; - private int _preparedConnectionReconnectCount = -1; - - private SqlParameterCollection _parameters; private _SqlRPC[] _rpcArrayOf1 = null; // Used for RPC executes private _SqlRPC _rpcForEncryption = null; // Used for sp_describe_parameter_encryption RPC executes @@ -192,23 +175,6 @@ private bool ShouldCacheEncryptionMetadata internal static int DebugForceAsyncWriteDelay { get; set; } #endif - /// - /// Return if column encryption setting is enabled. - /// The order in the below if is important since _activeConnection.Parser can throw if the - /// underlying tds connection is closed and we don't want to change the behavior for folks - /// not trying to use transparent parameter encryption i.e. who don't use (SqlCommandColumnEncryptionSetting.Enabled or _activeConnection.IsColumnEncryptionSettingEnabled) here. - /// - internal bool IsColumnEncryptionEnabled - { - get - { - return (_columnEncryptionSetting == SqlCommandColumnEncryptionSetting.Enabled - || (_columnEncryptionSetting == SqlCommandColumnEncryptionSetting.UseConnectionSetting && _activeConnection.IsColumnEncryptionSettingEnabled)) - && _activeConnection.Parser != null - && _activeConnection.Parser.IsColumnEncryptionSupported; - } - } - internal bool ShouldUseEnclaveBasedWorkflow => (!string.IsNullOrWhiteSpace(_activeConnection.EnclaveAttestationUrl) || Connection.AttestationProtocol == SqlConnectionAttestationProtocol.None) && IsColumnEncryptionEnabled; @@ -324,33 +290,13 @@ private AsyncState CachedAsyncState } } - // sql reader will pull this value out for each NextResult call. It is not cumulative - // _rowsAffected is cumulative for ExecuteNonQuery across all rpc batches - internal int _rowsAffected = -1; // rows affected by the command - // number of rows affected by sp_describe_parameter_encryption. // The below line is used only for debug asserts and not exposed publicly or impacts functionality otherwise. private int _rowsAffectedBySpDescribeParameterEncryption = -1; - - private SqlNotificationRequest _notification; - - // transaction support - private SqlTransaction _transaction; - - private StatementCompletedEventHandler _statementCompletedEventHandler; - - // Volatile bool used to synchronize with cancel thread the state change of an executing - // command going from pre-processing to obtaining a stateObject. The cancel synchronization - // we require in the command is only from entering an Execute* API to obtaining a - // stateObj. Once a stateObj is successfully obtained, cancel synchronization is handled - // by the stateObject. - private volatile bool _pendingCancel; - - private bool _batchRPCMode; + private List<_SqlRPC> _RPCList; private _SqlRPC[] _sqlRPCParameterEncryptionReqArray; private int _currentlyExecutingBatch; - private SqlRetryLogicBaseProvider _retryLogicProvider; /// /// This variable is used to keep track of which RPC batch's results are being read when reading the results of @@ -428,238 +374,8 @@ private SqlCommand(SqlCommand from) : this() } } - /// - [DefaultValue(null)] - [ResCategory(StringsHelper.ResourceNames.DataCategory_Data)] - [ResDescription(StringsHelper.ResourceNames.DbCommand_Connection)] - new public SqlConnection Connection - { - get - { - return _activeConnection; - } - set - { - // Don't allow the connection to be changed while in an async operation. - if (_activeConnection != value && _activeConnection != null) - { - // If new value... - if (CachedAsyncState != null && CachedAsyncState.PendingAsyncOperation) - { - // If in pending async state, throw. - throw SQL.CannotModifyPropertyAsyncOperationInProgress(); - } - } - - // Check to see if the currently set transaction has completed. If so, - // null out our local reference. - if (_transaction != null && _transaction.Connection == null) - { - _transaction = null; - } - - // Command is no longer prepared on new connection, cleanup prepare status - if (IsPrepared) - { - if (_activeConnection != value && _activeConnection != null) - { - try - { - // cleanup - Unprepare(); - } - catch (Exception) - { - // we do not really care about errors in unprepare (may be the old connection went bad) - } - finally - { - // clean prepare status (even successful Unprepare does not do that) - _prepareHandle = s_cachedInvalidPrepareHandle; - _execType = EXECTYPE.UNPREPARED; - } - } - } - _activeConnection = value; - SqlClientEventSource.Log.TryTraceEvent("SqlCommand.Set_Connection | API | ObjectId {0}, Client Connection Id {1}", ObjectID, value?.ClientConnectionId); - } - } - - /// - protected override DbConnection DbConnection - { - get - { - return Connection; - } - set - { - Connection = (SqlConnection)value; - } - } - - private SqlInternalConnectionTds InternalTdsConnection - { - get - { - return (SqlInternalConnectionTds)_activeConnection.InnerConnection; - } - } - private bool IsProviderRetriable => SqlConfigurableRetryFactory.IsRetriable(RetryLogicProvider); - /// - [Browsable(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public SqlRetryLogicBaseProvider RetryLogicProvider - { - get - { - if (_retryLogicProvider == null) - { - _retryLogicProvider = SqlConfigurableRetryLogicManager.CommandProvider; - } - return _retryLogicProvider; - } - set - { - _retryLogicProvider = value; - } - } - - /// - [Browsable(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] // MDAC 90471 - [ResCategory(StringsHelper.ResourceNames.DataCategory_Notification)] - [ResDescription(StringsHelper.ResourceNames.SqlCommand_Notification)] - public SqlNotificationRequest Notification - { - get - { - return _notification; - } - set - { - _sqlDep = null; - _notification = value; - SqlClientEventSource.Log.TryTraceEvent("SqlCommand.Set_Notification | API | Object Id {0}", ObjectID); - } - } - - internal SqlStatistics Statistics - { - get - { - if (_activeConnection != null) - { - if (_activeConnection.StatisticsEnabled || - s_diagnosticListener.IsEnabled(SqlClientCommandAfter.Name)) - { - return _activeConnection.Statistics; - } - } - return null; - } - } - - /// - [Browsable(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - [ResDescription(StringsHelper.ResourceNames.DbCommand_Transaction)] - new public SqlTransaction Transaction - { - get - { - // if the transaction object has been zombied, just return null - if (_transaction != null && _transaction.Connection == null) - { - _transaction = null; - } - return _transaction; - } - set - { - // Don't allow the transaction to be changed while in an async operation. - if (_transaction != value && _activeConnection != null) - { - // If new value... - if (CachedAsyncState.PendingAsyncOperation) - { - // If in pending async state, throw - throw SQL.CannotModifyPropertyAsyncOperationInProgress(); - } - } - _transaction = value; - SqlClientEventSource.Log.TryTraceEvent("SqlCommand.Set_Transaction | API | Object Id {0}, Internal Transaction Id {1}, Client Connection Id {2}", ObjectID, value?.InternalTransaction?.TransactionId, Connection?.ClientConnectionId); - } - } - - /// - protected override DbTransaction DbTransaction - { - get - { - return Transaction; - } - set - { - Transaction = (SqlTransaction)value; - SqlClientEventSource.Log.TryTraceEvent("SqlCommand.Set_DbTransaction | API | Object Id {0}, Client Connection Id {1}", ObjectID, Connection?.ClientConnectionId); - } - } - - /// - [DefaultValue("")] - [RefreshProperties(RefreshProperties.All)] // MDAC 67707 - [ResCategory(StringsHelper.ResourceNames.DataCategory_Data)] - [ResDescription(StringsHelper.ResourceNames.DbCommand_CommandText)] - public override string CommandText - { - get => _commandText ?? ""; - set - { - if (_commandText != value) - { - PropertyChanging(); - _commandText = value; - } - SqlClientEventSource.Log.TryTraceEvent("SqlCommand.Set_CommandText | API | Object Id {0}, String Value = '{1}', Client Connection Id {2}", ObjectID, value, Connection?.ClientConnectionId); - } - } - - /// - [Browsable(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - [ResCategory(StringsHelper.ResourceNames.DataCategory_Data)] - [ResDescription(StringsHelper.ResourceNames.TCE_SqlCommand_ColumnEncryptionSetting)] - public SqlCommandColumnEncryptionSetting ColumnEncryptionSetting => _columnEncryptionSetting; - - /// - [ResCategory(StringsHelper.ResourceNames.DataCategory_Data)] - [ResDescription(StringsHelper.ResourceNames.DbCommand_CommandTimeout)] - public override int CommandTimeout - { - get - { - return _commandTimeout ?? DefaultCommandTimeout; - } - set - { - if (value < 0) - { - throw ADP.InvalidCommandTimeout(value); - } - - if (value != _commandTimeout) - { - PropertyChanging(); - _commandTimeout = value; - } - - SqlClientEventSource.Log.TryTraceEvent("SqlCommand.Set_CommandTimeout | API | ObjectId {0}, Command Timeout value {1}, Client Connection Id {2}", ObjectID, value, Connection?.ClientConnectionId); - } - } - /// public void ResetCommandTimeout() { @@ -670,142 +386,6 @@ public void ResetCommandTimeout() } } - private int DefaultCommandTimeout - { - get - { - return _activeConnection?.CommandTimeout ?? ADP.DefaultCommandTimeout; - } - } - - /// - [DefaultValue(CommandType.Text)] - [RefreshProperties(RefreshProperties.All)] - [ResCategory(StringsHelper.ResourceNames.DataCategory_Data)] - [ResDescription(StringsHelper.ResourceNames.DbCommand_CommandType)] - public override CommandType CommandType - { - get - { - CommandType cmdType = _commandType; - return ((0 != cmdType) ? cmdType : CommandType.Text); - } - set - { - if (_commandType != value) - { - switch (value) - { - case CommandType.Text: - case CommandType.StoredProcedure: - PropertyChanging(); - _commandType = value; - break; - case System.Data.CommandType.TableDirect: - throw SQL.NotSupportedCommandType(value); - default: - throw ADP.InvalidCommandType(value); - } - - SqlClientEventSource.Log.TryTraceEvent("SqlCommand.Set_CommandType | API | ObjectId {0}, Command type value {1}, Client Connection Id {2}", ObjectID, (int)value, Connection?.ClientConnectionId); - } - } - } - - // By default, the cmd object is visible on the design surface (i.e. VS7 Server Tray) - // to limit the number of components that clutter the design surface, - // when the DataAdapter design wizard generates the insert/update/delete commands it will - // set the DesignTimeVisible property to false so that cmds won't appear as individual objects - /// - [DefaultValue(true)] - [DesignOnly(true)] - [Browsable(false)] - [EditorBrowsable(EditorBrowsableState.Never)] - public override bool DesignTimeVisible - { - get - { - return !_designTimeInvisible; - } - set - { - _designTimeInvisible = !value; - } - } - - /// - public bool EnableOptimizedParameterBinding { get; set; } - - /// - [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] - [ResCategory(StringsHelper.ResourceNames.DataCategory_Data)] - [ResDescription(StringsHelper.ResourceNames.DbCommand_Parameters)] - new public SqlParameterCollection Parameters - { - get - { - if (_parameters == null) - { - // delay the creation of the SqlParameterCollection - // until user actually uses the Parameters property - _parameters = new SqlParameterCollection(); - } - return _parameters; - } - } - - /// - protected override DbParameterCollection DbParameterCollection - { - get - { - return Parameters; - } - } - - /// - [DefaultValue(UpdateRowSource.Both)] - [ResCategory(StringsHelper.ResourceNames.DataCategory_Update)] - [ResDescription(StringsHelper.ResourceNames.DbCommand_UpdatedRowSource)] - public override UpdateRowSource UpdatedRowSource - { - get - { - return _updatedRowSource; - } - set - { - switch (value) - { - case UpdateRowSource.None: - case UpdateRowSource.OutputParameters: - case UpdateRowSource.FirstReturnedRecord: - case UpdateRowSource.Both: - _updatedRowSource = value; - break; - default: - throw ADP.InvalidUpdateRowSource(value); - } - - SqlClientEventSource.Log.TryTraceEvent("SqlCommand.UpdatedRowSource | API | ObjectId {0}, Updated row source value {1}, Client Connection Id {2}", ObjectID, (int)value, Connection?.ClientConnectionId); - } - } - - /// - [ResCategory(StringsHelper.ResourceNames.DataCategory_StatementCompleted)] - [ResDescription(StringsHelper.ResourceNames.DbCommand_StatementCompleted)] - public event StatementCompletedEventHandler StatementCompleted - { - add - { - _statementCompletedEventHandler += value; - } - remove - { - _statementCompletedEventHandler -= value; - } - } - internal void OnStatementCompleted(int recordCount) { if (0 <= recordCount) @@ -829,12 +409,6 @@ internal void OnStatementCompleted(int recordCount) } } - private void PropertyChanging() - { - // also called from SqlParameterCollection - this.IsDirty = true; - } - // Cancel is supposed to be multi-thread safe. // It doesn't make sense to verify the connection exists or that it is open during cancel // because immediately after checking the connection can be closed or removed via another thread. @@ -6614,25 +6188,6 @@ internal int RowsAffectedByDescribeParameterEncryption } } - internal int InternalRecordsAffected - { - get - { - return _rowsAffected; - } - set - { - if (-1 == _rowsAffected) - { - _rowsAffected = value; - } - else if (0 < value) - { - _rowsAffected += value; - } - } - } - /// /// Clear the state in sqlcommand related to describe parameter encryption RPC requests. /// diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlCommand.netfx.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlCommand.netfx.cs index 6e986435bc..d34b323951 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlCommand.netfx.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlCommand.netfx.cs @@ -110,24 +110,11 @@ protected override void AfterCleared(SqlCommand owner) } } - private int? _commandTimeout; - private UpdateRowSource _updatedRowSource = UpdateRowSource.Both; - private bool _designTimeInvisible; - /// /// Indicates if the column encryption setting was set at-least once in the batch rpc mode, when using AddBatchCommand. /// private bool _wasBatchModeColumnEncryptionSettingSetOnce; - /// - /// Column Encryption Override. Defaults to SqlConnectionSetting, in which case - /// it will be Enabled if SqlConnectionOptions.IsColumnEncryptionSettingEnabled = true, Disabled if false. - /// This may also be used to set other behavior which overrides connection level setting. - /// - private SqlCommandColumnEncryptionSetting _columnEncryptionSetting = SqlCommandColumnEncryptionSetting.UseConnectionSetting; - - internal SqlDependency _sqlDep; - #if DEBUG /// /// Force the client to sleep during sp_describe_parameter_encryption in the function TryFetchInputParameterEncryptionInfo. @@ -156,10 +143,6 @@ protected override void AfterCleared(SqlCommand owner) #endif internal static readonly Action s_cancelIgnoreFailure = CancelIgnoreFailureCallback; - private int _preparedConnectionCloseCount = -1; - private int _preparedConnectionReconnectCount = -1; - - private SqlParameterCollection _parameters; private _SqlRPC[] _rpcArrayOf1 = null; // Used for RPC executes private _SqlRPC _rpcForEncryption = null; // Used for sp_describe_parameter_encryption RPC executes @@ -191,23 +174,6 @@ private bool ShouldCacheEncryptionMetadata internal static int DebugForceAsyncWriteDelay { get; set; } #endif - /// - /// Return if column encryption setting is enabled. - /// The order in the below if is important since _activeConnection.Parser can throw if the - /// underlying tds connection is closed and we don't want to change the behavior for folks - /// not trying to use transparent parameter encryption i.e. who don't use (SqlCommandColumnEncryptionSetting.Enabled or _activeConnection.IsColumnEncryptionSettingEnabled) here. - /// - internal bool IsColumnEncryptionEnabled - { - get - { - return (_columnEncryptionSetting == SqlCommandColumnEncryptionSetting.Enabled - || (_columnEncryptionSetting == SqlCommandColumnEncryptionSetting.UseConnectionSetting && _activeConnection.IsColumnEncryptionSettingEnabled)) - && _activeConnection.Parser != null - && _activeConnection.Parser.IsColumnEncryptionSupported; - } - } - internal bool ShouldUseEnclaveBasedWorkflow => (!string.IsNullOrWhiteSpace(_activeConnection.EnclaveAttestationUrl) || Connection.AttestationProtocol == SqlConnectionAttestationProtocol.None) && IsColumnEncryptionEnabled; @@ -323,34 +289,13 @@ private AsyncState CachedAsyncState } } - // sql reader will pull this value out for each NextResult call. It is not cumulative - // _rowsAffected is cumulative for ExecuteNonQuery across all rpc batches - internal int _rowsAffected = -1; // rows affected by the command - // number of rows affected by sp_describe_parameter_encryption. // The below line is used only for debug asserts and not exposed publicly or impacts functionality otherwise. private int _rowsAffectedBySpDescribeParameterEncryption = -1; - - private SqlNotificationRequest _notification; - private bool _notificationAutoEnlist = true; // Notifications auto enlistment is turned on by default - - // transaction support - private SqlTransaction _transaction; - - private StatementCompletedEventHandler _statementCompletedEventHandler; - - // Volatile bool used to synchronize with cancel thread the state change of an executing - // command going from pre-processing to obtaining a stateObject. The cancel synchronization - // we require in the command is only from entering an Execute* API to obtaining a - // stateObj. Once a stateObj is successfully obtained, cancel synchronization is handled - // by the stateObject. - private volatile bool _pendingCancel; - - private bool _batchRPCMode; + private List<_SqlRPC> _RPCList; private _SqlRPC[] _sqlRPCParameterEncryptionReqArray; private int _currentlyExecutingBatch; - private SqlRetryLogicBaseProvider _retryLogicProvider; /// /// This variable is used to keep track of which RPC batch's results are being read when reading the results of @@ -428,254 +373,8 @@ private SqlCommand(SqlCommand from) : this() } } - /// - [DefaultValue(null)] - [ResCategory(StringsHelper.ResourceNames.DataCategory_Data)] - [ResDescription(StringsHelper.ResourceNames.DbCommand_Connection)] - new public SqlConnection Connection - { - get - { - return _activeConnection; - } - set - { - // Don't allow the connection to be changed while in an async operation. - if (_activeConnection != value && _activeConnection != null) - { - // If new value... - if (CachedAsyncState != null && CachedAsyncState.PendingAsyncOperation) - { - // If in pending async state, throw. - throw SQL.CannotModifyPropertyAsyncOperationInProgress(); - } - } - - // Check to see if the currently set transaction has completed. If so, - // null out our local reference. - if (_transaction != null && _transaction.Connection == null) - { - _transaction = null; - } - - // Command is no longer prepared on new connection, cleanup prepare status - if (IsPrepared) - { - if (_activeConnection != value && _activeConnection != null) - { - try - { - // cleanup - Unprepare(); - } - // @TODO: CER Exception Handling was removed here (see GH#3581) - catch (Exception) - { - // we do not really care about errors in unprepare (may be the old connection went bad) - } - finally - { - // clean prepare status (even successful Unprepare does not do that) - _prepareHandle = -1; - _execType = EXECTYPE.UNPREPARED; - } - } - } - _activeConnection = value; - SqlClientEventSource.Log.TryTraceEvent(" {0}, {1}", ObjectID, value?.ObjectID); - } - } - - /// - protected override DbConnection DbConnection - { - get - { - return Connection; - } - set - { - Connection = (SqlConnection)value; - } - } - - private SqlInternalConnectionTds InternalTdsConnection - { - get - { - return (SqlInternalConnectionTds)_activeConnection.InnerConnection; - } - } - private bool IsProviderRetriable => SqlConfigurableRetryFactory.IsRetriable(RetryLogicProvider); - /// - [Browsable(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public SqlRetryLogicBaseProvider RetryLogicProvider - { - get - { - if (_retryLogicProvider == null) - { - _retryLogicProvider = SqlConfigurableRetryLogicManager.CommandProvider; - } - return _retryLogicProvider; - } - set - { - _retryLogicProvider = value; - } - } - - /// - [DefaultValue(true)] - [ResCategory(StringsHelper.ResourceNames.DataCategory_Notification)] - [ResDescription(StringsHelper.ResourceNames.SqlCommand_NotificationAutoEnlist)] - public bool NotificationAutoEnlist - { - get - { - return _notificationAutoEnlist; - } - set - { - _notificationAutoEnlist = value; - } - } - - /// - [Browsable(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] // MDAC 90471 - [ResCategory(StringsHelper.ResourceNames.DataCategory_Notification)] - [ResDescription(StringsHelper.ResourceNames.SqlCommand_Notification)] - public SqlNotificationRequest Notification - { - get - { - return _notification; - } - set - { - SqlClientEventSource.Log.TryTraceEvent(" {0}", ObjectID); - _sqlDep = null; - _notification = value; - } - } - - internal SqlStatistics Statistics - { - get - { - if (_activeConnection != null) - { - if (_activeConnection.StatisticsEnabled) - { - return _activeConnection.Statistics; - } - } - return null; - } - } - - /// - [Browsable(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - [ResDescription(StringsHelper.ResourceNames.DbCommand_Transaction)] - new public SqlTransaction Transaction - { - get - { - // if the transaction object has been zombied, just return null - if (_transaction != null && _transaction.Connection == null) - { - _transaction = null; - } - return _transaction; - } - set - { - // Don't allow the transaction to be changed while in an async operation. - if (_transaction != value && _activeConnection != null) - { - // If new value... - if (CachedAsyncState.PendingAsyncOperation) - { - // If in pending async state, throw - throw SQL.CannotModifyPropertyAsyncOperationInProgress(); - } - } - _transaction = value; - SqlClientEventSource.Log.TryTraceEvent("SqlCommand.Set_Transaction | API | Object Id {0}, Internal Transaction Id {1}, Client Connection Id {2}", ObjectID, value?.InternalTransaction?.TransactionId, Connection?.ClientConnectionId); - } - } - - /// - protected override DbTransaction DbTransaction - { - get - { - return Transaction; - } - set - { - Transaction = (SqlTransaction)value; - SqlClientEventSource.Log.TryTraceEvent("SqlCommand.Set_DbTransaction | API | Object Id {0}, Client Connection Id {1}", ObjectID, Connection?.ClientConnectionId); - } - } - - /// - [DefaultValue("")] - [RefreshProperties(RefreshProperties.All)] // MDAC 67707 - [ResCategory(StringsHelper.ResourceNames.DataCategory_Data)] - [ResDescription(StringsHelper.ResourceNames.DbCommand_CommandText)] - public override string CommandText - { - get => _commandText ?? ""; - set - { - if (_commandText != value) - { - PropertyChanging(); - _commandText = value; - } - SqlClientEventSource.Log.TryTraceEvent("SqlCommand.Set_CommandText | API | Object Id {0}, String Value = '{1}', Client Connection Id {2}", ObjectID, value, Connection?.ClientConnectionId); - } - } - - /// - [Browsable(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - [ResCategory(StringsHelper.ResourceNames.DataCategory_Data)] - [ResDescription(StringsHelper.ResourceNames.TCE_SqlCommand_ColumnEncryptionSetting)] - public SqlCommandColumnEncryptionSetting ColumnEncryptionSetting => _columnEncryptionSetting; - - /// - [ResCategory(StringsHelper.ResourceNames.DataCategory_Data)] - [ResDescription(StringsHelper.ResourceNames.DbCommand_CommandTimeout)] - public override int CommandTimeout - { - get - { - return _commandTimeout ?? DefaultCommandTimeout; - } - set - { - if (value < 0) - { - throw ADP.InvalidCommandTimeout(value, nameof(CommandTimeout)); - } - - if (value != _commandTimeout) - { - PropertyChanging(); - _commandTimeout = value; - } - - SqlClientEventSource.Log.TryTraceEvent("SqlCommand.Set_CommandTimeout | API | ObjectId {0}, Command Timeout value {1}, Client Connection Id {2}", ObjectID, value, Connection?.ClientConnectionId); - } - } - /// public void ResetCommandTimeout() { @@ -686,143 +385,6 @@ public void ResetCommandTimeout() } } - private int DefaultCommandTimeout - { - get - { - return _activeConnection?.CommandTimeout ?? ADP.DefaultCommandTimeout; - } - } - - /// - [DefaultValue(CommandType.Text)] - [RefreshProperties(RefreshProperties.All)] - [ResCategory(StringsHelper.ResourceNames.DataCategory_Data)] - [ResDescription(StringsHelper.ResourceNames.DbCommand_CommandType)] - public override CommandType CommandType - { - get - { - CommandType cmdType = _commandType; - return ((0 != cmdType) ? cmdType : CommandType.Text); - } - set - { - if (_commandType != value) - { - switch (value) - { - case CommandType.Text: - case CommandType.StoredProcedure: - PropertyChanging(); - _commandType = value; - break; - case System.Data.CommandType.TableDirect: - throw SQL.NotSupportedCommandType(value); - default: - throw ADP.InvalidCommandType(value); - } - - SqlClientEventSource.Log.TryTraceEvent("SqlCommand.Set_CommandType | API | ObjectId {0}, Command type value {1}, Client Connection Id {2}", ObjectID, (int)value, Connection?.ClientConnectionId); - } - } - } - - // By default, the cmd object is visible on the design surface (i.e. VS7 Server Tray) - // to limit the number of components that clutter the design surface, - // when the DataAdapter design wizard generates the insert/update/delete commands it will - // set the DesignTimeVisible property to false so that cmds won't appear as individual objects - /// - [DefaultValue(true)] - [DesignOnly(true)] - [Browsable(false)] - [EditorBrowsable(EditorBrowsableState.Never)] - public override bool DesignTimeVisible - { - get - { - return !_designTimeInvisible; - } - set - { - _designTimeInvisible = !value; - TypeDescriptor.Refresh(this); - } - } - - /// - public bool EnableOptimizedParameterBinding { get; set; } - - /// - [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] - [ResCategory(StringsHelper.ResourceNames.DataCategory_Data)] - [ResDescription(StringsHelper.ResourceNames.DbCommand_Parameters)] - new public SqlParameterCollection Parameters - { - get - { - if (_parameters == null) - { - // delay the creation of the SqlParameterCollection - // until user actually uses the Parameters property - _parameters = new SqlParameterCollection(); - } - return _parameters; - } - } - - /// - protected override DbParameterCollection DbParameterCollection - { - get - { - return Parameters; - } - } - - /// - [DefaultValue(UpdateRowSource.Both)] - [ResCategory(StringsHelper.ResourceNames.DataCategory_Update)] - [ResDescription(StringsHelper.ResourceNames.DbCommand_UpdatedRowSource)] - public override UpdateRowSource UpdatedRowSource - { - get - { - return _updatedRowSource; - } - set - { - switch (value) - { - case UpdateRowSource.None: - case UpdateRowSource.OutputParameters: - case UpdateRowSource.FirstReturnedRecord: - case UpdateRowSource.Both: - _updatedRowSource = value; - break; - default: - throw ADP.InvalidUpdateRowSource(value); - } - - SqlClientEventSource.Log.TryTraceEvent("SqlCommand.UpdatedRowSource | API | ObjectId {0}, Updated row source value {1}, Client Connection Id {2}", ObjectID, (int)value, Connection?.ClientConnectionId); - } - } - - /// - [ResCategory(StringsHelper.ResourceNames.DataCategory_StatementCompleted)] - [ResDescription(StringsHelper.ResourceNames.DbCommand_StatementCompleted)] - public event StatementCompletedEventHandler StatementCompleted - { - add - { - _statementCompletedEventHandler += value; - } - remove - { - _statementCompletedEventHandler -= value; - } - } - internal void OnStatementCompleted(int recordCount) { if (0 <= recordCount) @@ -848,12 +410,6 @@ internal void OnStatementCompleted(int recordCount) } } - private void PropertyChanging() - { - // also called from SqlParameterCollection - this.IsDirty = true; - } - // Cancel is supposed to be multi-thread safe. // It doesn't make sense to verify the connection exists or that it is open during cancel // because immediately after checkin the connection can be closed or removed via another thread. @@ -6443,25 +5999,6 @@ internal int RowsAffectedByDescribeParameterEncryption } } - internal int InternalRecordsAffected - { - get - { - return _rowsAffected; - } - set - { - if (-1 == _rowsAffected) - { - _rowsAffected = value; - } - else if (0 < value) - { - _rowsAffected += value; - } - } - } - /// /// Clear the state in sqlcommand related to describe parameter encryption RPC requests. /// diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/AdapterUtil.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/AdapterUtil.cs index 60ea8cbc7b..248fe0f985 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/AdapterUtil.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/AdapterUtil.cs @@ -1173,6 +1173,9 @@ internal static Exception DeriveParametersNotSupported(IDbCommand value) => DataAdapter(StringsHelper.GetString(Strings.ADP_DeriveParametersNotSupported, value.GetType().Name, value.CommandType.ToString())); internal static Exception NoStoredProcedureExists(string sproc) => InvalidOperation(StringsHelper.GetString(Strings.ADP_NoStoredProcedureExists, sproc)); + + internal static Exception InvalidCommandTimeout(int value, [CallerMemberName] string property = "") + => Argument(StringsHelper.GetString(Strings.ADP_InvalidCommandTimeout, value.ToString(CultureInfo.InvariantCulture)), property); #endregion #region DbMetaDataFactory @@ -1503,14 +1506,6 @@ internal static Exception NumericToDecimalOverflow() return InvalidCast(StringsHelper.GetString(Strings.ADP_NumericToDecimalOverflow)); } - // - // IDbCommand - // - internal static Exception InvalidCommandTimeout(int value, string name) - { - return Argument(StringsHelper.GetString(Strings.ADP_InvalidCommandTimeout, value.ToString(CultureInfo.InvariantCulture)), name); - } - // // DbDataAdapter // @@ -1640,12 +1635,6 @@ internal static ArgumentOutOfRangeException InvalidParameterDirection(ParameterD #endif return InvalidEnumerationValue(typeof(ParameterDirection), (int)value); } - - // - // IDbCommand - // - internal static Exception InvalidCommandTimeout(int value, [CallerMemberName] string property = "") - => Argument(StringsHelper.GetString(Strings.ADP_InvalidCommandTimeout, value.ToString(CultureInfo.InvariantCulture)), property); #endregion #endif } diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlCommand.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlCommand.cs index 67865bb155..8b96a7b421 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlCommand.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlCommand.cs @@ -9,6 +9,11 @@ using System.Diagnostics; using System.Threading; using Microsoft.Data.Common; +using Microsoft.Data.Sql; + +#if NET +using Microsoft.Data.SqlClient.Diagnostics; +#endif namespace Microsoft.Data.SqlClient { @@ -20,12 +25,21 @@ public sealed partial class SqlCommand : DbCommand, ICloneable { #region Constants + /// + /// Pre-boxed invalid prepare handle - used to optimize boxing behavior. + /// private static readonly object s_cachedInvalidPrepareHandle = (object)-1; #endregion #region Fields + + // @TODO: Make property - non-private fields are bad + internal SqlDependency _sqlDep; + // @TODO: Rename _batchRpcMode to follow pattern + private bool _batchRPCMode; + /// /// Number of instances of SqlCommand that have been created. Used to generate ObjectId /// @@ -36,15 +50,39 @@ public sealed partial class SqlCommand : DbCommand, ICloneable /// private SqlConnection _activeConnection; + /// + /// Column Encryption Override. Defaults to SqlConnectionSetting, in which case it will be + /// Enabled if SqlConnectionOptions.IsColumnEncryptionSettingEnabled = true, Disabled if + /// false. This may also be used to set other behavior which overrides connection level + /// setting. + /// + // @TODO: Make auto-property + private SqlCommandColumnEncryptionSetting _columnEncryptionSetting = + SqlCommandColumnEncryptionSetting.UseConnectionSetting; + /// /// Text to execute when executing the command. /// private string _commandText; + /// + /// Maximum amount of time, in seconds, the command will execute before timing out. + /// + private int? _commandTimeout; + /// /// Type of the command to execute. /// private CommandType _commandType; + + /// + /// By default, the cmd object is visible on the design surface (i.e. VS7 Server Tray) to + /// limit the number of components that clutter the design surface, when the DataAdapter + /// design wizard generates the insert/update/delete commands it will set the + /// DesignTimeVisible property to false so that cmds won't appear as individual objects + /// + // @TODO: Make auto-property + private bool _designTimeInvisible; /// /// Current state of preparation of the command. @@ -73,21 +111,102 @@ public sealed partial class SqlCommand : DbCommand, ICloneable /// // @TODO: Make auto-property private bool _inPrepare = false; + + private SqlNotificationRequest _notification; + + #if NETFRAMEWORK + // @TODO: Make auto-property + private bool _notificationAutoEnlist = true; + #endif + + /// + /// Parameters that have been added to the current instance. + /// + private SqlParameterCollection _parameters; + + /// + /// Volatile bool used to synchronize with cancel thread the state change of an executing + /// command going from pre-processing to obtaining a stateObject. The cancel + /// synchronization we require in the command is only from entering an Execute* API to + /// obtaining a stateObj. Once a stateObj is successfully obtained, cancel synchronization + /// is handled by the stateObject. + /// + private volatile bool _pendingCancel; + + /// + /// Number of times the connection was closed when the command was prepared. Used to + /// determine if the connection has closed between prepare and execute. + /// + private int _preparedConnectionCloseCount = -1; /// - /// The handle of a prepared command. Apparently there can be multiple prepared commands at - /// a time - a feature that we do not support yet. this is an int which is used in the + /// Number of times the connection was reconnected when the command was prepared. Used to + /// determine if the connection has reconnected between prepare and execute. + /// + private int _preparedConnectionReconnectCount = -1; + + /// + /// the handle of a prepared command. Apparently there can be multiple prepared commands at + /// a time - a feature that we do not support yet. This is an int which is used in the /// object typed SqlParameter.Value field, avoid repeated boxing by storing in a box. /// - private object _prepareHandle = s_cachedInvalidPrepareHandle; // this is an int which is used in the object typed SqlParameter.Value field, avoid repeated boxing by storing in a box + private object _prepareHandle = s_cachedInvalidPrepareHandle; + + /// + /// Retry logic provider to use for execution of the current instance. + /// + private SqlRetryLogicBaseProvider _retryLogicProvider; + + /// + /// Sql reader will pull this value out for each NextResult call. It is not cumulative. + /// _rowsAffected is cumulative for ExecuteNonQuery across all rpc batches + /// + // @TODO: Use int? and replace -1 usage with null + private int _rowsAffected = -1; /// /// TDS session the current instance is using. /// private TdsParserStateObject _stateObj; + + /// + /// Event to call when a statement completes. + /// + // @TODO: Make auto-event? + private StatementCompletedEventHandler _statementCompletedEventHandler; + + /// + /// Current transaction the command is participating in. + /// + private SqlTransaction _transaction; + + /// + /// How command results are applied to a DataRow when used by the update method of + /// DbDataAdapter. + /// + private UpdateRowSource _updatedRowSource = UpdateRowSource.Both; #endregion + #region Events + + /// + [ResCategory(StringsHelper.ResourceNames.DataCategory_StatementCompleted)] + [ResDescription(StringsHelper.ResourceNames.DbCommand_StatementCompleted)] + public event StatementCompletedEventHandler StatementCompleted + { + add + { + _statementCompletedEventHandler += value; + } + remove + { + _statementCompletedEventHandler -= value; + } + } + + #endregion + #region Enums // @TODO: Rename to match naming conventions @@ -111,13 +230,417 @@ private enum EXECTYPE #endregion - #region Properties + #region Public Properties + + /// + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + [ResCategory(StringsHelper.ResourceNames.DataCategory_Data)] + [ResDescription(StringsHelper.ResourceNames.TCE_SqlCommand_ColumnEncryptionSetting)] + public SqlCommandColumnEncryptionSetting ColumnEncryptionSetting => _columnEncryptionSetting; - internal bool InPrepare => _inPrepare; + /// + [ResCategory(StringsHelper.ResourceNames.DataCategory_Data)] + [ResDescription(StringsHelper.ResourceNames.DbCommand_CommandTimeout)] + public override int CommandTimeout + { + get => _commandTimeout ?? DefaultCommandTimeout; + set + { + if (value < 0) + { + throw ADP.InvalidCommandTimeout(value); + } + + if (value != _commandTimeout) + { + PropertyChanging(); + _commandTimeout = value; + } + + SqlClientEventSource.Log.TryTraceEvent( + "SqlCommand.Set_CommandTimeout | API | " + + $"Object Id {ObjectID}, " + + $"Command Timeout value {value}, " + + $"Client Connection Id {Connection?.ClientConnectionId}"); + } + } + + /// + [DefaultValue("")] + [RefreshProperties(RefreshProperties.All)] + [ResCategory(StringsHelper.ResourceNames.DataCategory_Data)] + [ResDescription(StringsHelper.ResourceNames.DbCommand_CommandText)] + public override string CommandText + { + get => _commandText ?? string.Empty; + set + { + if (_commandText != value) + { + PropertyChanging(); + _commandText = value; + } + + SqlClientEventSource.Log.TryTraceEvent( + "SqlCommand.Set_CommandText | API | " + + $"Object Id {ObjectID}, " + + $"String Value = '{value}', " + + $"Client Connection Id {Connection?.ClientConnectionId}"); + } + } + + /// + [DefaultValue(CommandType.Text)] + [RefreshProperties(RefreshProperties.All)] + [ResCategory(StringsHelper.ResourceNames.DataCategory_Data)] + [ResDescription(StringsHelper.ResourceNames.DbCommand_CommandType)] + public override CommandType CommandType + { + get => _commandType != 0 ? _commandType : CommandType.Text; + set + { + if (_commandType != value) + { + switch (value) + { + case CommandType.Text: + case CommandType.StoredProcedure: + PropertyChanging(); + _commandType = value; + break; + case CommandType.TableDirect: + throw SQL.NotSupportedCommandType(value); + default: + throw ADP.InvalidCommandType(value); + } + + // @TODO: Either move this outside the if block or move all the other instances inside the if block. + SqlClientEventSource.Log.TryTraceEvent( + "SqlCommand.Set_CommandType | API | " + + $"Object Id {ObjectID}, " + + $"Command Type value {(int)value}, " + + $"Client Connection Id {Connection?.ClientConnectionId}"); + } + } + } + + /// + [DefaultValue(null)] + [ResCategory(StringsHelper.ResourceNames.DataCategory_Data)] + [ResDescription(StringsHelper.ResourceNames.DbCommand_Connection)] + public new SqlConnection Connection + { + get => _activeConnection; + set + { + // Don't allow the connection to be changed while in an async operation + // @TODO: Factor out + if (_activeConnection != value && _activeConnection != null) + { + // If new value... + if (CachedAsyncState != null && CachedAsyncState.PendingAsyncOperation) + { + // If in pending async state, throw. + throw SQL.CannotModifyPropertyAsyncOperationInProgress(); + } + } + + // Check to see if the currently set transaction has completed. If so, null out + // our local reference. + if (_transaction?.Connection is null) + { + _transaction = null; + } + + if (IsPrepared) + { + if (_activeConnection != value && _activeConnection != null) + { + try + { + Unprepare(); + } + // @TODO: CER Exception Handling was removed here (see GH#3581) + catch (Exception) + { + // We do not really care about errors in unprepare (maybe the old + // connection went bad?) + } + finally + { + // Clean prepare status (even successful unprepare does not do that) + // @TODO: ... but it does? + _prepareHandle = s_cachedInvalidPrepareHandle; + _execType = EXECTYPE.UNPREPARED; + } + } + } + + _activeConnection = value; + + SqlClientEventSource.Log.TryTraceEvent( + "SqlCommand.Set_Connection | API | " + + $"Object Id {ObjectID}, " + + $"Client Connection Id {value?.ClientConnectionId}"); + } + } + + /// + [DefaultValue(true)] + [DesignOnly(true)] + [Browsable(false)] + [EditorBrowsable(EditorBrowsableState.Never)] + public override bool DesignTimeVisible + { + get => !_designTimeInvisible; + set + { + _designTimeInvisible = !value; + + #if NETFRAMEWORK + TypeDescriptor.Refresh(this); + #endif + } + } + + /// + public bool EnableOptimizedParameterBinding { get; set; } + + /// + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + [ResCategory(StringsHelper.ResourceNames.DataCategory_Notification)] + [ResDescription(StringsHelper.ResourceNames.SqlCommand_Notification)] + public SqlNotificationRequest Notification + { + get => _notification; + set + { + _sqlDep = null; + _notification = value; + SqlClientEventSource.Log.TryTraceEvent( + "SqlCommand.Set_Notification | API | " + + $"Object Id {ObjectID}"); + } + } + + #if NETFRAMEWORK + /// + [DefaultValue(true)] + [ResCategory(StringsHelper.ResourceNames.DataCategory_Notification)] + [ResDescription(StringsHelper.ResourceNames.SqlCommand_NotificationAutoEnlist)] + public bool NotificationAutoEnlist + { + get => _notificationAutoEnlist; + set => _notificationAutoEnlist = value; + } + #endif + + /// + [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] + [ResCategory(StringsHelper.ResourceNames.DataCategory_Data)] + [ResDescription(StringsHelper.ResourceNames.DbCommand_Parameters)] + public new SqlParameterCollection Parameters + { + get + { + // Delay the creation of the SqlParameterCollection until user actually uses the + // Parameters property. + _parameters ??= new SqlParameterCollection(); + return _parameters; + } + } + + /// + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public SqlRetryLogicBaseProvider RetryLogicProvider + { + get + { + _retryLogicProvider ??= SqlConfigurableRetryLogicManager.CommandProvider; + return _retryLogicProvider; + } + set => _retryLogicProvider = value; + } + + /// + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + [ResDescription(StringsHelper.ResourceNames.DbCommand_Transaction)] + public new SqlTransaction Transaction + { + get + { + // If the transaction object has been zombied, just return null + if (_transaction is not null && _transaction.Connection is null) + { + _transaction = null; + } + + return _transaction; + } + set + { + // Don't allow the transaction to be changed while in an async operation + if (_transaction != value && _activeConnection is not null) + { + // If new value... + if (CachedAsyncState != null && CachedAsyncState.PendingAsyncOperation) + { + // If in pending async state, throw. + throw SQL.CannotModifyPropertyAsyncOperationInProgress(); + } + } + + _transaction = value; + + SqlClientEventSource.Log.TryTraceEvent( + "SqlCommand.Set_Transaction | API | " + + $"Object Id {ObjectID}, " + + $"Internal Transaction Id {value?.InternalTransaction?.TransactionId}, " + + $"Client Connection Id {Connection?.ClientConnectionId}"); + } + } + + /// + [DefaultValue(UpdateRowSource.Both)] + [ResCategory(StringsHelper.ResourceNames.DataCategory_Update)] + [ResDescription(StringsHelper.ResourceNames.DbCommand_UpdatedRowSource)] + public override UpdateRowSource UpdatedRowSource + { + get => _updatedRowSource; + set + { + switch (value) + { + case UpdateRowSource.None: + case UpdateRowSource.OutputParameters: + case UpdateRowSource.FirstReturnedRecord: + case UpdateRowSource.Both: + _updatedRowSource = value; + break; + default: + throw ADP.InvalidUpdateRowSource(value); + } + + SqlClientEventSource.Log.TryTraceEvent( + "SqlCommand.UpdatedRowSource | API | " + + $"Object Id {ObjectID}, " + + $"Updated Row Source value {(int)value}, " + + $"Client Connection Id {Connection?.ClientConnectionId}"); + } + } + + #endregion + + #region Internal/Protected/Private Properties + internal bool InPrepare => _inPrepare; + + internal int InternalRecordsAffected + { + get => _rowsAffected; + set + { + if (_rowsAffected == -1) + { + _rowsAffected = value; + } + else if (value > 0) + { + _rowsAffected += value; + } + } + } + // @TODO: Rename to match conventions. internal int ObjectID { get; } = Interlocked.Increment(ref _objectTypeCount); + internal SqlStatistics Statistics + { + get + { + if (_activeConnection is not null) + { + #if NET + bool isStatisticsEnabled = _activeConnection.StatisticsEnabled || + s_diagnosticListener.IsEnabled(SqlClientCommandAfter.Name); + #else + bool isStatisticsEnabled = _activeConnection.StatisticsEnabled; + #endif + + if (isStatisticsEnabled) + { + return _activeConnection.Statistics; + } + } + + return null; + } + } + + /// + protected override DbConnection DbConnection + { + get => Connection; + // @TODO: Does set need a trace event like DbTransaction? + set => Connection = (SqlConnection)value; + } + + /// + protected override DbParameterCollection DbParameterCollection + { + get => Parameters; + } + + /// + protected override DbTransaction DbTransaction + { + get => Transaction; + set + { + // @TODO: Does this need a trace event, we have one in Transaction? + Transaction = (SqlTransaction)value; + SqlClientEventSource.Log.TryTraceEvent( + "SqlCommand.Set_DbTransaction | API | " + + $"Object Id {ObjectID}, " + + $"Client Connection Id {Connection?.ClientConnectionId}"); + } + } + + private int DefaultCommandTimeout + { + // @TODO: Should use connection? Should DefaultCommandTimeout be defined *in the command object*? + get => _activeConnection?.CommandTimeout ?? ADP.DefaultCommandTimeout; + } + + // @TODO: Should be used in more than one place to justify its existence + private SqlInternalConnectionTds InternalTdsConnection + { + // @TODO: Should check for null? Should use Connection? + get => (SqlInternalConnectionTds)_activeConnection.InnerConnection; + } + + private bool IsColumnEncryptionEnabled + { + get + { + bool isEncryptionEnabled = + _columnEncryptionSetting is SqlCommandColumnEncryptionSetting.Enabled || + (_columnEncryptionSetting is SqlCommandColumnEncryptionSetting.UseConnectionSetting && + _activeConnection.IsColumnEncryptionSettingEnabled); + + // Order matters here b/c 1) _activeConnection.Parser can throw if the underlying + // connection is closed, and 2) we do not want to throw in that situation unless + // the user is using transparent parameter encryption (breaks old behavior). + return isEncryptionEnabled && + _activeConnection.Parser is not null && + _activeConnection.Parser.IsColumnEncryptionSupported; + } + } + private bool IsDirty { get @@ -146,6 +669,7 @@ private bool IsDirty { _parameters.IsDirty = _dirty; } + _cachedMetaData = null; } } @@ -252,7 +776,7 @@ private void InternalPrepare() { if (IsDirty) { - Debug.Assert(_cachedMetaData == null || !_dirty, "dirty query should not have cached metadata!"); // can have cached metadata if dirty because of parameters + Debug.Assert(_cachedMetaData is null || !_dirty, "dirty query should not have cached metadata!"); // Someone changed the command text or the parameter schema so we must unprepare the command Unprepare(); @@ -277,6 +801,11 @@ private void InternalPrepare() Statistics?.SafeIncrement(ref Statistics._prepares); } + private void PropertyChanging() + { + IsDirty = true; + } + private void Unprepare() { Debug.Assert(IsPrepared, "Invalid attempt to Unprepare a non-prepared command!"); From 994cf81f35a9a70154c2ef3b9d3ea8d8e5ae685d Mon Sep 17 00:00:00 2001 From: Paul Medynski <31868385+paulmedynski@users.noreply.github.com> Date: Thu, 18 Sep 2025 08:35:43 -0300 Subject: [PATCH 12/30] User Story 37654: Create Abstractions package - Replaced generic "NugetPackageVersion" with variables names specific to the package (i.e. MdsPackageVersion, AkvPackageVersion, etc). - Removed top-level Abstractions package version parameters in favour of a variable. --- build.proj | 2 +- eng/pipelines/akv-official-pipeline.yml | 5 ++--- .../jobs/build-signed-package-job.yml | 6 ++--- .../templates/jobs/ci-build-nugets-job.yml | 4 ++-- .../jobs/run-tests-package-reference-job.yml | 6 ++--- .../jobs/validate-signed-package-job.yml | 14 ++++++------ .../templates/steps/build-all-tests-step.yml | 6 ++--- .../build-and-run-tests-netcore-step.yml | 12 +++++----- .../steps/build-and-run-tests-netfx-step.yml | 12 +++++----- .../templates/steps/ci-project-build-step.yml | 12 +++++----- .../steps/generate-nuget-package-step.yml | 8 +++---- .../templates/steps/publish-symbols-step.yml | 2 +- .../templates/steps/run-all-tests-step.yml | 22 +++++++++---------- eng/pipelines/dotnet-sqlclient-ci-core.yml | 15 +++++-------- ...qlclient-ci-package-reference-pipeline.yml | 6 ----- ...qlclient-ci-project-reference-pipeline.yml | 6 ----- .../dotnet-sqlclient-signing-pipeline.yml | 2 +- eng/pipelines/jobs/build-akv-official-job.yml | 19 +++++++--------- .../libraries/ci-build-variables.yml | 4 +++- eng/pipelines/libraries/common-variables.yml | 4 ++-- .../libraries/mds-validation-variables.yml | 2 +- .../steps/compound-build-akv-step.yml | 10 ++++----- .../steps/roslyn-analyzers-akv-step.yml | 6 ++--- .../variables/akv-official-variables.yml | 4 +--- tools/props/Versions.props | 10 ++++----- tools/targets/GenerateNugetPackage.targets | 8 +++---- .../GenerateAKVProviderNugetPackage.targets | 6 ++--- 27 files changed, 95 insertions(+), 118 deletions(-) diff --git a/build.proj b/build.proj index 082dd58f31..ab45ccc1ac 100644 --- a/build.proj +++ b/build.proj @@ -88,7 +88,7 @@ - + diff --git a/eng/pipelines/akv-official-pipeline.yml b/eng/pipelines/akv-official-pipeline.yml index d7bc900bb8..fcaa1bb3e2 100644 --- a/eng/pipelines/akv-official-pipeline.yml +++ b/eng/pipelines/akv-official-pipeline.yml @@ -113,7 +113,7 @@ extends: sbom: enabled: ${{ parameters.runSdlTasks }} packageName: 'Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider' - packageVersion: ${{ variables.nugetPackageVersion }} + packageVersion: ${{ variables.akvPackageVersion }} tsa: # OneBranch publishes all sdl results to TSA. If TSA is disabled all SDL tools will @@ -131,8 +131,7 @@ extends: apiScanPdbPath: '${{ variables.apiScanPdbPath }}' assemblyFileVersion: '${{ variables.assemblyFileVersion }}' buildConfiguration: '${{ parameters.buildConfiguration }}' - nugetPackageVersion: '${{ variables.nugetPackageVersion }}' - mdsPackageVersion: '${{ variables.mdsPackageVersion }}' + akvPackageVersion: '${{ variables.akvPackageVersion }}' publishSymbols: '${{ parameters.publishSymbols }}' signingAppRegistrationClientId: '$(SigningAppRegistrationClientId)' signingAppRegistrationTenantId: '$(SigningAppRegistrationTenantId)' diff --git a/eng/pipelines/common/templates/jobs/build-signed-package-job.yml b/eng/pipelines/common/templates/jobs/build-signed-package-job.yml index 91eb864337..53403d9d57 100644 --- a/eng/pipelines/common/templates/jobs/build-signed-package-job.yml +++ b/eng/pipelines/common/templates/jobs/build-signed-package-job.yml @@ -27,8 +27,8 @@ jobs: variables: - template: ../../../libraries/variables.yml@self - ${{ if parameters.isPreview }}: - - name: NugetPackageVersion - value: $(PreviewNugetPackageVersion) + - name: mdsPackageVersion + value: $(previewMdsPackageVersion) steps: - script: SET @@ -64,4 +64,4 @@ jobs: - template: ../steps/publish-symbols-step.yml@self parameters: publishSymbols: ${{ parameters['PublishSymbols'] }} - symbolsArtifactName: mds_symbols_$(System.TeamProject)_$(Build.Repository.Name)_$(Build.SourceBranchName)_$(NuGetPackageVersion)_$(System.TimelineId) + symbolsArtifactName: mds_symbols_$(System.TeamProject)_$(Build.Repository.Name)_$(Build.SourceBranchName)_$(mdsPackageVersion)_$(System.TimelineId) diff --git a/eng/pipelines/common/templates/jobs/ci-build-nugets-job.yml b/eng/pipelines/common/templates/jobs/ci-build-nugets-job.yml index fbb21b81e2..63f99cae76 100644 --- a/eng/pipelines/common/templates/jobs/ci-build-nugets-job.yml +++ b/eng/pipelines/common/templates/jobs/ci-build-nugets-job.yml @@ -78,7 +78,7 @@ jobs: - template: ../steps/generate-nuget-package-step.yml@self parameters: - NugetPackageVersion: $(NugetPackageVersion) + mdsPackageVersion: $(mdsPackageVersion) configuration: $(Configuration) nuspecPath: 'tools/specs/Microsoft.Data.SqlClient.nuspec' OutputDirectory: $(packagePath) @@ -87,7 +87,7 @@ jobs: - template: ../steps/generate-nuget-package-step.yml@self parameters: - NugetPackageVersion: $(NugetPackageVersion) + mdsPackageVersion: $(mdsPackageVersion) configuration: $(Configuration) nuspecPath: 'tools/specs/add-ons/Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider.nuspec' OutputDirectory: $(packagePath) diff --git a/eng/pipelines/common/templates/jobs/run-tests-package-reference-job.yml b/eng/pipelines/common/templates/jobs/run-tests-package-reference-job.yml index 14aea42411..c422ffdc34 100644 --- a/eng/pipelines/common/templates/jobs/run-tests-package-reference-job.yml +++ b/eng/pipelines/common/templates/jobs/run-tests-package-reference-job.yml @@ -52,8 +52,6 @@ jobs: - template: ../steps/update-nuget-config-local-feed-step.yml parameters: downloadedNugetPath: $(Pipeline.Workspace)\${{parameters.packageFolderName }} - ${{ if parameters.isPreview }}: - nugetPackageVersion: $(PreviewNugetPackageVersion) - template: ../steps/update-config-file-step.yml parameters: @@ -68,11 +66,11 @@ jobs: parameters: referenceType: Package ${{ if parameters.isPreview }}: - nugetPackageVersion: $(PreviewNugetPackageVersion) + mdsPackageVersion: $(previewMdsPackageVersion) - template: ../steps/build-and-run-tests-netcore-step.yml parameters: referenceType: Package cleanFirst: true ${{ if parameters.isPreview }}: - nugetPackageVersion: $(PreviewNugetPackageVersion) + mdsPackageVersion: $(previewMdsPackageVersion) diff --git a/eng/pipelines/common/templates/jobs/validate-signed-package-job.yml b/eng/pipelines/common/templates/jobs/validate-signed-package-job.yml index 009e6f2647..333e78ffd4 100644 --- a/eng/pipelines/common/templates/jobs/validate-signed-package-job.yml +++ b/eng/pipelines/common/templates/jobs/validate-signed-package-job.yml @@ -54,18 +54,18 @@ jobs: value: $(Pipeline.Workspace)\${{parameters.packageFolderName }} - name: ProductVersion #MDS product version (MDS validation) - value: $(NugetPackageVersion) + value: $(mdsPackageVersion) - name: BuildType value: $[ stageDependencies.buildMDS.build_signed_package.outputs['GetBuildType.CDP_BUILD_TYPE_COPY'] ] - ${{ if parameters.isPreview }}: - name: extractedNugetPath - value: $(extractedNugetRootPath).$(PreviewNugetPackageVersion) - - name: NugetPackageVersion - value: $(PreviewNugetPackageVersion) + value: $(extractedNugetRootPath).$(previewMdsPackageVersion) + - name: mdsPackageVersion + value: $(previewMdsPackageVersion) - name: ProductVersion - value: $(PreviewNugetPackageVersion) + value: $(previewMdsPackageVersion) steps: - script: SET @@ -75,7 +75,7 @@ jobs: displayName: 'Use NuGet' - powershell: | - #Sets Variables for AssemblyFileVersion, AssemblyVersion and NugetPackageVersion + # Sets the pipeline ASSEMBLY_VERSION variable. [Xml] $versionprops = Get-Content -Path ".\tools\props\Versions.props" Write-Host $versionprops.Project.PropertyGroup[0].AssemblyFileVersion @@ -336,7 +336,7 @@ jobs: [Xml] $versionprops = Get-Content -Path "tools/props/Versions.props" $versionpropspath = "tools\props\Versions.props" - $versionprops.Project.PropertyGroup[$versionprops.Project.PropertyGroup.Count-1].TestMicrosoftDataSqlClientVersion ="$(NugetPackageVersion)" + $versionprops.Project.PropertyGroup[$versionprops.Project.PropertyGroup.Count-1].TestMicrosoftDataSqlClientVersion ="$(mdsPackageVersion)" Write-Host "Saving Test nuget version at $rootfolder\props ...." -ForegroundColor Green $versionprops.Save($versionpropspath) diff --git a/eng/pipelines/common/templates/steps/build-all-tests-step.yml b/eng/pipelines/common/templates/steps/build-all-tests-step.yml index 2742376c1f..43ecb6aafa 100644 --- a/eng/pipelines/common/templates/steps/build-all-tests-step.yml +++ b/eng/pipelines/common/templates/steps/build-all-tests-step.yml @@ -42,7 +42,7 @@ steps: solution: build.proj platform: '${{parameters.platform }}' configuration: '${{parameters.configuration }}' - msbuildArguments: '-t:BuildTestsNetFx -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }} -p:AbstractionsPackageVersion=${{ parameters.abstractionsPackageVersion }}.$(Build.BuildNumber)' + msbuildArguments: '-t:BuildTestsNetFx -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }} -p:AbstractionsPackageVersion=${{ parameters.abstractionsPackageVersion }}' - ${{elseif eq(parameters.osGroup, '')}}: # .NET on Windows - task: MSBuild@1 @@ -51,7 +51,7 @@ steps: solution: build.proj platform: '${{parameters.platform }}' configuration: '${{parameters.configuration }}' - msbuildArguments: '-t:BuildTestsNetCore -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }} -p:AbstractionsPackageVersion=${{ parameters.abstractionsPackageVersion }}.$(Build.BuildNumber)' + msbuildArguments: '-t:BuildTestsNetCore -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }} -p:AbstractionsPackageVersion=${{ parameters.abstractionsPackageVersion }}' condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT')) - ${{ else }}: # .NET on Unix @@ -61,7 +61,7 @@ steps: command: custom projects: build.proj custom: msbuild - arguments: '-t:BuildTestsNetCore -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }} -p:OSGroup=${{parameters.osGroup }} -p:platform=${{parameters.platform }} -p:Configuration=${{parameters.configuration }} -p:AbstractionsPackageVersion=${{ parameters.abstractionsPackageVersion }}.$(Build.BuildNumber)' + arguments: '-t:BuildTestsNetCore -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }} -p:OSGroup=${{parameters.osGroup }} -p:platform=${{parameters.platform }} -p:Configuration=${{parameters.configuration }} -p:AbstractionsPackageVersion=${{ parameters.abstractionsPackageVersion }}' verbosityRestore: Detailed verbosityPack: Detailed condition: and(succeeded(), ne(variables['Agent.OS'], 'Windows_NT')) diff --git a/eng/pipelines/common/templates/steps/build-and-run-tests-netcore-step.yml b/eng/pipelines/common/templates/steps/build-and-run-tests-netcore-step.yml index c70fe776a7..43eea4449d 100644 --- a/eng/pipelines/common/templates/steps/build-and-run-tests-netcore-step.yml +++ b/eng/pipelines/common/templates/steps/build-and-run-tests-netcore-step.yml @@ -18,9 +18,9 @@ parameters: - Project - Package - - name: NugetPackageVersion + - name: mdsPackageVersion type: string - default: $(NugetPackageVersion) + default: $(mdsPackageVersion) - name: platform type: string @@ -55,14 +55,14 @@ steps: inputs: solution: build.proj msbuildArchitecture: x64 - msbuildArguments: '-p:Configuration=${{parameters.configuration }} -t:BuildAKVNetCore -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.NugetPackageVersion }}' + msbuildArguments: '-p:Configuration=${{parameters.configuration }} -t:BuildAKVNetCore -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }}' - task: MSBuild@1 displayName: 'MSBuild Build Tests for ${{parameters.TargetNetCoreVersion }}' inputs: solution: build.proj msbuildArchitecture: x64 - msbuildArguments: '-t:BuildTestsNetCore -p:ReferenceType=${{parameters.referenceType }} -p:TargetNetCoreVersion=${{parameters.TargetNetCoreVersion }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.NugetPackageVersion }} -p:Configuration=${{parameters.configuration }}' + msbuildArguments: '-t:BuildTestsNetCore -p:ReferenceType=${{parameters.referenceType }} -p:TargetNetCoreVersion=${{parameters.TargetNetCoreVersion }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }} -p:Configuration=${{parameters.configuration }}' # Don't run unit tests using package reference. Unit tests are only run using project reference. @@ -71,12 +71,12 @@ steps: inputs: command: test projects: 'src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.FunctionalTests.csproj' - arguments: '-p:Platform=${{parameters.platform }} -p:TestTargetOS="${{parameters.TestTargetOS }}" -p:TargetNetCoreVersion=${{parameters.TargetNetCoreVersion }} -p:ReferenceType=${{parameters.referenceType }} -p:Configuration=${{parameters.configuration }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.NugetPackageVersion }} --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests"' + arguments: '-p:Platform=${{parameters.platform }} -p:TestTargetOS="${{parameters.TestTargetOS }}" -p:TargetNetCoreVersion=${{parameters.TargetNetCoreVersion }} -p:ReferenceType=${{parameters.referenceType }} -p:Configuration=${{parameters.configuration }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }} --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests"' - task: DotNetCoreCLI@2 displayName: 'Run Manual Tests for ${{parameters.TargetNetCoreVersion }}' inputs: command: test projects: 'src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj' - arguments: '-p:Platform=${{parameters.platform }} -p:TestTargetOS="${{parameters.TestTargetOS }}" -p:TargetNetCoreVersion=${{parameters.TargetNetCoreVersion }} -p:ReferenceType=${{parameters.referenceType }} -p:Configuration=${{parameters.configuration }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.NugetPackageVersion }} --no-build -v n --filter category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests --collect "Code Coverage"' + arguments: '-p:Platform=${{parameters.platform }} -p:TestTargetOS="${{parameters.TestTargetOS }}" -p:TargetNetCoreVersion=${{parameters.TargetNetCoreVersion }} -p:ReferenceType=${{parameters.referenceType }} -p:Configuration=${{parameters.configuration }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }} --no-build -v n --filter category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests --collect "Code Coverage"' retryCountOnTaskFailure: ${{parameters.retryCountOnManualTests }} diff --git a/eng/pipelines/common/templates/steps/build-and-run-tests-netfx-step.yml b/eng/pipelines/common/templates/steps/build-and-run-tests-netfx-step.yml index 5d9f194c48..e7b35f653e 100644 --- a/eng/pipelines/common/templates/steps/build-and-run-tests-netfx-step.yml +++ b/eng/pipelines/common/templates/steps/build-and-run-tests-netfx-step.yml @@ -18,9 +18,9 @@ parameters: - Project - Package - - name: NugetPackageVersion + - name: mdsPackageVersion type: string - default: $(NugetPackageVersion) + default: $(mdsPackageVersion) - name: platform type: string @@ -55,13 +55,13 @@ steps: inputs: solution: build.proj msbuildArchitecture: x64 - msbuildArguments: '-p:Configuration=${{parameters.configuration }} -t:BuildAKVNetFx -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.NugetPackageVersion }}' + msbuildArguments: '-p:Configuration=${{parameters.configuration }} -t:BuildAKVNetFx -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }}' - task: MSBuild@1 displayName: 'MSBuild Build Tests for ${{parameters.TargetNetFxVersion }}' inputs: solution: build.proj - msbuildArguments: ' -t:BuildTestsNetFx -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.NugetPackageVersion }} -p:TargetNetFxVersion=${{parameters.TargetNetFxVersion }} -p:Configuration=${{parameters.configuration }} -p:Platform=${{parameters.platform }}' + msbuildArguments: ' -t:BuildTestsNetFx -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }} -p:TargetNetFxVersion=${{parameters.TargetNetFxVersion }} -p:Configuration=${{parameters.configuration }} -p:Platform=${{parameters.platform }}' # Don't run unit tests using package reference. Unit tests are only run using project reference. @@ -70,12 +70,12 @@ steps: inputs: command: test projects: 'src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.FunctionalTests.csproj' - arguments: '-p:Platform=${{parameters.platform }} -p:TestTargetOS="${{parameters.TestTargetOS }}" -p:TargetNetFxVersion=${{parameters.TargetNetFxVersion }} -p:ReferenceType=${{parameters.referenceType }} -p:Configuration=${{parameters.configuration }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.NugetPackageVersion }} --no-build -v n --filter "category!=nonnetfxtests&category!=failing&category!=nonwindowstests" --collect "Code Coverage"' + arguments: '-p:Platform=${{parameters.platform }} -p:TestTargetOS="${{parameters.TestTargetOS }}" -p:TargetNetFxVersion=${{parameters.TargetNetFxVersion }} -p:ReferenceType=${{parameters.referenceType }} -p:Configuration=${{parameters.configuration }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }} --no-build -v n --filter "category!=nonnetfxtests&category!=failing&category!=nonwindowstests" --collect "Code Coverage"' - task: DotNetCoreCLI@2 displayName: 'Run Manual Tests for ${{parameters.TargetNetFxVersion }}' inputs: command: test projects: 'src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj' - arguments: '-p:Platform=${{parameters.platform }} -p:TestTargetOS="${{parameters.TestTargetOS }}" -p:TargetNetFxVersion=${{parameters.TargetNetFxVersion }} -p:ReferenceType=${{parameters.referenceType }} -p:Configuration=${{parameters.configuration }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.NugetPackageVersion }} --no-build -v n --filter "category!=nonnetfxtests&category!=failing&category!=nonwindowstests" --collect "Code Coverage"' + arguments: '-p:Platform=${{parameters.platform }} -p:TestTargetOS="${{parameters.TestTargetOS }}" -p:TargetNetFxVersion=${{parameters.TargetNetFxVersion }} -p:ReferenceType=${{parameters.referenceType }} -p:Configuration=${{parameters.configuration }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }} --no-build -v n --filter "category!=nonnetfxtests&category!=failing&category!=nonwindowstests" --collect "Code Coverage"' retryCountOnTaskFailure: ${{parameters.retryCountOnManualTests }} diff --git a/eng/pipelines/common/templates/steps/ci-project-build-step.yml b/eng/pipelines/common/templates/steps/ci-project-build-step.yml index fa6779616e..6d3ec671a2 100644 --- a/eng/pipelines/common/templates/steps/ci-project-build-step.yml +++ b/eng/pipelines/common/templates/steps/ci-project-build-step.yml @@ -57,7 +57,7 @@ steps: inputs: solution: build.proj msbuildArchitecture: x64 - msbuildArguments: '-t:restore -p:AbstractionsPackageVersion=${{parameters.abstractionsPackageVersion}}.${{parameters.buildNumber}}' + msbuildArguments: '-t:restore -p:AbstractionsPackageVersion=${{parameters.abstractionsPackageVersion}}' retryCountOnTaskFailure: 1 - ${{ if eq(parameters.build, 'allNoDocs') }}: @@ -69,7 +69,7 @@ steps: msbuildArchitecture: x64 platform: '${{ parameters.platform }}' configuration: '${{ parameters.configuration }}' - msbuildArguments: '-t:BuildAllConfigurations -p:GenerateDocumentationFile=false -p:GenerateNuGet=false -p:BuildNumber=${{ parameters.buildNumber }} -p:AbstractionsPackageVersion=${{parameters.abstractionsPackageVersion}}.${{parameters.buildNumber}}' + msbuildArguments: '-t:BuildAllConfigurations -p:GenerateDocumentationFile=false -p:GenerateNuGet=false -p:BuildNumber=${{ parameters.buildNumber }} -p:AbstractionsPackageVersion=${{parameters.abstractionsPackageVersion}}' clean: true - ${{ if or(eq(parameters.build, 'MDS'), eq(parameters.build, 'all')) }}: @@ -81,7 +81,7 @@ steps: msbuildArchitecture: x64 platform: '${{ parameters.platform }}' configuration: '${{ parameters.configuration }}' - msbuildArguments: '-t:BuildAllConfigurations -p:GenerateNuGet=false -p:BuildNumber=${{ parameters.buildNumber }} -p:AbstractionsPackageVersion=${{parameters.abstractionsPackageVersion}}.${{parameters.buildNumber}}' + msbuildArguments: '-t:BuildAllConfigurations -p:GenerateNuGet=false -p:BuildNumber=${{ parameters.buildNumber }} -p:AbstractionsPackageVersion=${{parameters.abstractionsPackageVersion}}' clean: true - ${{ if or(eq(parameters.build, 'AKV'), eq(parameters.build, 'all'), eq(parameters.build, 'allNoDocs')) }}: @@ -93,7 +93,7 @@ steps: msbuildArchitecture: x64 platform: '${{ parameters.platform }}' configuration: '${{ parameters.configuration }}' - msbuildArguments: '-t:BuildAKVNetFx -p:BuildNumber=${{ parameters.buildNumber }} -p:AbstractionsPackageVersion=${{parameters.abstractionsPackageVersion}}.${{parameters.buildNumber}}' + msbuildArguments: '-t:BuildAKVNetFx -p:BuildNumber=${{ parameters.buildNumber }} -p:AbstractionsPackageVersion=${{parameters.abstractionsPackageVersion}}' - task: MSBuild@1 displayName: 'Build AKV Provider NetCore All OS [Win]' @@ -103,7 +103,7 @@ steps: msbuildArchitecture: x64 platform: '${{ parameters.platform }}' configuration: '${{ parameters.configuration }}' - msbuildArguments: '-t:BuildAKVNetCoreAllOS -p:BuildNumber=${{ parameters.buildNumber }} -p:AbstractionsPackageVersion=${{parameters.abstractionsPackageVersion}}.${{parameters.buildNumber}}' + msbuildArguments: '-t:BuildAKVNetCoreAllOS -p:BuildNumber=${{ parameters.buildNumber }} -p:AbstractionsPackageVersion=${{parameters.abstractionsPackageVersion}}' - ${{ if or(eq(parameters.operatingSystem, 'Linux'), eq(parameters.operatingSystem, 'MacOS'), eq(parameters.operatingSystem, 'deferedToRuntime')) }}: - task: DotNetCoreCLI@2 @@ -113,7 +113,7 @@ steps: command: custom projects: build.proj custom: msbuild - arguments: '-t:BuildAll -p:TestEnabled=true -p:GenerateDocumentationFile=false -p:configuration=${{ parameters.configuration }} -p:AbstractionsPackageVersion=${{parameters.abstractionsPackageVersion}}.${{parameters.buildNumber}}' + arguments: '-t:BuildAll -p:TestEnabled=true -p:GenerateDocumentationFile=false -p:configuration=${{ parameters.configuration }} -p:AbstractionsPackageVersion=${{parameters.abstractionsPackageVersion}}' verbosityRestore: Detailed verbosityPack: Detailed retryCountOnTaskFailure: 1 diff --git a/eng/pipelines/common/templates/steps/generate-nuget-package-step.yml b/eng/pipelines/common/templates/steps/generate-nuget-package-step.yml index 4e32f989c3..1afd22c063 100644 --- a/eng/pipelines/common/templates/steps/generate-nuget-package-step.yml +++ b/eng/pipelines/common/templates/steps/generate-nuget-package-step.yml @@ -8,9 +8,9 @@ parameters: type: string default: '$(nuspecPath)' - - name: NugetPackageVersion + - name: mdsPackageVersion type: string - default: '$(NugetPackageVersion)' + default: '$(mdsPackageVersion)' - name: OutputDirectory type: string @@ -55,6 +55,6 @@ steps: inputs: command: custom ${{ if parameters.generateSymbolsPackage }}: - arguments: 'pack -Symbols -SymbolPackageFormat snupkg ${{parameters.nuspecPath}} -Version ${{parameters.NugetPackageVersion}} -OutputDirectory ${{parameters.OutputDirectory}} -properties "COMMITID=$(CommitHead);Configuration=${{parameters.Configuration}};ReferenceType=${{parameters.referenceType}}"' + arguments: 'pack -Symbols -SymbolPackageFormat snupkg ${{parameters.nuspecPath}} -Version ${{parameters.mdsPackageVersion}} -OutputDirectory ${{parameters.OutputDirectory}} -properties "COMMITID=$(CommitHead);Configuration=${{parameters.Configuration}};ReferenceType=${{parameters.referenceType}}"' ${{else }}: - arguments: 'pack ${{parameters.nuspecPath}} -Version ${{parameters.NugetPackageVersion}} -OutputDirectory ${{parameters.OutputDirectory}} -properties "COMMITID=$(CommitHead);Configuration=${{parameters.Configuration}};ReferenceType=${{parameters.referenceType}}"' + arguments: 'pack ${{parameters.nuspecPath}} -Version ${{parameters.mdsPackageVersion}} -OutputDirectory ${{parameters.OutputDirectory}} -properties "COMMITID=$(CommitHead);Configuration=${{parameters.Configuration}};ReferenceType=${{parameters.referenceType}}"' diff --git a/eng/pipelines/common/templates/steps/publish-symbols-step.yml b/eng/pipelines/common/templates/steps/publish-symbols-step.yml index 5f8d2e6a7d..8999a6cc1d 100644 --- a/eng/pipelines/common/templates/steps/publish-symbols-step.yml +++ b/eng/pipelines/common/templates/steps/publish-symbols-step.yml @@ -15,7 +15,7 @@ parameters: - name: symbolsVersion type: string - default: '$(NuGetPackageVersion)' + default: '$(mdsPackageVersion)' - name: symbolServer type: string diff --git a/eng/pipelines/common/templates/steps/run-all-tests-step.yml b/eng/pipelines/common/templates/steps/run-all-tests-step.yml index b9a870ada4..27da9e4e73 100644 --- a/eng/pipelines/common/templates/steps/run-all-tests-step.yml +++ b/eng/pipelines/common/templates/steps/run-all-tests-step.yml @@ -11,9 +11,9 @@ parameters: - name: targetFramework type: string - - name: nugetPackageVersion + - name: mdsPackageVersion type: string - default: $(NugetPackageVersion) + default: $(mdsPackageVersion) - name: platform type: string @@ -62,9 +62,9 @@ steps: platform: '${{parameters.platform }}' configuration: '${{parameters.configuration }}' ${{ if eq(parameters.msbuildArchitecture, 'x64') }}: - msbuildArguments: '-t:RunUnitTests -p:TF=${{parameters.targetFramework }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.nugetPackageVersion }}' + msbuildArguments: '-t:RunUnitTests -p:TF=${{parameters.targetFramework }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }}' ${{ else }}: # x86 - msbuildArguments: '-t:RunUnitTests -p:TF=${{parameters.targetFramework }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.nugetPackageVersion }} -p:DotnetPath=${{parameters.dotnetx86RootPath }}' + msbuildArguments: '-t:RunUnitTests -p:TF=${{parameters.targetFramework }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }} -p:DotnetPath=${{parameters.dotnetx86RootPath }}' condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT')) retryCountOnTaskFailure: 1 @@ -76,9 +76,9 @@ steps: platform: '${{parameters.platform }}' configuration: '${{parameters.configuration }}' ${{ if eq(parameters.msbuildArchitecture, 'x64') }}: - msbuildArguments: '-t:RunFunctionalTests -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.nugetPackageVersion }}' + msbuildArguments: '-t:RunFunctionalTests -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }}' ${{ else }}: # x86 - msbuildArguments: '-t:RunFunctionalTests -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.nugetPackageVersion }} -p:DotnetPath=${{parameters.dotnetx86RootPath }}' + msbuildArguments: '-t:RunFunctionalTests -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }} -p:DotnetPath=${{parameters.dotnetx86RootPath }}' condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT')) retryCountOnTaskFailure: 1 @@ -90,9 +90,9 @@ steps: platform: '${{parameters.platform }}' configuration: '${{parameters.configuration }}' ${{ if eq(parameters.msbuildArchitecture, 'x64') }}: - msbuildArguments: '-t:RunManualTests -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.nugetPackageVersion }}' + msbuildArguments: '-t:RunManualTests -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }}' ${{ else }}: # x86 - msbuildArguments: '-t:RunManualTests -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.nugetPackageVersion }} -p:DotnetPath=${{parameters.dotnetx86RootPath }}' + msbuildArguments: '-t:RunManualTests -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }} -p:DotnetPath=${{parameters.dotnetx86RootPath }}' condition: eq(variables['Agent.OS'], 'Windows_NT') retryCountOnTaskFailure: 2 @@ -104,7 +104,7 @@ steps: command: custom projects: build.proj custom: msbuild - arguments: '-t:RunUnitTests -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.nugetPackageVersion }} -p:platform=${{parameters.platform }} -p:Configuration=${{parameters.configuration }}' + arguments: '-t:RunUnitTests -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }} -p:platform=${{parameters.platform }} -p:Configuration=${{parameters.configuration }}' verbosityRestore: Detailed verbosityPack: Detailed retryCountOnTaskFailure: 1 @@ -116,7 +116,7 @@ steps: command: custom projects: build.proj custom: msbuild - arguments: '-t:RunFunctionalTests -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.nugetPackageVersion }} -p:platform=${{parameters.platform }} -p:Configuration=${{parameters.configuration }}' + arguments: '-t:RunFunctionalTests -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }} -p:platform=${{parameters.platform }} -p:Configuration=${{parameters.configuration }}' verbosityRestore: Detailed verbosityPack: Detailed retryCountOnTaskFailure: 1 @@ -128,7 +128,7 @@ steps: command: custom projects: build.proj custom: msbuild - arguments: '-t:RunManualTests -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.nugetPackageVersion }} -p:platform=${{parameters.platform }} -p:Configuration=${{parameters.configuration }}' + arguments: '-t:RunManualTests -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }} -p:platform=${{parameters.platform }} -p:Configuration=${{parameters.configuration }}' verbosityRestore: Detailed verbosityPack: Detailed retryCountOnTaskFailure: 2 diff --git a/eng/pipelines/dotnet-sqlclient-ci-core.yml b/eng/pipelines/dotnet-sqlclient-ci-core.yml index 0a54fc894e..e9b979a1f5 100644 --- a/eng/pipelines/dotnet-sqlclient-ci-core.yml +++ b/eng/pipelines/dotnet-sqlclient-ci-core.yml @@ -34,11 +34,6 @@ parameters: type: object default: [1, 2, 3] -- name: abstractionsPackageVersion - displayName: Abstractions Package Version Override - type: string - default: '' - - name: useManagedSNI displayName: | Use Managed/Native SNI on Windows, @@ -113,7 +108,7 @@ stages: - template: stages/build-abstractions-package-ci-stage.yml@self parameters: buildConfiguration: Release - packageVersion: ${{parameters.abstractionsPackageVersion}} + packageVersion: $(abstractionsPackageVersion) buildNumber: $(buildNumber) artifactName: $(abstractionsArtifactName) ${{if eq(parameters.debug, 'true')}}: @@ -134,7 +129,7 @@ stages: parameters: referenceType: ${{ parameters.referenceType }} configuration: ${{ parameters.buildConfiguration }} - abstractionsPackageVersion: ${{parameters.abstractionsPackageVersion}} + abstractionsPackageVersion: $(abstractionsPackageVersion) abstractionsArtifactName: $(abstractionsArtifactName) mdsArtifactName: $(mdsArtifactName) ${{if ne(parameters.SNIVersion, '')}}: @@ -150,7 +145,7 @@ stages: buildConfiguration: ${{ parameters.buildConfiguration }} dependsOn: [build_mds_packages_job] pipelineArtifactName: $(artifactName) - mdsPackageVersion: $(NugetPackageVersion) + mdsPackageVersion: $(mdsPackageVersion) ${{ if eq(parameters.debug, 'true') }}: verbosity: 'detailed' @@ -160,9 +155,9 @@ stages: referenceType: ${{ parameters.referenceType }} testsTimeout: ${{ parameters.testsTimeout }} abstractionsArtifactName: $(abstractionsArtifactName) - abstractionsPackageVersion: ${{parameters.abstractionsPackageVersion}} + abstractionsPackageVersion: $(abstractionsPackageVersion) mdsArtifactName: $(mdsArtifactName) - mdsPackageVersion: $(NugetPackageVersion) + mdsPackageVersion: $(mdsPackageVersion) # When testing MDS via packages, we must depend on the Abstractions and # MDS packages. diff --git a/eng/pipelines/dotnet-sqlclient-ci-package-reference-pipeline.yml b/eng/pipelines/dotnet-sqlclient-ci-package-reference-pipeline.yml index 1ca58a910d..6eafba83cf 100644 --- a/eng/pipelines/dotnet-sqlclient-ci-package-reference-pipeline.yml +++ b/eng/pipelines/dotnet-sqlclient-ci-package-reference-pipeline.yml @@ -62,11 +62,6 @@ parameters: # parameters are shown up in ADO UI in a build queue time type: object default: [1, 2, 3] -- name: abstractionsPackageVersion - displayName: Abstractions Package Version - type: string - default: 1.0.0 - - name: useManagedSNI displayName: | Use Managed/Native SNI on Windows, @@ -105,7 +100,6 @@ extends: targetFrameworksLinux: ${{ parameters.targetFrameworksLinux }} buildPlatforms: ${{ parameters.buildPlatforms }} testSets: ${{ parameters.testSets }} - abstractionsPackageVersion: ${{ parameters.abstractionsPackageVersion }} useManagedSNI: ${{ parameters.useManagedSNI }} codeCovTargetFrameworks: ${{ parameters.codeCovTargetFrameworks }} referenceType: Package diff --git a/eng/pipelines/dotnet-sqlclient-ci-project-reference-pipeline.yml b/eng/pipelines/dotnet-sqlclient-ci-project-reference-pipeline.yml index 1217339c97..6169893061 100644 --- a/eng/pipelines/dotnet-sqlclient-ci-project-reference-pipeline.yml +++ b/eng/pipelines/dotnet-sqlclient-ci-project-reference-pipeline.yml @@ -54,11 +54,6 @@ parameters: # parameters are shown up in ADO UI in a build queue time type: object default: [1, 2, 3] -- name: abstractionsPackageVersion - displayName: Abstractions Package Version - type: string - default: 1.0.0 - - name: useManagedSNI displayName: | Use Managed/Native SNI on Windows, @@ -97,7 +92,6 @@ extends: targetFrameworksLinux: ${{ parameters.targetFrameworksLinux }} buildPlatforms: ${{ parameters.buildPlatforms }} testSets: ${{ parameters.testSets }} - abstractionsPackageVersion: ${{ parameters.abstractionsPackageVersion }} useManagedSNI: ${{ parameters.useManagedSNI }} codeCovTargetFrameworks: ${{ parameters.codeCovTargetFrameworks }} referenceType: Project diff --git a/eng/pipelines/dotnet-sqlclient-signing-pipeline.yml b/eng/pipelines/dotnet-sqlclient-signing-pipeline.yml index b494a87426..ca49e3d402 100644 --- a/eng/pipelines/dotnet-sqlclient-signing-pipeline.yml +++ b/eng/pipelines/dotnet-sqlclient-signing-pipeline.yml @@ -114,7 +114,7 @@ extends: sbom: enabled: ${{ not(parameters['isPreview']) }} packageName: Microsoft.Data.SqlClient - packageVersion: $(NugetPackageVersion) + packageVersion: $(mdsPackageVersion) policheck: enabled: ${{ not(parameters['isPreview']) }} break: true # always break the build on policheck issues. You can disable it by setting to 'false' diff --git a/eng/pipelines/jobs/build-akv-official-job.yml b/eng/pipelines/jobs/build-akv-official-job.yml index a4374b773b..cbed1e2cbc 100644 --- a/eng/pipelines/jobs/build-akv-official-job.yml +++ b/eng/pipelines/jobs/build-akv-official-job.yml @@ -5,6 +5,9 @@ ################################################################################# parameters: + - name: akvPackageVersion + type: string + - name: apiScanDllPath type: string @@ -17,12 +20,6 @@ parameters: - name: buildConfiguration type: string - - name: nugetPackageVersion - type: string - - - name: mdsPackageVersion - type: string - - name: publishSymbols type: boolean @@ -90,7 +87,7 @@ jobs: parameters: assemblyFileVersion: '${{ parameters.assemblyFileVersion }}' buildConfiguration: '${{ parameters.buildConfiguration }}' - mdsPackageVersion: '${{ parameters.mdsPackageVersion }}' + akvPackageVersion: '${{ parameters.akvPackageVersion }}' - ${{ each targetFramework in parameters.targetFrameworks }}: - template: ../steps/compound-extract-akv-apiscan-files-step.yml @@ -104,7 +101,7 @@ jobs: - template: ../steps/roslyn-analyzers-akv-step.yml@self parameters: buildConfiguration: '${{ parameters.buildConfiguration }}' - mdsPackageVersion: '${{ parameters.mdsPackageVersion }}' + akvPackageVersion: '${{ parameters.akvPackageVersion }}' - template: ../steps/compound-esrp-code-signing-step.yml@self parameters: @@ -120,7 +117,7 @@ jobs: parameters: buildConfiguration: '${{ parameters.buildConfiguration }}' generateSymbolsPackage: true # Always generate symbols, even if they are not published - packageVersion: '${{ parameters.nugetPackageVersion }}' + packageVersion: '${{ parameters.akvPackageVersion }}' nuspecPath: '$(REPO_ROOT)/tools/specs/add-ons/$(PACKAGE_NAME).nuspec' outputDirectory: '$(ARTIFACT_PATH)' referenceType: 'Package' @@ -138,7 +135,7 @@ jobs: - ${{ if parameters.publishSymbols }}: - template: ../steps/compound-publish-symbols-step.yml@self parameters: - artifactName: 'akv_symbols_$(System.TeamProject)_$(Build.Repository.Name)_$(Build.SourceBranchName)_${{ parameters.nugetPackageVersion }}_$(System.TimelineId)' + artifactName: 'akv_symbols_$(System.TeamProject)_$(Build.Repository.Name)_$(Build.SourceBranchName)_${{ parameters.akvPackageVersion }}_$(System.TimelineId)' azureSubscription: '${{ parameters.symbolsAzureSubscription }}' publishProjectName: '${{ parameters.symbolsPublishProjectName }}' packageName: '$(PACKAGE_NAME)' @@ -151,4 +148,4 @@ jobs: Windows_NT/${{ parameters.buildConfiguration }}.AnyCPU/AzureKeyVaultProvider/**/$(PACKAGE_NAME).pdb AnyOS/${{ parameters.buildConfiguration }}.AnyCPU/AzureKeyVaultProvider/**/$(PACKAGE_NAME).pdb uploadAccount: '${{ parameters.symbolsUploadAccount }}' - version: '${{ parameters.nugetPackageVersion }}' + version: '${{ parameters.akvPackageVersion }}' diff --git a/eng/pipelines/libraries/ci-build-variables.yml b/eng/pipelines/libraries/ci-build-variables.yml index 122281e083..ac39665b62 100644 --- a/eng/pipelines/libraries/ci-build-variables.yml +++ b/eng/pipelines/libraries/ci-build-variables.yml @@ -15,7 +15,9 @@ variables: value: 'net8.0' - name: SQLTarget value: 'localhost' - - name: NugetPackageVersion + - name: akvPackageVersion + value: 1.0.0.$(buildNumber) + - name: mdsPackageVersion value: $(Major).$(Minor)$(Patch)-pull.1$(buildnumber) - name: skipComponentGovernanceDetection value: true diff --git a/eng/pipelines/libraries/common-variables.yml b/eng/pipelines/libraries/common-variables.yml index 8fc6aec755..b7df898497 100644 --- a/eng/pipelines/libraries/common-variables.yml +++ b/eng/pipelines/libraries/common-variables.yml @@ -40,9 +40,9 @@ variables: - name: Revision value: '1' - - name: NugetPackageVersion + - name: mdsPackageVersion value: $(Major).$(Minor).$(Patch) - - name: PreviewNugetPackageVersion + - name: previewMdsPackageVersion value: $(Major).$(Minor).$(Patch)$(Preview)$(Revision).$(Build.BuildNumber) - name: AssemblyFileVersion value: '$(Major).$(Minor)$(Patch).$(Build.BuildNumber)' diff --git a/eng/pipelines/libraries/mds-validation-variables.yml b/eng/pipelines/libraries/mds-validation-variables.yml index d7723a059f..93dc0804ff 100644 --- a/eng/pipelines/libraries/mds-validation-variables.yml +++ b/eng/pipelines/libraries/mds-validation-variables.yml @@ -13,7 +13,7 @@ variables: - name: extractedNugetRootPath value: $(Build.SourcesDirectory)\$(TempFolderName)\Microsoft.Data.SqlClient - name: extractedNugetPath - value: $(extractedNugetRootPath).$(NugetPackageVersion) + value: $(extractedNugetRootPath).$(mdsPackageVersion) - name: expectedFolderNames value: lib,ref,runtimes - name: expectedDotnetVersions diff --git a/eng/pipelines/steps/compound-build-akv-step.yml b/eng/pipelines/steps/compound-build-akv-step.yml index 906dcfaf72..a547604a2c 100644 --- a/eng/pipelines/steps/compound-build-akv-step.yml +++ b/eng/pipelines/steps/compound-build-akv-step.yml @@ -7,16 +7,16 @@ # @TODO: This can probably be made generic and pass in the command lines for msbuild # BUT, they should be kept separate by now as we rebuild build.proj in parallel, we won't # affect >1 project at a time. -# @TODO: NugetPackageVersion should not be used for MDS package version +# @TODO: mdsPackageVersion should not be used for MDS package version parameters: - - name: assemblyFileVersion + - name: akvPackageVersion type: string - - name: buildConfiguration + - name: assemblyFileVersion type: string - - name: mdsPackageVersion + - name: buildConfiguration type: string steps: @@ -46,7 +46,7 @@ steps: msbuildArguments: >- -t:BuildAkv -p:AssemblyFileVersion=${{ parameters.assemblyFileVersion }} - -p:NugetPackageVersion=${{ parameters.mdsPackageVersion }} + -p:AkvPackageVersion=${{ parameters.akvPackageVersion }} -p:ReferenceType=Package -p:SigningKeyPath=$(Agent.TempDirectory)/netfxKeypair.snk diff --git a/eng/pipelines/steps/roslyn-analyzers-akv-step.yml b/eng/pipelines/steps/roslyn-analyzers-akv-step.yml index 0e05177d5a..c7acc84088 100644 --- a/eng/pipelines/steps/roslyn-analyzers-akv-step.yml +++ b/eng/pipelines/steps/roslyn-analyzers-akv-step.yml @@ -9,10 +9,10 @@ # affect >1 project at a time. parameters: - - name: buildConfiguration + - name: akvPackageVersion type: string - - name: mdsPackageVersion + - name: buildConfiguration type: string steps: @@ -25,7 +25,7 @@ steps: $(REPO_ROOT)/build.proj -t:BuildAkv -p:Configuration=${{ parameters.buildConfiguration }} - -p:NugetPackageVersion=${{ parameters.mdsPackageVersion }} + -p:AkvPackageVersion=${{ parameters.akvPackageVersion }} -p:ReferenceType=Package msBuildVersion: 17.0 setupCommandLinePicker: vs2022 diff --git a/eng/pipelines/variables/akv-official-variables.yml b/eng/pipelines/variables/akv-official-variables.yml index aaf8de7c5e..b22044548d 100644 --- a/eng/pipelines/variables/akv-official-variables.yml +++ b/eng/pipelines/variables/akv-official-variables.yml @@ -37,7 +37,5 @@ variables: # Compound Variables --------------------------------------------------- - name: assemblyFileVersion value: '${{ variables.versionMajor }}.${{ variables.versionMinor }}${{ variables.versionPatch }}.$(Build.BuildNumber)' - - name: nugetPackageVersion + - name: akvPackageVersion value: '${{ variables.versionMajor }}.${{ variables.versionMinor }}.${{ variables.versionPatch }}${{ variables.versionPreview }}' - - diff --git a/tools/props/Versions.props b/tools/props/Versions.props index 7981910485..ecc7ff50e7 100644 --- a/tools/props/Versions.props +++ b/tools/props/Versions.props @@ -6,7 +6,6 @@ 0 - @@ -32,13 +31,14 @@ 7.0.0 + $(MdsVersionDefault).$(BuildNumber)-dev + - $(MdsVersionDefault).$(BuildNumber)-dev @@ -68,7 +68,7 @@ - $(NugetPackageVersion) + $(AkvPackageVersion) - $(NugetPackageVersion) + $(MdsPackageVersion) diff --git a/tools/targets/GenerateNugetPackage.targets b/tools/targets/GenerateNugetPackage.targets index 4c8cea4159..7b674ebfdb 100644 --- a/tools/targets/GenerateNugetPackage.targets +++ b/tools/targets/GenerateNugetPackage.targets @@ -1,10 +1,10 @@ - + - $(NugetPackageVersion)-debug + $(MdsPackageVersion)-debug - + @@ -12,7 +12,7 @@ - + diff --git a/tools/targets/add-ons/GenerateAKVProviderNugetPackage.targets b/tools/targets/add-ons/GenerateAKVProviderNugetPackage.targets index 78da74bf32..aa50a32463 100644 --- a/tools/targets/add-ons/GenerateAKVProviderNugetPackage.targets +++ b/tools/targets/add-ons/GenerateAKVProviderNugetPackage.targets @@ -2,11 +2,11 @@ - $(NugetPackageVersion)-debug + $(AkvPackageVersion)-debug - + - + From 960a6c4d3642baf526214f99ef58dd944e5f0218 Mon Sep 17 00:00:00 2001 From: Paul Medynski <31868385+paulmedynski@users.noreply.github.com> Date: Thu, 18 Sep 2025 10:57:39 -0300 Subject: [PATCH 13/30] User Story 37654: Create Abstractions package - Fixes to Abstractions version number construction. - Fixes for some build.proj targets. --- build.proj | 4 +-- .../templates/steps/ci-project-build-step.yml | 6 ++-- .../Abstractions/src/Abstractions.csproj | 32 +++++++++++++------ tools/props/Versions.props | 21 ------------ 4 files changed, 28 insertions(+), 35 deletions(-) diff --git a/build.proj b/build.proj index ab45ccc1ac..fc22196202 100644 --- a/build.proj +++ b/build.proj @@ -52,7 +52,7 @@ - + @@ -117,7 +117,7 @@ diff --git a/eng/pipelines/common/templates/steps/ci-project-build-step.yml b/eng/pipelines/common/templates/steps/ci-project-build-step.yml index 6d3ec671a2..8353779198 100644 --- a/eng/pipelines/common/templates/steps/ci-project-build-step.yml +++ b/eng/pipelines/common/templates/steps/ci-project-build-step.yml @@ -52,7 +52,7 @@ steps: - ${{ if or(eq(parameters.operatingSystem, 'Windows'), eq(parameters.operatingSystem, 'deferedToRuntime')) }}: - ${{ if or(eq(parameters.build, 'MDS'), eq(parameters.build, 'all'), eq(parameters.build, 'allNoDocs')) }}: - task: MSBuild@1 - displayName: 'Restore nugets [Win]' + displayName: 'Restore [Win]' condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT')) inputs: solution: build.proj @@ -62,7 +62,7 @@ steps: - ${{ if eq(parameters.build, 'allNoDocs') }}: - task: MSBuild@1 - displayName: 'Build Driver [Win]' + displayName: 'Build Driver (no docs) [Win]' condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT')) inputs: solution: build.proj @@ -107,7 +107,7 @@ steps: - ${{ if or(eq(parameters.operatingSystem, 'Linux'), eq(parameters.operatingSystem, 'MacOS'), eq(parameters.operatingSystem, 'deferedToRuntime')) }}: - task: DotNetCoreCLI@2 - displayName: 'Build Driver [non-Win]' + displayName: 'Build Driver [${{ parameters.operatingSystem }}]' condition: and(succeeded(), ne(variables['Agent.OS'], 'Windows_NT')) inputs: command: custom diff --git a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/Abstractions.csproj b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/Abstractions.csproj index 1537c33630..8844458f1b 100644 --- a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/Abstractions.csproj +++ b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/Abstractions.csproj @@ -6,18 +6,31 @@ files. --> - + + + 1 + - $(AbstractionsPackageVersion) + $(AbstractionsPackageMajorVersion).0.0 + - $(PackageVersion).$(BuildNumber) + $(AbstractionsPackageVersion).$(BuildNumber) + + + $(AbstractionsPackageMajorVersion).0.0.0 @@ -35,9 +48,10 @@ Microsoft.Data.SqlClient.Extensions.Abstractions + $(AbstractionsPackageVersion) $(AbstractionsPackageAssemblyVersion) $(PackageVersion) $(AssemblyFileVersion) diff --git a/tools/props/Versions.props b/tools/props/Versions.props index ecc7ff50e7..e37e4c7fb1 100644 --- a/tools/props/Versions.props +++ b/tools/props/Versions.props @@ -6,27 +6,6 @@ 0 - - - - 1 - - - $(AbstractionsPackageMajorVersion).0.0 - - - $(AbstractionsPackageMajorVersion).0.0.0 - - 7.0.0 From dd39ffa901d1e9d75aada21db0417d171d420347 Mon Sep 17 00:00:00 2001 From: Paul Medynski <31868385+paulmedynski@users.noreply.github.com> Date: Thu, 18 Sep 2025 11:40:54 -0300 Subject: [PATCH 14/30] User Story 37654: Create Abstractions package - Fixes for Abstractions and AKV default versioning. --- .../Abstractions/src/Abstractions.csproj | 33 +++++++------------ tools/props/Versions.props | 8 ++++- 2 files changed, 19 insertions(+), 22 deletions(-) diff --git a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/Abstractions.csproj b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/Abstractions.csproj index 8844458f1b..367a35f8e1 100644 --- a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/Abstractions.csproj +++ b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/Abstractions.csproj @@ -12,19 +12,18 @@ 1 - $(AbstractionsPackageMajorVersion).0.0 - - $(AbstractionsPackageVersion).$(BuildNumber) + -dev + $(AbstractionsPackageMajorVersion).0.0.$(BuildNumber) Microsoft.Data.SqlClient.Extensions.Abstractions - - $(AbstractionsPackageVersion) + Microsoft.Data.SqlClient.Extensions.Abstractions + $(AbstractionsPackageAssemblyVersion) - $(PackageVersion) + $(AbstractionsPackageVersion) $(AssemblyFileVersion) - - Microsoft.Data.SqlClient.Extensions.Abstractions + $(AbstractionsPackageVersion)$(AbstractionsPackageVersionSuffix) @@ -79,11 +74,7 @@ specified above. --> - - + $(Version) $(PackagesDir) true snupkg diff --git a/tools/props/Versions.props b/tools/props/Versions.props index e37e4c7fb1..c8595f574a 100644 --- a/tools/props/Versions.props +++ b/tools/props/Versions.props @@ -31,6 +31,11 @@ 7.0.0.0 $(AssemblyFileVersion) + + $(MdsPackageVersion) @@ -47,7 +52,8 @@ - $(AkvPackageVersion) + 7.0.0 + $(AkvVersionDefault).$(BuildNumber)-dev @@ -25,6 +26,7 @@ all + diff --git a/src/Microsoft.Data.SqlClient/tests/UnitTests/Microsoft/Data/SqlClient/UdtSerialization/InvalidSerializationTest.cs b/src/Microsoft.Data.SqlClient/tests/UnitTests/Microsoft/Data/SqlClient/UdtSerialization/InvalidSerializationTest.cs new file mode 100644 index 0000000000..246d9a73f0 --- /dev/null +++ b/src/Microsoft.Data.SqlClient/tests/UnitTests/Microsoft/Data/SqlClient/UdtSerialization/InvalidSerializationTest.cs @@ -0,0 +1,62 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.IO; +using Microsoft.Data.SqlClient.Server; +using Microsoft.Data.SqlClient.UnitTests.UdtSerialization.SerializedTypes; +using Microsoft.SqlServer.Server; +using Xunit; + +namespace Microsoft.Data.SqlClient.UnitTests.UdtSerialization; + +/// +/// Attempts to serialize types which do not meet the requirements for either user-defined or native serialization. +/// +public sealed class InvalidSerializationTest : IDisposable +{ + private readonly MemoryStream _stream; + + /// + /// Initializes the MemoryStream used for all tests in this class. + /// + public InvalidSerializationTest() + { + _stream = new MemoryStream(); + } + + void IDisposable.Dispose() + { + _stream.Dispose(); + } + + /// + /// Attempts to serialize a class that does not have the SqlUserDefinedType attribute. Verifies that this fails. + /// + [Fact] + public void Serialize_MissingSqlUserDefinedTypeAttribute_Throws() + { + Action serialize = () => SerializationHelperSql9.Serialize(_stream, new ClassMissingSqlUserDefinedTypeAttribute()); + var exception = Assert.Throws(serialize); + + Assert.Equal($"'{typeof(ClassMissingSqlUserDefinedTypeAttribute).FullName}' is an invalid user defined type, reason: no UDT attribute.", exception.Message); + } + + /// + /// Attempts to serialize a class that has a SqlUserDefinedType attribute, but specifies a Format enumeration value of + /// Unknown. Verifies that this fails. + /// + [Fact] + public void Serialize_UnknownFormattedType_Throws() + { + Action serialize = () => SerializationHelperSql9.Serialize(_stream, new UnknownFormattedClass()); + var exception = Assert.Throws("Format", serialize); + +#if NET + Assert.Equal("The Format enumeration value, 0, is not supported by the format method. (Parameter 'Format')", exception.Message); +#else + Assert.Equal("The Format enumeration value, Unknown, is not supported by the format method.\r\nParameter name: Format", exception.Message); +#endif + } +} diff --git a/src/Microsoft.Data.SqlClient/tests/UnitTests/Microsoft/Data/SqlClient/UdtSerialization/NativeSerializationTest.cs b/src/Microsoft.Data.SqlClient/tests/UnitTests/Microsoft/Data/SqlClient/UdtSerialization/NativeSerializationTest.cs new file mode 100644 index 0000000000..3369a66985 --- /dev/null +++ b/src/Microsoft.Data.SqlClient/tests/UnitTests/Microsoft/Data/SqlClient/UdtSerialization/NativeSerializationTest.cs @@ -0,0 +1,491 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.Data.SqlClient.Server; +using Microsoft.Data.SqlClient.UnitTests.UdtSerialization.SerializedTypes; +using System; +using System.Collections.Generic; +using System.Data.SqlTypes; +using System.IO; +using Xunit; + +namespace Microsoft.Data.SqlClient.UnitTests.UdtSerialization; + +/// +/// Tests the serialization method defined by MS-SSCLRT. Ensures that combinations of primitives and custom types round-trip. +/// +/// +public sealed class NativeSerializationTest : IDisposable +{ + private readonly MemoryStream _stream; + + /// + /// Initializes the MemoryStream used for all tests in this class. + /// + public NativeSerializationTest() + { + _stream = new MemoryStream(); + } + + void IDisposable.Dispose() + { + _stream.Dispose(); + } + + /// + /// Provides a collection of test data representing non-null primitive type values and their corresponding + /// serialized byte arrays. + /// + /// + public static TheoryData SerializedNonNullPrimitiveTypeValues() => + new() + { + { + new BoolWrapperStruct { Field1 = true }, + new byte[] { 0x01 } + }, + { + new ByteWrapperStruct { Field1 = 0x20 }, + new byte[] { 0x20 } + }, + { + new SByteWrapperStruct { Field1 = -0x1 }, + new byte[] { 0x7F } + }, + { + new UShortWrapperStruct { Field1 = 0x8000 }, + new byte[] { 0x80, 0x00 } + }, + { + new ShortWrapperStruct { Field1 = 0x1234 }, + new byte[] { 0x92, 0x34 } + }, + { + new UIntWrapperStruct { Field1 = 0xFFFFFFFF }, + new byte[] { 0xFF, 0xFF, 0xFF, 0xFF } + }, + { + new IntWrapperStruct { Field1 = -0x12345678 }, + new byte[] { 0x6D, 0xCB, 0xA9, 0x88 } + }, + { + new ULongWrapperStruct { Field1 = ulong.MaxValue }, + new byte[] { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } + }, + { + new LongWrapperStruct { Field1 = long.MinValue }, + new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } + }, + { + new FloatWrapperStruct { Field1 = -0 }, + new byte[] { 0x80, 0x00, 0x00, 0x00 } + }, + { + new DoubleWrapperStruct { Field1 = Math.PI }, + new byte[] { 0xC0, 0x09, 0x21, 0xFB, 0x54, 0x44, 0x2D, 0x18 } + }, + { + new SqlByteWrapperStruct { Field1 = 0x20 }, + new byte[] { 0x01, 0x20 } + }, + { + new SqlInt16WrapperStruct { Field1 = 0x1234 }, + new byte[] { 0x01, 0x92, 0x34 } + }, + { + new SqlInt32WrapperStruct { Field1 = -0x12345678 }, + new byte[] { 0x01, 0x6D, 0xCB, 0xA9, 0x88 } + }, + { + new SqlInt64WrapperStruct { Field1 = long.MinValue }, + new byte[] { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } + }, + { + new SqlBooleanWrapperStruct { Field1 = false }, + new byte[] { 0x01 } + }, + { + new SqlSingleWrapperStruct { Field1 = -1 }, + new byte[] { 0x01, 0x40, 0x7F, 0xFF, 0xFF } + }, + { + new SqlDoubleWrapperStruct { Field1 = -Math.PI }, + new byte[] { 0x01, 0x3F, 0xF6, 0xDE, 0x04, 0xAB, 0xBB, 0xD2, 0xE7 } + }, + { + new SqlDateTimeWrapperStruct { Field1 = new DateTime(2000, 1, 1, 12, 34, 56, 500) }, + new byte[] { 0x01, 0x80, 0x00, 0x8E, 0xAC, 0x80, 0xCF, 0x59, 0xD6 } + }, + { + new SqlMoneyWrapperStruct { Field1 = 1.10m }, + new byte[] { 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2A, 0xF8 } + } + }; + + /// + /// Provides a collection of test data representing serialized values of nested non-null primitive types. + /// + /// + public static TheoryData SerializedNestedNonNullPrimitiveTypeValues() => + new() + { + { + new NestedBoolWrapperStruct { Field1 = true, Field2 = new BoolWrapperStruct { Field1 = false } }, + new byte[] + { + // Field1 + 0x01, + // Field2 + 0x00 + } + }, + { + new NestedByteWrapperStruct { Field1 = 0x20, Field2 = new ByteWrapperStruct { Field1 = 0x30 } }, + new byte[] + { + // Field1 + 0x20, + // Field2 + 0x30 + } + }, + { + new NestedSByteWrapperStruct { Field1 = -0x01, Field2 = new SByteWrapperStruct { Field1 = 0x01 } }, + new byte[] + { + // Field1 + 0x7F, + // Field2 + 0x81 + } + }, + { + new NestedUShortWrapperStruct { Field1 = 0x8000, Field2 = new UShortWrapperStruct { Field1 = 0x8014 } }, + new byte[] + { + // Field1 + 0x80, 0x00, + // Field2.Field1 + 0x80, 0x14 + } + }, + { + new NestedShortWrapperStruct { Field1 = 0x1234, Field2 = new ShortWrapperStruct { Field1 = 0x4321 } }, + new byte[] + { + // Field1 + 0x92, 0x34, + // Field2.Field1 + 0xC3, 0x21 + } + }, + { + new NestedUIntWrapperStruct { Field1 = 0xFFFFFFFF, Field2 = new UIntWrapperStruct { Field1 = 0x00000000 } }, + new byte[] + { + // Field1 + 0xFF, 0xFF, 0xFF, 0xFF, + // Field2.Field1 + 0x00, 0x00, 0x00, 0x00 + } + }, + { + new NestedIntWrapperStruct { Field1 = -0x12345678, Field2 = new IntWrapperStruct { Field1 = 0x12345678 } }, + new byte[] + { + /// Field1 + 0x6D, 0xCB, 0xA9, 0x88, + // Field2.Field1 + 0x92, 0x34, 0x56, 0x78 + } + }, + { + new NestedULongWrapperStruct { Field1 = ulong.MaxValue, Field2 = new ULongWrapperStruct { Field1 = long.MaxValue } }, + new byte[] + { + // Field1 + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + // Field2.Field1 + 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF + } + }, + { + new NestedLongWrapperStruct { Field1 = long.MinValue, Field2 = new LongWrapperStruct { Field1 = long.MaxValue } }, + new byte[] + { + // Field1 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // Field2.Field1 + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF + } + }, + { + new NestedFloatWrapperStruct { Field1 = -0, Field2 = new FloatWrapperStruct { Field1 = +0 } }, + new byte[] + { + // Field1 + 0x80, 0x00, 0x00, 0x00, + // Field2.Field1 + 0x80, 0x00, 0x00, 0x00 + } + }, + { + new NestedDoubleWrapperStruct { Field1 = Math.PI, Field2 = new DoubleWrapperStruct { Field1 = Math.PI } }, + new byte[] + { + // Field1 + 0xC0, 0x09, 0x21, 0xFB, 0x54, 0x44, 0x2D, 0x18, + // Field2.Field1 + 0xC0, 0x09, 0x21, 0xFB, 0x54, 0x44, 0x2D, 0x18 + } + }, + { + new NestedSqlByteWrapperStruct { Field1 = 0x20, Field2 = new SqlByteWrapperStruct { Field1 = 0x30 } }, + new byte[] + { + // Field1 + 0x01, 0x20, + // Field2.Field1 + 0x01, 0x30 + } + }, + { + new NestedSqlInt16WrapperStruct { Field1 = 0x1234, Field2 = new SqlInt16WrapperStruct { Field1 = 0x4321 } }, + new byte[] + { + // Field1 + 0x01, 0x92, 0x34, + // Field2.Field1 + 0x01, 0xC3, 0x21 + } + }, + { + new NestedSqlInt32WrapperStruct { Field1 = -0x12345678, Field2 = new SqlInt32WrapperStruct { Field1 = 0x12345678 } }, + new byte[] + { + // Field1 + 0x01, 0x6D, 0xCB, 0xA9, 0x88, + // Field2.Field1 + 0x01, 0x92, 0x34, 0x56, 0x78 + } + }, + { + new NestedSqlInt64WrapperStruct { Field1 = long.MinValue, Field2 = new SqlInt64WrapperStruct { Field1 = long.MaxValue } }, + new byte[] + { + // Field1 + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // Field2.Field1 + 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF + } + }, + { + new NestedSqlBooleanWrapperStruct { Field1 = false, Field2 = new SqlBooleanWrapperStruct { Field1 = true } }, + new byte[] + { + // Field1 + 0x01, + // Field2.Field1 + 0x02 + } + }, + { + new NestedSqlSingleWrapperStruct { Field1 = -0, Field2 = new SqlSingleWrapperStruct { Field1 = +0 } }, + new byte[] + { + // Field1 + 0x01, 0x80, 0x00, 0x00, 0x00, + // Field2.Field1 + 0x01, 0x80, 0x00, 0x00, 0x00 + } + }, + { + new NestedSqlDoubleWrapperStruct { Field1 = Math.PI, Field2 = new SqlDoubleWrapperStruct { Field1 = Math.PI } }, + new byte[] + { + // Field1 + 0x01, 0xC0, 0x09, 0x21, 0xFB, 0x54, 0x44, 0x2D, 0x18, + // Field2.Field1 + 0x01, 0xC0, 0x09, 0x21, 0xFB, 0x54, 0x44, 0x2D, 0x18 + } + }, + { + new NestedSqlDateTimeWrapperStruct { Field1 = new DateTime(2000, 1, 1, 12, 34, 56, 500), Field2 = new SqlDateTimeWrapperStruct { Field1 = new DateTime(2000, 1, 1) } }, + new byte[] + { + // Field1 + 0x01, 0x80, 0x00, 0x8E, 0xAC, 0x80, 0xCF, 0x59, 0xD6, + // Field2.Field1 + 0x01, 0x80, 0x00, 0x8E, 0xAC, 0x80, 0x00, 0x00, 0x00 + } + }, + { + new NestedSqlMoneyWrapperStruct { Field1 = 1.10m, Field2 = new SqlMoneyWrapperStruct { Field1 = -2.55m } }, + new byte[] + { + // Field1 + 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2A, 0xF8, + // Field2.Field1 + 0x01, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x9C, 0x64 + } + } + }; + + /// + /// Provides a collection of test data representing serialized null values for various primitive types. + /// + /// + public static TheoryData SerializedNullPrimitiveTypeValues() => + new() + { + { + new SqlByteWrapperStruct { Field1 = SqlByte.Null }, + new byte[] { 0x00, 0x00 } + }, + { + new SqlInt16WrapperStruct { Field1 = SqlInt16.Null }, + new byte[] { 0x00, 0x80, 0x00 } + }, + { + new SqlInt32WrapperStruct { Field1 = SqlInt32.Null }, + new byte[] { 0x00, 0x80, 0x00, 0x00, 0x00 } + }, + { + new SqlInt64WrapperStruct { Field1 = SqlInt64.Null }, + new byte[] { 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } + }, + { + new SqlBooleanWrapperStruct { Field1 = SqlBoolean.Null }, + new byte[] { 0x00 } + }, + { + new SqlSingleWrapperStruct { Field1 = SqlSingle.Null }, + new byte[] { 0x00, 0x80, 0x00, 0x00, 0x00 } + }, + { + new SqlDoubleWrapperStruct { Field1 = SqlDouble.Null }, + new byte[] { 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } + }, + { + new SqlDateTimeWrapperStruct { Field1 = SqlDateTime.Null }, + new byte[] { 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00 } + }, + { + new SqlMoneyWrapperStruct { Field1 = SqlMoney.Null }, + new byte[] { 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } + } + }; + + /// + /// Attempts to serialize various structs containing non-null primitive types. + /// Verifies that the method does not throw, that serialized byte output is correct, and that the value round-trips. + /// + /// Primitive to serialize and to compare against. + /// Expected byte output. + [Theory] + [MemberData(nameof(SerializedNonNullPrimitiveTypeValues))] + public void Serialize_PrimitiveType_Roundtrips(object primitive, byte[] expectedValue) => + RoundtripType(primitive, expectedValue); + + /// + /// Attempts to serialize a nested struct hierarchy containing non-null primitive types. + /// Verifies that the method does not throw, that serialized byte output is correct, and that the value round-trips. + /// + /// Primitive to serialize and to compare against. + /// Expected byte output. + [Theory] + [MemberData(nameof(SerializedNestedNonNullPrimitiveTypeValues))] + public void Serialize_NestedPrimitiveType_Roundtrips(object primitive, byte[] expectedValue) => + RoundtripType(primitive, expectedValue); + + /// + /// Attempts to serialize various structs containing null-valued primitive types. + /// Verifies that the method does not throw, that serialized byte output is correct, and that the value round-trips. + /// + /// Primitive to serialize and to compare against. + /// Expected byte output. + [Theory] + [MemberData(nameof(SerializedNullPrimitiveTypeValues))] + public void Serialize_NullPrimitiveType_Roundtrips(object primitive, byte[] expectedValue) => + RoundtripType(primitive, expectedValue); + + /// + /// Attempts to serialize an instance of a class. + /// + /// + [Fact] + public void Serialize_TopLevelClass_Succeeds() + { + NestedBoolWrapperClass validWrapper = new() + { + Field1 = true, + Field2 = new BoolWrapperStruct() { Field1 = true } + }; + + SerializationHelperSql9.Serialize(_stream, validWrapper); + } + + /// + /// Attempts to serialize a field referring to an instance of a class. + /// Verifies that this fails, and that Native format serialization only operates with primitive types and value types containing these. + /// + /// + [Fact] + public void Serialize_NestedClass_Throws() + { + InvalidNestedBoolWrapperClass invalidWrapper = new() + { + Field1 = true, + Field2 = new BoolWrapperClass() { Field1 = true } + }; + + var ex = Assert.Throws(() => SerializationHelperSql9.Serialize(_stream, invalidWrapper)); + string expectedException = StringsHelper.GetString(Strings.SQL_CannotCreateNormalizer, invalidWrapper.Field2.GetType().FullName); + + Assert.Equal(expectedException, ex.Message); + } + + /// + /// Attempts to serialize a struct containing non-primitive value types. + /// Verifies that this fails. + /// + [Fact] + public void Serialize_NonPrimitiveType_Throws() + { + InvalidIntPtrAndByteWrapperStruct invalidWrapper = new() + { + Field1 = 1, + Field2 = IntPtr.Zero + }; + + var ex = Assert.Throws(() => SerializationHelperSql9.Serialize(_stream, invalidWrapper)); + string expectedException = StringsHelper.GetString(Strings.SQL_CannotCreateNormalizer, invalidWrapper.Field2.GetType().FullName); + + Assert.Equal(expectedException, ex.Message); + } + + /// + /// Serializes an object, verifies the value and the size of the object, then roundtrips it and verifies the result is identical. + /// + /// Object to serialize. + /// Expected serialization output. + private void RoundtripType(object inputValue, byte[] expectedValue) + { + int typeSize = SerializationHelperSql9.SizeInBytes(inputValue.GetType()); + int objectSize = SerializationHelperSql9.SizeInBytes(inputValue); + int maxTypeSize = SerializationHelperSql9.GetUdtMaxLength(inputValue.GetType()); + + SerializationHelperSql9.Serialize(_stream, inputValue); + _stream.Seek(0, SeekOrigin.Begin); + object readPrimitive = SerializationHelperSql9.Deserialize(_stream, inputValue.GetType()); + + // For native formatting, the type size, the object size and the maximum object size will always be identical + Assert.Equal(typeSize, objectSize); + Assert.Equal(expectedValue.Length, typeSize); + Assert.Equal(typeSize, maxTypeSize); + + Assert.Equal(expectedValue, _stream.ToArray()); + Assert.Equal(inputValue, readPrimitive); + } +} diff --git a/src/Microsoft.Data.SqlClient/tests/UnitTests/Microsoft/Data/SqlClient/UdtSerialization/SerializedTypes.cs b/src/Microsoft.Data.SqlClient/tests/UnitTests/Microsoft/Data/SqlClient/UdtSerialization/SerializedTypes.cs new file mode 100644 index 0000000000..a02c213e01 --- /dev/null +++ b/src/Microsoft.Data.SqlClient/tests/UnitTests/Microsoft/Data/SqlClient/UdtSerialization/SerializedTypes.cs @@ -0,0 +1,335 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.SqlServer.Server; +using System; +using System.Data.SqlTypes; +using System.IO; +using System.Runtime.InteropServices; + +namespace Microsoft.Data.SqlClient.UnitTests.UdtSerialization.SerializedTypes; + +// Simple cases: a struct containing one of the designated primitive types +[SqlUserDefinedType(Format.Native)] +[StructLayout(LayoutKind.Sequential)] +internal struct BoolWrapperStruct { public bool Field1; } + +[SqlUserDefinedType(Format.Native)] +[StructLayout(LayoutKind.Sequential)] +internal struct ByteWrapperStruct { public byte Field1; } + +[SqlUserDefinedType(Format.Native)] +[StructLayout(LayoutKind.Sequential)] +internal struct SByteWrapperStruct { public sbyte Field1; } + +[SqlUserDefinedType(Format.Native)] +[StructLayout(LayoutKind.Sequential)] +internal struct UShortWrapperStruct { public ushort Field1; } + +[SqlUserDefinedType(Format.Native)] +[StructLayout(LayoutKind.Sequential)] +internal struct ShortWrapperStruct { public short Field1; } + +[SqlUserDefinedType(Format.Native)] +[StructLayout(LayoutKind.Sequential)] +internal struct UIntWrapperStruct { public uint Field1; } + +[SqlUserDefinedType(Format.Native)] +[StructLayout(LayoutKind.Sequential)] +internal struct IntWrapperStruct { public int Field1; } + +[SqlUserDefinedType(Format.Native)] +[StructLayout(LayoutKind.Sequential)] +internal struct ULongWrapperStruct { public ulong Field1; } + +[SqlUserDefinedType(Format.Native)] +[StructLayout(LayoutKind.Sequential)] +internal struct LongWrapperStruct { public long Field1; } + +[SqlUserDefinedType(Format.Native)] +[StructLayout(LayoutKind.Sequential)] +internal struct FloatWrapperStruct { public float Field1; } + +[SqlUserDefinedType(Format.Native)] +[StructLayout(LayoutKind.Sequential)] +internal struct DoubleWrapperStruct { public double Field1; } + +[SqlUserDefinedType(Format.Native)] +[StructLayout(LayoutKind.Sequential)] +internal struct SqlByteWrapperStruct { public SqlByte Field1; } + +[SqlUserDefinedType(Format.Native)] +[StructLayout(LayoutKind.Sequential)] +internal struct SqlInt16WrapperStruct { public SqlInt16 Field1; } + +[SqlUserDefinedType(Format.Native)] +[StructLayout(LayoutKind.Sequential)] +internal struct SqlInt32WrapperStruct { public SqlInt32 Field1; } + +[SqlUserDefinedType(Format.Native)] +[StructLayout(LayoutKind.Sequential)] +internal struct SqlInt64WrapperStruct { public SqlInt64 Field1; } + +[SqlUserDefinedType(Format.Native)] +[StructLayout(LayoutKind.Sequential)] +internal struct SqlBooleanWrapperStruct { public SqlBoolean Field1; } + +[SqlUserDefinedType(Format.Native)] +[StructLayout(LayoutKind.Sequential)] +internal struct SqlSingleWrapperStruct { public SqlSingle Field1; } + +[SqlUserDefinedType(Format.Native)] +[StructLayout(LayoutKind.Sequential)] +internal struct SqlDoubleWrapperStruct { public SqlDouble Field1; } + +[SqlUserDefinedType(Format.Native)] +[StructLayout(LayoutKind.Sequential)] +internal struct SqlDateTimeWrapperStruct { public SqlDateTime Field1; } + +[SqlUserDefinedType(Format.Native)] +[StructLayout(LayoutKind.Sequential)] +internal struct SqlMoneyWrapperStruct { public SqlMoney Field1; } + + +// Success case: a class containing one of the designated primitive types +[SqlUserDefinedType(Format.Native)] +[StructLayout(LayoutKind.Sequential)] +internal class BoolWrapperClass { public bool Field1; } + +// Success case: a struct containing one designated primitive type and one nested struct +[SqlUserDefinedType(Format.Native)] +[StructLayout(LayoutKind.Sequential)] +internal struct NestedBoolWrapperStruct { public bool Field1; public BoolWrapperStruct Field2; } + +[SqlUserDefinedType(Format.Native)] +[StructLayout(LayoutKind.Sequential)] +internal struct NestedByteWrapperStruct { public byte Field1; public ByteWrapperStruct Field2; } + +[SqlUserDefinedType(Format.Native)] +[StructLayout(LayoutKind.Sequential)] +internal struct NestedSByteWrapperStruct { public sbyte Field1; public SByteWrapperStruct Field2; } + +[SqlUserDefinedType(Format.Native)] +[StructLayout(LayoutKind.Sequential)] +internal struct NestedUShortWrapperStruct { public ushort Field1; public UShortWrapperStruct Field2; } + +[SqlUserDefinedType(Format.Native)] +[StructLayout(LayoutKind.Sequential)] +internal struct NestedShortWrapperStruct { public short Field1; public ShortWrapperStruct Field2; } + +[SqlUserDefinedType(Format.Native)] +[StructLayout(LayoutKind.Sequential)] +internal struct NestedUIntWrapperStruct { public uint Field1; public UIntWrapperStruct Field2; } + +[SqlUserDefinedType(Format.Native)] +[StructLayout(LayoutKind.Sequential)] +internal struct NestedIntWrapperStruct { public int Field1; public IntWrapperStruct Field2; } + +[SqlUserDefinedType(Format.Native)] +[StructLayout(LayoutKind.Sequential)] +internal struct NestedULongWrapperStruct { public ulong Field1; public ULongWrapperStruct Field2; } + +[SqlUserDefinedType(Format.Native)] +[StructLayout(LayoutKind.Sequential)] +internal struct NestedLongWrapperStruct { public long Field1; public LongWrapperStruct Field2; } + +[SqlUserDefinedType(Format.Native)] +[StructLayout(LayoutKind.Sequential)] +internal struct NestedFloatWrapperStruct { public float Field1; public FloatWrapperStruct Field2; } + +[SqlUserDefinedType(Format.Native)] +[StructLayout(LayoutKind.Sequential)] +internal struct NestedDoubleWrapperStruct { public double Field1; public DoubleWrapperStruct Field2; } + +[SqlUserDefinedType(Format.Native)] +[StructLayout(LayoutKind.Sequential)] +internal struct NestedSqlByteWrapperStruct { public SqlByte Field1; public SqlByteWrapperStruct Field2; } + +[SqlUserDefinedType(Format.Native)] +[StructLayout(LayoutKind.Sequential)] +internal struct NestedSqlInt16WrapperStruct { public SqlInt16 Field1; public SqlInt16WrapperStruct Field2; } + +[SqlUserDefinedType(Format.Native)] +[StructLayout(LayoutKind.Sequential)] +internal struct NestedSqlInt32WrapperStruct { public SqlInt32 Field1; public SqlInt32WrapperStruct Field2; } + +[SqlUserDefinedType(Format.Native)] +[StructLayout(LayoutKind.Sequential)] +internal struct NestedSqlInt64WrapperStruct { public SqlInt64 Field1; public SqlInt64WrapperStruct Field2; } + +[SqlUserDefinedType(Format.Native)] +[StructLayout(LayoutKind.Sequential)] +internal struct NestedSqlBooleanWrapperStruct { public SqlBoolean Field1; public SqlBooleanWrapperStruct Field2; } + +[SqlUserDefinedType(Format.Native)] +[StructLayout(LayoutKind.Sequential)] +internal struct NestedSqlSingleWrapperStruct { public SqlSingle Field1; public SqlSingleWrapperStruct Field2; } + +[SqlUserDefinedType(Format.Native)] +[StructLayout(LayoutKind.Sequential)] +internal struct NestedSqlDoubleWrapperStruct { public SqlDouble Field1; public SqlDoubleWrapperStruct Field2; } + +[SqlUserDefinedType(Format.Native)] +[StructLayout(LayoutKind.Sequential)] +internal struct NestedSqlDateTimeWrapperStruct { public SqlDateTime Field1; public SqlDateTimeWrapperStruct Field2; } + +[SqlUserDefinedType(Format.Native)] +[StructLayout(LayoutKind.Sequential)] +internal struct NestedSqlMoneyWrapperStruct { public SqlMoney Field1; public SqlMoneyWrapperStruct Field2; } + + +// Success case: a class containing one designated primitive type and a nested struct +[SqlUserDefinedType(Format.Native)] +[StructLayout(LayoutKind.Sequential)] +internal class NestedBoolWrapperClass { public bool Field1; public BoolWrapperStruct Field2; } + +// Failure case: a struct or a class containing one designated primitive type and a nested class +[SqlUserDefinedType(Format.Native)] +[StructLayout(LayoutKind.Sequential)] +internal class InvalidNestedBoolWrapperClass { public bool Field1; public BoolWrapperClass? Field2; } + +// Failure case: a struct or a class containing a field which is not a designated primitive type +[SqlUserDefinedType(Format.Native)] +[StructLayout(LayoutKind.Sequential)] +internal struct InvalidIntPtrAndByteWrapperStruct { public byte Field1; public IntPtr Field2; } + +// Success case: a struct or a class implementing IBinarySerialize which would not otherwise be serializable +internal interface IFormattingProgress +{ + bool ParameterlessConstructorInvoked { get; } + bool ReadInvoked { get; } + bool WriteInvoked { get; } +} + +[SqlUserDefinedType(Format.UserDefined, MaxByteSize = 11)] +internal struct UserDefinedFormattedStruct : IBinarySerialize, IFormattingProgress, IEquatable +{ + public IntPtr Field1; + public bool ParameterlessConstructorInvoked { get; } + public bool ReadInvoked { get; private set; } + public bool WriteInvoked { get; private set; } + + public UserDefinedFormattedStruct() + { + ParameterlessConstructorInvoked = true; + } + + public UserDefinedFormattedStruct(IntPtr field1) + { + Field1 = field1; + } + + public void Read(BinaryReader r) + { + Field1 = IntPtr.Size switch + { + sizeof(uint) => (IntPtr)r.ReadUInt32(), + sizeof(ulong) => (IntPtr)r.ReadUInt64(), + _ => throw new Exception("Invalid IntPtr size") + }; + + ReadInvoked = true; + } + + public void Write(BinaryWriter w) + { + if (IntPtr.Size == sizeof(uint)) + { + w.Write((uint)Field1); + } + else if (IntPtr.Size == sizeof(ulong)) + { + w.Write((ulong)Field1); + } + else + { + throw new Exception("Invalid IntPtr size"); + } + + WriteInvoked = true; + } + + public bool Equals(UserDefinedFormattedStruct other) + => other.Field1 == Field1; +} + +[SqlUserDefinedType(Format.UserDefined, MaxByteSize = 11)] +internal class UserDefinedFormattedClass : IBinarySerialize, IFormattingProgress, IEquatable +{ + public IntPtr Field1; + public bool ParameterlessConstructorInvoked { get; } + public bool ReadInvoked { get; private set; } + public bool WriteInvoked { get; private set; } + + public UserDefinedFormattedClass() + { + ParameterlessConstructorInvoked = true; + } + + public UserDefinedFormattedClass(IntPtr field1) + { + Field1 = field1; + } + + public void Read(BinaryReader r) + { + Field1 = IntPtr.Size switch + { + sizeof(uint) => (IntPtr)r.ReadUInt32(), + sizeof(ulong) => (IntPtr)r.ReadUInt64(), + _ => throw new Exception("Invalid IntPtr size") + }; + + ReadInvoked = true; + } + + public void Write(BinaryWriter w) + { + if (IntPtr.Size == sizeof(uint)) + { + w.Write((uint)Field1); + } + else if (IntPtr.Size == sizeof(ulong)) + { + w.Write((ulong)Field1); + } + else + { + throw new Exception("Invalid IntPtr size"); + } + + WriteInvoked = true; + } + + public bool Equals(UserDefinedFormattedClass? other) + => other is not null && other.Field1 == Field1; +} + +// Failure cases: type does not have a public constructor, does not implement IBinarySerialize, does not have a SqlUserDefinedType attribute, +// or has a SqlUserDefinedType attribute with a Format of Unknown. + +[SqlUserDefinedType(Format.UserDefined)] +internal class UserDefinedMissingPublicConstructor : IBinarySerialize +{ + public UserDefinedMissingPublicConstructor(bool _) { } + + public void Read(BinaryReader r) { } + + public void Write(BinaryWriter w) { } +} + +[SqlUserDefinedType(Format.UserDefined)] +internal class UserDefinedDoesNotImplementIBinarySerialize +{ + public UserDefinedDoesNotImplementIBinarySerialize() { } +} + +internal class ClassMissingSqlUserDefinedTypeAttribute +{ +} + +[SqlUserDefinedType(Format.Unknown)] +internal class UnknownFormattedClass +{ +} diff --git a/src/Microsoft.Data.SqlClient/tests/UnitTests/Microsoft/Data/SqlClient/UdtSerialization/UserDefinedSerializationTest.cs b/src/Microsoft.Data.SqlClient/tests/UnitTests/Microsoft/Data/SqlClient/UdtSerialization/UserDefinedSerializationTest.cs new file mode 100644 index 0000000000..4d7ea799fd --- /dev/null +++ b/src/Microsoft.Data.SqlClient/tests/UnitTests/Microsoft/Data/SqlClient/UdtSerialization/UserDefinedSerializationTest.cs @@ -0,0 +1,123 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.Data.SqlClient.Server; +using Microsoft.Data.SqlClient.UnitTests.UdtSerialization.SerializedTypes; +using System; +using System.Collections.Generic; +using System.IO; +using Xunit; + +namespace Microsoft.Data.SqlClient.UnitTests.UdtSerialization; + +/// +/// Tests the user-defined UDT serialization method. Verifies that custom types round-trip. +/// +public sealed class UserDefinedSerializationTest : IDisposable +{ + private readonly MemoryStream _stream; + + /// + /// Initializes the MemoryStream used for all tests in this class. + /// + public UserDefinedSerializationTest() + { + _stream = new MemoryStream(); + } + + void IDisposable.Dispose() + { + _stream.Dispose(); + } + + /// + /// Attempts to serialize and deserialize an instance of a struct with a user-defined serialization method. + /// + /// + [Fact] + public void Serialize_Struct_Roundtrips() => + RoundtripType(new UserDefinedFormattedStruct((IntPtr)0x12345678)); + + /// + /// Attempts to serialize and deserialize an instance of a class with a user-defined serialization method. + /// + /// + [Fact] + public void Serialize_Class_Roundtrips() => + RoundtripType(new UserDefinedFormattedClass((IntPtr)0x12345678)); + + /// + /// Attempts to deserialize an instance of a type with a user-defined serialization method but without a public + /// parameterless constructor. Verifies that this fails. + /// + [Fact] + public void Deserialize_MissingPublicParameterlessConstructor_Throws() + { + SerializationHelperSql9.Serialize(_stream, new UserDefinedMissingPublicConstructor(true)); + _stream.Seek(0, SeekOrigin.Begin); + + Action deserialize = () => SerializationHelperSql9.Deserialize(_stream, typeof(UserDefinedMissingPublicConstructor)); + + Assert.Throws(deserialize); + } + + /// + /// Attempts to deserialize an instance of a type with a user-defined serialization method but which does not, + /// implement IBinarySerialize. Verifies that this fails. + /// + [Fact] + public void Serialize_DoesNotImplementIBinarySerialize_Throws() + { + Action serialize = () => SerializationHelperSql9.Serialize(_stream, new UserDefinedDoesNotImplementIBinarySerialize()); + + Assert.Throws(serialize); + } + + private void RoundtripType(T userObject) + where T : IFormattingProgress + { + int typeSize = SerializationHelperSql9.SizeInBytes(userObject.GetType()); + int objectSize = SerializationHelperSql9.SizeInBytes(userObject); + int maxTypeSize = SerializationHelperSql9.GetUdtMaxLength(userObject.GetType()); + + SerializationHelperSql9.Serialize(_stream, userObject); + _stream.Seek(0, SeekOrigin.Begin); + byte[] serializedValue = _stream.ToArray(); + T readInstance = (T)SerializationHelperSql9.Deserialize(_stream, userObject.GetType()); + + // If this is a struct, it will have been copied by value and the write to WriteInvoked will have been made + // to another copy of our object + if (!typeof(T).IsValueType) + { + Assert.True(userObject.WriteInvoked); + } + + Assert.Equal(IntPtr.Size, typeSize); + Assert.Equal(IntPtr.Size, objectSize); + Assert.Equal(11, maxTypeSize); + + Assert.Equal(IntPtr.Size, serializedValue.Length); + if (IntPtr.Size == 8) + { + Assert.Equal([0x78, 0x56, 0x34, 0x12, 0x00, 0x00, 0x00, 0x00], serializedValue); + } + else if (IntPtr.Size == 4) + { + Assert.Equal([0x78, 0x56, 0x34, 0x12], serializedValue); + } + else + { + Assert.Fail("Invalid IntPtr size."); + } + + // In .NET Framework, Activator.CreateInstance does not invoke a struct's parameterless constructor +#if NET + Assert.NotEqual(userObject.ParameterlessConstructorInvoked, readInstance.ParameterlessConstructorInvoked); + Assert.True(readInstance.ParameterlessConstructorInvoked); +#endif + Assert.True(readInstance.ReadInvoked); + + Assert.Equal(userObject, readInstance); + } +} diff --git a/src/Microsoft.Data.SqlClient/tests/UnitTests/Microsoft/Data/SqlTypes/SqlTypeWorkaroundsTests.cs b/src/Microsoft.Data.SqlClient/tests/UnitTests/Microsoft/Data/SqlTypes/SqlTypeWorkaroundsTests.cs index f7cd1811ed..cf97f21a39 100644 --- a/src/Microsoft.Data.SqlClient/tests/UnitTests/Microsoft/Data/SqlTypes/SqlTypeWorkaroundsTests.cs +++ b/src/Microsoft.Data.SqlClient/tests/UnitTests/Microsoft/Data/SqlTypes/SqlTypeWorkaroundsTests.cs @@ -20,7 +20,7 @@ public class SqlTypeWorkaroundsTests #region SqlBinary public static TheoryData ByteArrayToSqlBinary_NonNullInput_Data => - new TheoryData + new() { Array.Empty(), new byte[] { 1, 2, 3, 4}, @@ -53,7 +53,7 @@ public void ByteArrayToSqlBinary_NullInput() #region SqlDecimal public static TheoryData SqlDecimalWriteTdsValue_NonNullInput_Data => - new TheoryData + new() { SqlDecimal.MinValue, new SqlDecimal(-1.2345678), @@ -102,7 +102,7 @@ public void SqlDecimalWriteTdsValue_NullInput() #region SqlGuid public static TheoryData ByteArrayToSqlGuid_InvalidInput_Data => - new TheoryData + new() { null, Array.Empty(), @@ -122,7 +122,7 @@ public void ByteArrayToSqlGuid_InvalidInput(byte[]? input) } public static TheoryData ByteArrayToSqlGuid_ValidInput_Data => - new TheoryData + new() { new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 } @@ -145,7 +145,7 @@ public void ByteArrayToSqlGuid_ValidInput(byte[] input) #region SqlMoney public static TheoryData LongToSqlMoney_Data => - new TheoryData + new() { { long.MinValue, SqlMoney.MinValue }, { (long)((decimal)-123000000 / 10000), new SqlMoney(-1.23) }, @@ -166,7 +166,7 @@ public void LongToSqlMoney(long input, SqlMoney expected) } public static TheoryData SqlMoneyToLong_NonNullInput_Data => - new TheoryData + new() { { SqlMoney.MinValue, long.MinValue }, { new SqlMoney(-1.23), (long)(new SqlMoney(-1.23).ToDecimal() * 10000) }, diff --git a/src/Microsoft.Data.SqlClient/tests/UnitTests/TdsParserInternalsTest.cs b/src/Microsoft.Data.SqlClient/tests/UnitTests/TdsParserInternalsTest.cs index f0b3729d6f..17a4ad8b5a 100644 --- a/src/Microsoft.Data.SqlClient/tests/UnitTests/TdsParserInternalsTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/UnitTests/TdsParserInternalsTest.cs @@ -92,7 +92,7 @@ public void WriteUserAgentFeatureRequest_WriteTrue_AppendsOnlyExtensionBytes() bufferAfter[start + 5]); // slice into the existing buffer - ReadOnlySpan writtenSpan = new ReadOnlySpan( + ReadOnlySpan writtenSpan = new( bufferAfter, start + 6, appended - 6); From 600803b06fb78a9d9b71663a9f02c261ad253e90 Mon Sep 17 00:00:00 2001 From: Paul Medynski <31868385+paulmedynski@users.noreply.github.com> Date: Thu, 18 Sep 2025 16:06:54 -0300 Subject: [PATCH 18/30] User Story 37654: Create Abstractions package - Removed obsolete ADO Library inclusion in CI variables. - Moved MDS CI versions numbers into CI variables. - Fixed Abstractions versioning to handle CI version format. --- eng/pipelines/dotnet-sqlclient-ci-core.yml | 2 +- .../libraries/ci-build-variables.yml | 7 +- .../Abstractions/src/Abstractions.csproj | 72 +++++++++++-------- 3 files changed, 47 insertions(+), 34 deletions(-) diff --git a/eng/pipelines/dotnet-sqlclient-ci-core.yml b/eng/pipelines/dotnet-sqlclient-ci-core.yml index be694f92de..cc6f9bf201 100644 --- a/eng/pipelines/dotnet-sqlclient-ci-core.yml +++ b/eng/pipelines/dotnet-sqlclient-ci-core.yml @@ -165,7 +165,7 @@ stages: ${{ if eq(parameters.referenceType, 'Package') }}: dependsOn: - build_abstractions_package_stage - - build_nugets + - build_mds_akv_packages_stage prebuildSteps: # steps to run prior to building and running tests on each job - ${{if ne(parameters.SNIVersion, '')}}: diff --git a/eng/pipelines/libraries/ci-build-variables.yml b/eng/pipelines/libraries/ci-build-variables.yml index 6ae1032de2..6b6ac2a825 100644 --- a/eng/pipelines/libraries/ci-build-variables.yml +++ b/eng/pipelines/libraries/ci-build-variables.yml @@ -6,7 +6,6 @@ variables: - group: 'ADO Build properties' - - group: 'ADO CI Packaging' - group: 'ADO Test Configuration Properties' - name: buildNumber @@ -16,11 +15,11 @@ variables: - name: SQLTarget value: 'localhost' - name: abstractionsPackageVersion - value: 1.0.0.$(buildNumber) + value: 1.0.0.$(buildNumber)-ci - name: akvPackageVersion - value: 7.0.0.$(buildNumber) + value: 7.0.0.$(buildNumber)-ci - name: mdsPackageVersion - value: $(Major).$(Minor)$(Patch)-pull.1$(buildnumber) + value: 7.0.0.$(buildNumber)-ci - name: skipComponentGovernanceDetection value: true - name: runCodesignValidationInjection diff --git a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/Abstractions.csproj b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/Abstractions.csproj index 367a35f8e1..bab743d838 100644 --- a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/Abstractions.csproj +++ b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/Abstractions.csproj @@ -8,28 +8,41 @@ - - 1 - - -dev - $(AbstractionsPackageMajorVersion).0.0.$(BuildNumber) - - $(AbstractionsPackageMajorVersion).0.0.0 + + 1 + + + + $(AbstractionsAssemblyFileVersion) + + $(AbstractionsPackageVersion.Split('-')[0]) + + $(DefaultMajorVersion).0.0.$(BuildNumber) + + + $(AbstractionsPackageVersion) + $(DefaultMajorVersion).0.0.$(BuildNumber)-dev @@ -48,10 +61,15 @@ Microsoft.Data.SqlClient.Extensions.Abstractions Microsoft.Data.SqlClient.Extensions.Abstractions - $(AbstractionsPackageAssemblyVersion) - $(AbstractionsPackageVersion) - $(AssemblyFileVersion) - $(AbstractionsPackageVersion)$(AbstractionsPackageVersionSuffix) + + $(DefaultMajorVersion).0.0.0 + + $(OurAssemblyFileVersion) + $(OurAssemblyFileVersion) + $(OurPackageVersion) @@ -69,12 +87,8 @@ See: https://learn.microsoft.com/en-us/nuget/reference/msbuild-targets#pack-target --> - - - $(Version) + $(AssemblyName) + $(OurPackageVersion) $(PackagesDir) true snupkg From 327df5e952578cd9263a4b22923276592a4ba2ec Mon Sep 17 00:00:00 2001 From: Paul Medynski <31868385+paulmedynski@users.noreply.github.com> Date: Fri, 19 Sep 2025 08:55:31 -0300 Subject: [PATCH 19/30] User Story 37654: Create Abstractions package - Addressed my own review comments. --- NuGet.config | 2 +- build.proj | 5 +++-- .../templates/jobs/build-signed-package-job.yml | 5 ++++- .../templates/jobs/ci-build-nugets-job.yml | 8 ++++---- .../common/templates/jobs/ci-run-tests-job.yml | 12 ++++++------ .../templates/stages/ci-run-tests-stage.yml | 12 ++++++------ .../steps/generate-nuget-package-step.yml | 9 +++------ eng/pipelines/dotnet-sqlclient-ci-core.yml | 4 +++- .../Abstractions/src/Abstractions.csproj | 4 ++-- tools/targets/GenerateMdsPackage.targets | 17 +++++++++++++++++ ...targets => GenerateSqlServerPackage.targets} | 14 -------------- ...ckage.targets => GenerateAkvPackage.targets} | 2 +- 12 files changed, 50 insertions(+), 44 deletions(-) create mode 100644 tools/targets/GenerateMdsPackage.targets rename tools/targets/{GenerateNugetPackage.targets => GenerateSqlServerPackage.targets} (53%) rename tools/targets/add-ons/{GenerateAKVProviderNugetPackage.targets => GenerateAkvPackage.targets} (90%) diff --git a/NuGet.config b/NuGet.config index 53f672d23b..3e762e7fe9 100644 --- a/NuGet.config +++ b/NuGet.config @@ -13,7 +13,7 @@ https://sqlclientdrivers.visualstudio.com/public/_artifacts/feed/sqlclient --> - + diff --git a/build.proj b/build.proj index fc22196202..7efa49d8bb 100644 --- a/build.proj +++ b/build.proj @@ -2,8 +2,9 @@ - - + + + diff --git a/eng/pipelines/common/templates/jobs/build-signed-package-job.yml b/eng/pipelines/common/templates/jobs/build-signed-package-job.yml index 53403d9d57..72b4e8e716 100644 --- a/eng/pipelines/common/templates/jobs/build-signed-package-job.yml +++ b/eng/pipelines/common/templates/jobs/build-signed-package-job.yml @@ -50,7 +50,10 @@ jobs: - template: ../steps/generate-nuget-package-step.yml@self parameters: - OutputDirectory: $(artifactDirectory) + nuspecPath: $(nuspecPath) + packageVersion: $(mdsPackageVersion) + outputDirectory: $(artifactDirectory) + displayName: 'Create MDS NuGet Package' - template: ../steps/esrp-code-signing-step.yml@self parameters: diff --git a/eng/pipelines/common/templates/jobs/ci-build-nugets-job.yml b/eng/pipelines/common/templates/jobs/ci-build-nugets-job.yml index 2066df3340..fd9755f32c 100644 --- a/eng/pipelines/common/templates/jobs/ci-build-nugets-job.yml +++ b/eng/pipelines/common/templates/jobs/ci-build-nugets-job.yml @@ -78,19 +78,19 @@ jobs: - template: ../steps/generate-nuget-package-step.yml@self parameters: - mdsPackageVersion: $(mdsPackageVersion) + packageVersion: $(mdsPackageVersion) configuration: $(Configuration) nuspecPath: 'tools/specs/Microsoft.Data.SqlClient.nuspec' - OutputDirectory: $(packagePath) + outputDirectory: $(packagePath) generateSymbolsPackage: false displayName: 'Create MDS NuGet Package' - template: ../steps/generate-nuget-package-step.yml@self parameters: - mdsPackageVersion: $(mdsPackageVersion) + packageVersion: $(akvPackageVersion) configuration: $(Configuration) nuspecPath: 'tools/specs/add-ons/Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider.nuspec' - OutputDirectory: $(packagePath) + outputDirectory: $(packagePath) generateSymbolsPackage: false installNuget: false displayName: 'Create AKV NuGet Package' diff --git a/eng/pipelines/common/templates/jobs/ci-run-tests-job.yml b/eng/pipelines/common/templates/jobs/ci-run-tests-job.yml index 20b39095b5..06bc31911b 100644 --- a/eng/pipelines/common/templates/jobs/ci-run-tests-job.yml +++ b/eng/pipelines/common/templates/jobs/ci-run-tests-job.yml @@ -10,12 +10,6 @@ parameters: - name: abstractionsPackageVersion type: string - - name: referenceType - type: string - values: - - Project - - Package - - name: configProperties type: object default: {} # - key: 'value' @@ -70,6 +64,12 @@ parameters: type: boolean default: false + - name: referenceType + type: string + values: + - Project + - Package + - name: targetFramework type: string diff --git a/eng/pipelines/common/templates/stages/ci-run-tests-stage.yml b/eng/pipelines/common/templates/stages/ci-run-tests-stage.yml index 994bb4f345..46318f8e06 100644 --- a/eng/pipelines/common/templates/stages/ci-run-tests-stage.yml +++ b/eng/pipelines/common/templates/stages/ci-run-tests-stage.yml @@ -10,12 +10,6 @@ parameters: - name: abstractionsPackageVersion type: string - - name: referenceType - default: Project - values: - - Project - - Package - - name: debug type: boolean default: false @@ -39,6 +33,12 @@ parameters: type: stepList default: [] + - name: referenceType + default: Project + values: + - Project + - Package + - name: testConfigurations type: object diff --git a/eng/pipelines/common/templates/steps/generate-nuget-package-step.yml b/eng/pipelines/common/templates/steps/generate-nuget-package-step.yml index 1afd22c063..816a9b7a7a 100644 --- a/eng/pipelines/common/templates/steps/generate-nuget-package-step.yml +++ b/eng/pipelines/common/templates/steps/generate-nuget-package-step.yml @@ -6,17 +6,15 @@ parameters: - name: nuspecPath type: string - default: '$(nuspecPath)' - - name: mdsPackageVersion + - name: packageVersion type: string - default: '$(mdsPackageVersion)' - - name: OutputDirectory + - name: outputDirectory type: string default: '$(Build.SourcesDirectory)/packages' - - name: Configuration + - name: configuration type: string default: '$(Configuration)' @@ -26,7 +24,6 @@ parameters: - name: displayName type: string - default: 'NuGet pack with snupkg' - name: installNuget type: boolean diff --git a/eng/pipelines/dotnet-sqlclient-ci-core.yml b/eng/pipelines/dotnet-sqlclient-ci-core.yml index cc6f9bf201..df7e1993f1 100644 --- a/eng/pipelines/dotnet-sqlclient-ci-core.yml +++ b/eng/pipelines/dotnet-sqlclient-ci-core.yml @@ -122,6 +122,8 @@ stages: ${{ if eq(parameters.referenceType, 'Package') }}: dependsOn: - build_abstractions_package_stage + ${{ else }}: + dependsOn: [] jobs: - template: common/templates/jobs/ci-build-nugets-job.yml@self @@ -143,7 +145,7 @@ stages: - template: stages/stress-tests-ci-stage.yml@self parameters: buildConfiguration: ${{ parameters.buildConfiguration }} - dependsOn: [build_mds_packages_job] + dependsOn: [build_mds_akv_packages_stage] pipelineArtifactName: $(artifactName) mdsPackageVersion: $(mdsPackageVersion) ${{ if eq(parameters.debug, 'true') }}: diff --git a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/Abstractions.csproj b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/Abstractions.csproj index bab743d838..b214f69b19 100644 --- a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/Abstractions.csproj +++ b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/Abstractions.csproj @@ -17,7 +17,7 @@ - Used as the base value of the assembly attribute 'AssemblyInformationalVersion' generated by MSBuild. - If not specified, defaults to: - $(AbstractionsPackageMajorVersion).0.0.$(BuildNumber)-dev. + $(DefaultMajorVersion).0.0.$(BuildNumber)-dev. AbstractionsAssemblyFileVersion: - Used as the value of the assembly attribute 'AssemblyFileVersion' @@ -26,7 +26,7 @@ - If $(AbstractionsPackageVersion) is specified, use the numeric parts of its value, for example 1.0.0.345. - Otherwise, defaults to: - $(AbstractionsPackageMajorVersion).0.0.$(BuildNumber). + $(DefaultMajorVersion).0.0.$(BuildNumber). --> diff --git a/tools/targets/GenerateMdsPackage.targets b/tools/targets/GenerateMdsPackage.targets new file mode 100644 index 0000000000..033b9a338b --- /dev/null +++ b/tools/targets/GenerateMdsPackage.targets @@ -0,0 +1,17 @@ + + + + + $(MdsPackageVersion)-debug + + + + + + + + + + + diff --git a/tools/targets/GenerateNugetPackage.targets b/tools/targets/GenerateSqlServerPackage.targets similarity index 53% rename from tools/targets/GenerateNugetPackage.targets rename to tools/targets/GenerateSqlServerPackage.targets index 7b674ebfdb..f7a2da0301 100644 --- a/tools/targets/GenerateNugetPackage.targets +++ b/tools/targets/GenerateSqlServerPackage.targets @@ -1,19 +1,5 @@ - - - $(MdsPackageVersion)-debug - - - - - - - - - - $(SqlServerPackageVersion)-debug diff --git a/tools/targets/add-ons/GenerateAKVProviderNugetPackage.targets b/tools/targets/add-ons/GenerateAkvPackage.targets similarity index 90% rename from tools/targets/add-ons/GenerateAKVProviderNugetPackage.targets rename to tools/targets/add-ons/GenerateAkvPackage.targets index aa50a32463..f63afe95a8 100644 --- a/tools/targets/add-ons/GenerateAKVProviderNugetPackage.targets +++ b/tools/targets/add-ons/GenerateAkvPackage.targets @@ -1,6 +1,6 @@ - + $(AkvPackageVersion)-debug From 6dcb0db1ae495dbaeb65c6b0336f953b45a75b8e Mon Sep 17 00:00:00 2001 From: Paul Medynski <31868385+paulmedynski@users.noreply.github.com> Date: Fri, 19 Sep 2025 09:00:08 -0300 Subject: [PATCH 20/30] User Story 37654: Create Abstractions package - Fixed parameter typo in YAML. --- .../common/templates/steps/generate-nuget-package-step.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/eng/pipelines/common/templates/steps/generate-nuget-package-step.yml b/eng/pipelines/common/templates/steps/generate-nuget-package-step.yml index 816a9b7a7a..a9ce1f2d83 100644 --- a/eng/pipelines/common/templates/steps/generate-nuget-package-step.yml +++ b/eng/pipelines/common/templates/steps/generate-nuget-package-step.yml @@ -52,6 +52,6 @@ steps: inputs: command: custom ${{ if parameters.generateSymbolsPackage }}: - arguments: 'pack -Symbols -SymbolPackageFormat snupkg ${{parameters.nuspecPath}} -Version ${{parameters.mdsPackageVersion}} -OutputDirectory ${{parameters.OutputDirectory}} -properties "COMMITID=$(CommitHead);Configuration=${{parameters.Configuration}};ReferenceType=${{parameters.referenceType}}"' + arguments: 'pack -Symbols -SymbolPackageFormat snupkg ${{parameters.nuspecPath}} -Version ${{parameters.packageVersion}} -OutputDirectory ${{parameters.outputDirectory}} -properties "COMMITID=$(CommitHead);Configuration=${{parameters.Configuration}};ReferenceType=${{parameters.referenceType}}"' ${{else }}: - arguments: 'pack ${{parameters.nuspecPath}} -Version ${{parameters.mdsPackageVersion}} -OutputDirectory ${{parameters.OutputDirectory}} -properties "COMMITID=$(CommitHead);Configuration=${{parameters.Configuration}};ReferenceType=${{parameters.referenceType}}"' + arguments: 'pack ${{parameters.nuspecPath}} -Version ${{parameters.packageVersion}} -OutputDirectory ${{parameters.outputDirectory}} -properties "COMMITID=$(CommitHead);Configuration=${{parameters.Configuration}};ReferenceType=${{parameters.referenceType}}"' From 88e95d573bede54c8f9c4263c1618f3486fe7ef7 Mon Sep 17 00:00:00 2001 From: Paul Medynski <31868385+paulmedynski@users.noreply.github.com> Date: Fri, 19 Sep 2025 17:29:26 -0300 Subject: [PATCH 21/30] User Story 37654: Create Abstractions package - Fixed Abstractions package versioning in official builds. - Fixed broken assembly version checks in official builds. - Removed Abstractions solution file. --- .../templates/jobs/build-signed-package-job.yml | 6 +++++- .../templates/jobs/validate-signed-package-job.yml | 10 ++++++++-- .../build-all-configurations-signed-dlls-step.yml | 9 ++++++++- .../jobs/pack-abstractions-package-ci-job.yml | 12 ++++++------ .../jobs/test-abstractions-package-ci-job.yml | 14 +++++++------- eng/pipelines/libraries/common-variables.yml | 14 ++++++++++++++ .../Abstractions/Abstractions.slnx | 8 -------- tools/props/Versions.props | 2 +- 8 files changed, 49 insertions(+), 26 deletions(-) delete mode 100644 src/Microsoft.Data.SqlClient.Extensions/Abstractions/Abstractions.slnx diff --git a/eng/pipelines/common/templates/jobs/build-signed-package-job.yml b/eng/pipelines/common/templates/jobs/build-signed-package-job.yml index 72b4e8e716..89c621b877 100644 --- a/eng/pipelines/common/templates/jobs/build-signed-package-job.yml +++ b/eng/pipelines/common/templates/jobs/build-signed-package-job.yml @@ -39,7 +39,11 @@ jobs: name: GetBuildType - template: ../steps/build-all-configurations-signed-dlls-step.yml@self - + parameters: + # These values are sourced from common-variables.yml. + abstractionsPackageVersion: $(abstractionsPackageVersion) + abstractionsAssemblyFileVersion: $(abstractionsAssemblyFileVersion) + - template: ../steps/code-analyze-step.yml@self parameters: analyzeType: all diff --git a/eng/pipelines/common/templates/jobs/validate-signed-package-job.yml b/eng/pipelines/common/templates/jobs/validate-signed-package-job.yml index 333e78ffd4..8f88a402ed 100644 --- a/eng/pipelines/common/templates/jobs/validate-signed-package-job.yml +++ b/eng/pipelines/common/templates/jobs/validate-signed-package-job.yml @@ -344,10 +344,16 @@ jobs: - powershell: | # Check assembly versions. + # + # GOTCHA: This expects the Versions.props file having XML elements in a + # certain order. If the order changes, this check will fail! + # + # TODO: This also isn't checking the versions of the actual assemblies in + # the package, so it isn't terribly useful. [Xml] $versionprops = Get-Content -Path "tools/props/Versions.props" - $AssemblyFileVersion = $versionprops.Project.PropertyGroup[0].AssemblyFileVersion - $AssemblyVersion = $versionprops.Project.PropertyGroup[0].AssemblyVersion + $AssemblyFileVersion = $versionprops.Project.PropertyGroup[1].AssemblyFileVersion + $AssemblyVersion = $versionprops.Project.PropertyGroup[1].AssemblyVersion if($AssemblyFileVersion -eq $AssemblyVersion) { diff --git a/eng/pipelines/common/templates/steps/build-all-configurations-signed-dlls-step.yml b/eng/pipelines/common/templates/steps/build-all-configurations-signed-dlls-step.yml index e6a6c0443a..736193b8ec 100644 --- a/eng/pipelines/common/templates/steps/build-all-configurations-signed-dlls-step.yml +++ b/eng/pipelines/common/templates/steps/build-all-configurations-signed-dlls-step.yml @@ -4,6 +4,13 @@ # See the LICENSE file in the project root for more information. # ################################################################################# parameters: + + - name: abstractionsPackageVersion + type: string + + - name: abstractionsAssemblyFileVersion + type: string + - name: AssemblyFileVersion type: string default: $(AssemblyFileVersion) @@ -47,4 +54,4 @@ steps: inputs: solution: '**/build.proj' configuration: '${{parameters.Configuration }}' - msbuildArguments: '-p:AssemblyFileVersion=${{parameters.AssemblyFileVersion }} -t:BuildAllConfigurations -p:GenerateNuget=false -p:SigningKeyPath=$(Agent.TempDirectory)\netfxKeypair.snk' + msbuildArguments: '-p:AssemblyFileVersion=${{parameters.AssemblyFileVersion }} -t:BuildAllConfigurations -p:GenerateNuget=false -p:SigningKeyPath=$(Agent.TempDirectory)\netfxKeypair.snk -p:AbstractionsPackageVersion=${{ parameters.abstractionsPackageVersion }} -p:AbstractionsAssemblyFileVersion=${{ parameters.abstractionsAssemblyFileVersion }}' diff --git a/eng/pipelines/jobs/pack-abstractions-package-ci-job.yml b/eng/pipelines/jobs/pack-abstractions-package-ci-job.yml index 795fbd4373..13bf3618fb 100644 --- a/eng/pipelines/jobs/pack-abstractions-package-ci-job.yml +++ b/eng/pipelines/jobs/pack-abstractions-package-ci-job.yml @@ -57,9 +57,9 @@ jobs: variables: - # The Abstractions solution file to use for all dotnet CLI commands. - - name: solution - value: src/Microsoft.Data.SqlClient.Extensions/Abstractions/Abstractions.slnx + # The Abstractions project file to use for all dotnet CLI commands. + - name: project + value: src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/Abstractions.csproj # The directory where the NuGet packages will be staged before being # published as pipeline artifacts. @@ -118,7 +118,7 @@ jobs: inputs: command: custom custom: restore - projects: $(solution) + projects: $(project) arguments: $(commonArguments) # Build the solution. @@ -127,7 +127,7 @@ jobs: inputs: command: custom custom: build - projects: $(solution) + projects: $(project) arguments: $(buildArguments) --no-restore # Create the NuGet packages. @@ -136,7 +136,7 @@ jobs: inputs: command: custom custom: pack - projects: $(solution) + projects: $(project) arguments: $(buildArguments) --no-build -o $(dotnetPackagesDir) # Publish the NuGet packages as a named pipeline artifact. diff --git a/eng/pipelines/jobs/test-abstractions-package-ci-job.yml b/eng/pipelines/jobs/test-abstractions-package-ci-job.yml index a2b25966d4..a5e0f98978 100644 --- a/eng/pipelines/jobs/test-abstractions-package-ci-job.yml +++ b/eng/pipelines/jobs/test-abstractions-package-ci-job.yml @@ -76,9 +76,9 @@ jobs: variables: - # The Abstractions solution file to use for all dotnet CLI commands. - - name: solution - value: src/Microsoft.Data.SqlClient.Extensions/Abstractions/Abstractions.slnx + # The Abstractions test project file to use for all dotnet CLI commands. + - name: project + value: src/Microsoft.Data.SqlClient.Extensions/Abstractions/test/Abstractions.Test.csproj # dotnet CLI arguments common to all commands. - name: commonArguments @@ -141,7 +141,7 @@ jobs: inputs: command: custom custom: restore - projects: $(solution) + projects: $(project) arguments: $(commonArguments) # Build the solution. @@ -150,7 +150,7 @@ jobs: inputs: command: custom custom: build - projects: $(solution) + projects: $(project) arguments: $(buildArguments) --no-restore # Run the tests for each .NET runtime. @@ -160,7 +160,7 @@ jobs: inputs: command: custom custom: test - projects: $(solution) + projects: $(project) arguments: $(buildArguments) --no-build -f ${{ runtime }} # Run the tests for each .NET Framework runtime. @@ -170,5 +170,5 @@ jobs: inputs: command: custom custom: test - projects: $(solution) + projects: $(project) arguments: $(buildArguments) --no-build -f ${{ runtime }} diff --git a/eng/pipelines/libraries/common-variables.yml b/eng/pipelines/libraries/common-variables.yml index b7df898497..94eb5103a3 100644 --- a/eng/pipelines/libraries/common-variables.yml +++ b/eng/pipelines/libraries/common-variables.yml @@ -26,6 +26,20 @@ variables: - name: artifactDirectory value: '$(REPOROOT)/packages' + # ---------------------------------------------------------------------------- + # Abstractions Package Versions + # + # These are version values that will be used by the official build. They + # should be updated after each release to reflect the next release's versions. + + # The NuGet package version for the Abstractions package. + - name: abstractionsPackageVersion + value: 1.0.0.$(Build.BuildNumber) + + # The AssemblyFileVersion for all assemblies in the Abstractions package. + - name: abstractionsAssemblyFileVersion + value: '1.0.0.0' + # Update this after every release. This is used to generate the MDS NuGet package version. - name: Major value: '7' diff --git a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/Abstractions.slnx b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/Abstractions.slnx deleted file mode 100644 index 9632efff88..0000000000 --- a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/Abstractions.slnx +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/tools/props/Versions.props b/tools/props/Versions.props index c8595f574a..e4935f8c91 100644 --- a/tools/props/Versions.props +++ b/tools/props/Versions.props @@ -20,7 +20,7 @@ --> + + + AbstractionsPackageVersion=$(AbstractionsPackageVersion) + + - - - AbstractionsPackageVersion=$(AbstractionsPackageVersion) - - + Properties="$(AbstractionsProperties)" /> - - AbstractionsPackageVersion=$(AbstractionsPackageVersion) - - + Properties="$(AbstractionsProperties)" /> - - AbstractionsPackageVersion=$(AbstractionsPackageVersion) - - + Properties="$(AbstractionsProperties)" /> - - AbstractionsPackageVersion=$(AbstractionsPackageVersion) - - + Properties="$(AbstractionsProperties)" /> diff --git a/eng/pipelines/common/templates/jobs/build-signed-package-job.yml b/eng/pipelines/common/templates/jobs/build-signed-package-job.yml index 54cac5100e..80cf59d5a7 100644 --- a/eng/pipelines/common/templates/jobs/build-signed-package-job.yml +++ b/eng/pipelines/common/templates/jobs/build-signed-package-job.yml @@ -46,6 +46,7 @@ jobs: ${{ else }}: abstractionsPackageVersion: $(abstractionsPackagePreviewVersion) abstractionsAssemblyFileVersion: $(abstractionsAssemblyFileVersion) + mdsAssemblyFileVersion: $(mdsAssemblyFileVersion) - template: ../steps/code-analyze-step.yml@self parameters: diff --git a/eng/pipelines/common/templates/steps/build-all-configurations-signed-dlls-step.yml b/eng/pipelines/common/templates/steps/build-all-configurations-signed-dlls-step.yml index 6289c7dae0..8040b991a8 100644 --- a/eng/pipelines/common/templates/steps/build-all-configurations-signed-dlls-step.yml +++ b/eng/pipelines/common/templates/steps/build-all-configurations-signed-dlls-step.yml @@ -13,7 +13,6 @@ parameters: - name: mdsAssemblyFileVersion type: string - default: $(mdsAssemblyFileVersion) - name: Configuration type: string diff --git a/eng/pipelines/common/templates/steps/copy-dlls-for-test-step.yml b/eng/pipelines/common/templates/steps/copy-dlls-for-test-step.yml index 098286866c..3b18dcf5bc 100644 --- a/eng/pipelines/common/templates/steps/copy-dlls-for-test-step.yml +++ b/eng/pipelines/common/templates/steps/copy-dlls-for-test-step.yml @@ -83,6 +83,6 @@ steps: $software = '${{parameters.softwareFolder}}' $symbols = '${{parameters.symbolsFolder}}' - Get-ChildItem -recurse "$software\*.dll" - Get-ChildItem -recurse "$symbols\*.pdb" + Get-ChildItem -recurse "$software\*.dll" | ForEach-Object VersionInfo + Get-ChildItem -recurse "$symbols\*.pdb" | ForEach-Object VersionInfo displayName: 'List the prepared files' From 9f49ffe307a488c0948098805b1a25c43b985388 Mon Sep 17 00:00:00 2001 From: Paul Medynski <31868385+paulmedynski@users.noreply.github.com> Date: Tue, 8 Jul 2025 08:31:05 -0300 Subject: [PATCH 29/30] User Story 37654: Create Abstractions package - Added empty Extensions package with some sample class and docs to demonstrate packaging. - Created CI stage to build, test, pack, and publish the Extensions NuGet package. - Updated downstream CI stages/jobs to use the Extensions package. - Updated build.proj Clean target to not delete packages/ dir. - Updated BUILDGUIDE with instructions for the Extensions package. - Cleaned up stale BUIDGUIDE sections. - Added temporary GitHub Discussion content so the team can review before posting it as a real Discussion. - Disable .pdb file inclusion in the application package. - Renamed Extensions package to Abstractions. - Updated README related to extensions design. - Changed MDS to reference Abstractions via project or package depending on build parameters. - Removed obsolete package reference files. - Updated CI pipelines to build Abstractions in parallel for Project-based builds. - Modularized Abstractions CI templates. - Cleaned up the project vs package pathways. - Replaced generic "NugetPackageVersion" with variables names specific to the package (i.e. MdsPackageVersion, AkvPackageVersion, etc). - Removed top-level Abstractions package version parameters in favour of a variable. - Fixes to Abstractions version number construction. - Fixes for some build.proj targets. --- BUILDGUIDE.md | 86 +++--- NuGet.config | 21 +- build.proj | 150 +++++++-- eng/pipelines/akv-official-pipeline.yml | 5 +- .../jobs/build-signed-package-job.yml | 6 +- .../templates/jobs/ci-build-nugets-job.yml | 43 ++- .../templates/jobs/ci-run-tests-job.yml | 113 ++++--- .../jobs/run-tests-package-reference-job.yml | 6 +- .../jobs/validate-signed-package-job.yml | 14 +- .../templates/stages/ci-run-tests-stage.yml | 53 ++-- .../templates/steps/build-all-tests-step.yml | 44 ++- .../build-and-run-tests-netcore-step.yml | 12 +- .../steps/build-and-run-tests-netfx-step.yml | 12 +- .../templates/steps/ci-prebuild-step.yml | 24 +- .../templates/steps/ci-project-build-step.yml | 22 +- .../steps/generate-nuget-package-step.yml | 8 +- .../templates/steps/publish-symbols-step.yml | 2 +- .../templates/steps/run-all-tests-step.yml | 22 +- .../update-nuget-config-local-feed-step.yml | 42 +-- eng/pipelines/dotnet-sqlclient-ci-core.yml | 212 +++++++------ ...qlclient-ci-package-reference-pipeline.yml | 9 +- ...qlclient-ci-project-reference-pipeline.yml | 9 +- .../dotnet-sqlclient-signing-pipeline.yml | 2 +- eng/pipelines/jobs/build-akv-official-job.yml | 19 +- .../jobs/pack-abstractions-package-ci-job.yml | 143 +++++++++ eng/pipelines/jobs/stress-tests-ci-job.yml | 2 +- .../jobs/test-abstractions-package-ci-job.yml | 174 +++++++++++ .../libraries/ci-build-variables.yml | 4 +- eng/pipelines/libraries/common-variables.yml | 4 +- .../libraries/mds-validation-variables.yml | 2 +- .../build-abstractions-package-ci-stage.yml | 124 ++++++++ .../steps/compound-build-akv-step.yml | 10 +- .../steps/roslyn-analyzers-akv-step.yml | 6 +- .../variables/akv-official-variables.yml | 4 +- src/Directory.Build.props | 15 + src/Directory.Packages.props | 7 + .../Abstractions/Abstractions.slnx | 8 + .../Abstractions/README.md | 285 ++++++++++++++++++ .../Abstractions/doc/Sample.xml | 18 ++ .../Abstractions/src/Abstractions.csproj | 109 +++++++ .../Abstractions/src/Sample.cs | 20 ++ .../test/Abstractions.Test.csproj | 26 ++ .../Abstractions/test/SampleTest.cs | 19 ++ src/Microsoft.Data.SqlClient.sln | 44 ++- .../ref/Microsoft.Data.SqlClient.csproj | 15 +- .../src/Microsoft.Data.SqlClient.csproj | 13 + .../netfx/ref/Microsoft.Data.SqlClient.csproj | 14 + .../netfx/src/Microsoft.Data.SqlClient.csproj | 14 + tools/props/Versions.props | 43 ++- tools/specs/Microsoft.Data.SqlClient.nuspec | 4 + tools/targets/GenerateNugetPackage.targets | 8 +- .../GenerateAKVProviderNugetPackage.targets | 6 +- 52 files changed, 1632 insertions(+), 445 deletions(-) create mode 100644 eng/pipelines/jobs/pack-abstractions-package-ci-job.yml create mode 100644 eng/pipelines/jobs/test-abstractions-package-ci-job.yml create mode 100644 eng/pipelines/stages/build-abstractions-package-ci-stage.yml create mode 100644 src/Microsoft.Data.SqlClient.Extensions/Abstractions/Abstractions.slnx create mode 100644 src/Microsoft.Data.SqlClient.Extensions/Abstractions/README.md create mode 100644 src/Microsoft.Data.SqlClient.Extensions/Abstractions/doc/Sample.xml create mode 100644 src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/Abstractions.csproj create mode 100644 src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/Sample.cs create mode 100644 src/Microsoft.Data.SqlClient.Extensions/Abstractions/test/Abstractions.Test.csproj create mode 100644 src/Microsoft.Data.SqlClient.Extensions/Abstractions/test/SampleTest.cs diff --git a/BUILDGUIDE.md b/BUILDGUIDE.md index efeb747cad..178c3fc2d6 100644 --- a/BUILDGUIDE.md +++ b/BUILDGUIDE.md @@ -16,28 +16,33 @@ Once the environment is setup properly, execute the desired set of commands belo ### Targets +The following build targets are defined in `build.proj`: + |Target|Description| |-|-| |`BuildAllConfigurations`|Default target. Builds the .NET Framework and .NET drivers for all target frameworks and operating systems.| +|`BuildAbstractionsPackage`|Restore, build, and pack the Abstractions package, publishing the resulting NuGet into `packages/`.| |`BuildNetCore`|Builds the .NET driver for all target frameworks.| |`BuildNetCoreAllOS`|Builds the .NET driver for all target frameworks and operating systems.| |`BuildNetFx`|Builds the .NET Framework driver for all target frameworks.| |`BuildTestsNetCore`|Builds tests for the .NET driver.| |`BuildTestsNetFx`|Builds tests for the .NET Framework driver.| -|`Clean`|Cleans generated files.| -|`Restore`|Restores Nuget packages.| +|`Clean`|Cleans all generated files.| +|`Restore`|Restores NuGet packages.| |`RunTests`|Runs the unit, functional, and manual tests for the .NET Framework and .NET drivers| |`RunUnitTests`|Runs just the unit tests for the .NET Framework and .NET drivers| |`RunFunctionalTests`|Runs just the functional tests for the .NET Framework and .NET drivers| |`RunManualTests`|Runs just the manual tests for the .NET Framework and .NET drivers| |`BuildAkv`|Builds the Azure Key Vault Provider package for all supported platforms.| - ### Parameters + +The following parameters may be defined as MSBuild properties to configure the +build: + |Name|Supported Values|Default|Description| |-|-|-|-| |`Configuration`|`Debug`, `Release`|`Debug`|Sets the release configuration.| -|`BuildNetFx`|`true`, `false`|`true` (Windows), `false` (other)|If false, skips building the .NET Framework driver on Windows.| |`OSGroup`|`Unix`, `Windows_NT`, `AnyOS`|typically defaults to the client system's OS, unless using `BuildAllConfigurations` or an `AnyOS` specific target|The operating system to target.| |`Platform`|`AnyCPU`, `x86`, `x64`, `ARM`, `ARM64`|`AnyCPU`|May only be set when using package reference type or running tests.| |`TestSet`|`1`, `2`, `3`, `AE`|all|Build or run a subset of the manual tests. Omit (default) to target all tests.| @@ -45,11 +50,12 @@ Once the environment is setup properly, execute the desired set of commands belo |`TF`|`net8.0`, `net462`, `net47`, `net471`, `net472`, `net48`, `net481`|`net8.0` in netcore, `net462` in netfx|Sets the target framework when building or running tests. Not applicable when building the drivers.| |`ResultsDirectory`|An absolute file path|./TestResults relative to current directory|Specifies where to write test results.| - ## Example Workflows using MSBuild (Recommended) + Using the default configuration and running all tests: ```bash +msbuild -t:BuildAbstractionsPackage msbuild msbuild -t:BuildTestsNetFx -p:TF=net462 msbuild -t:BuildTestsNetCore @@ -59,28 +65,31 @@ msbuild -t:RunTests Using the Release configuration: ```bash -msbuild -p:configuration=Release -msbuild -t:BuildTestsNetFx -p:TF=net462 -p:configuration=Release -msbuild -t:BuildTestsNetCore -p:configuration=Release -msbuild -t:RunTests -p:configuration=Release +msbuild -t:BuildAbstractionsPackage -p:Configuration=Release +msbuild -p:Configuration=Release +msbuild -t:BuildTestsNetFx -p:TF=net462 -p:Configuration=Release +msbuild -t:BuildTestsNetCore -p:Configuration=Release +msbuild -t:RunTests -p:Configuration=Release ``` Running only the unit tests: ```bash +msbuild -t:BuildAbstractionsPackage msbuild msbuild -t:BuildTestsNetFx -p:TF=net462 msbuild -t:BuildTestsNetCore msbuild -t:RunUnitTests ``` -Using a specific dotnet version/architecture: +Using a specific .NET runtime to run tests: ```bash -msbuild -p:configuration=Release -msbuild -t:BuildTestsNetFx -p:TF=net462 -p:configuration=Release -msbuild -t:BuildTestsNetCore -p:configuration=Release -msbuild -t:RunTests -p:configuration=Release -p:DotnetPath=C:\net8-win-x86\ +msbuild -t:BuildAbstractionsPackage +msbuild +msbuild -t:BuildTestsNetFx -p:TF=net462 +msbuild -t:BuildTestsNetCore +msbuild -t:RunTests -p:DotnetPath=C:\net8-win-x86\ ``` ### Running Manual Tests @@ -119,15 +128,13 @@ Manual Tests require the below setup to run: |IsManagedInstance | (Optional) When set to `true` **TVP** related tests will use on non-Azure bs files to compare test results. this is needed when testing against Managed Instances or TVP Tests will fail on Test set 3. The default value is `false`. | |PowerShellPath | The full path to PowerShell.exe. This is not required if the path is present in the PATH environment variable. | `D:\\escaped\\absolute\\path\\to\\PowerShell.exe` | - ## Example workflows using the Dotnet SDK -#### Run Functional Tests +### Run Functional Tests - Windows (`netfx x86`): ```bash -msbuild dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" -p:Platform="x86" -p:Configuration="Release" -p:TestTargetOS="Windowsnetfx" --no-build -v n --filter "category!=nonnetfxtests&category!=failing&category!=nonwindowstests" ``` @@ -152,7 +159,8 @@ dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.S ```bash dotnet test "src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj" -p:Platform="AnyCPU" -p:Configuration="Release" -p:TestTargetOS="Unixnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonlinuxtests&category!=nonuaptests" ``` -#### Run Manual Tests + +### Run Manual Tests - Windows (`netfx x86`): @@ -194,35 +202,40 @@ dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlCl Tests can be built and run with custom "Reference Type" property that enables different styles of testing: -- "Project" => Build and run tests with Microsoft.Data.SqlClient as Project Reference -- "Package" => Build and run tests with Microsoft.Data.SqlClient as Package Reference with configured "TestMicrosoftDataSqlClientVersion" in "Versions.props" file. +- "Project" => Build and run tests with Microsoft.Data.SqlClient as a Project Reference +- "Package" => Build and run tests with Microsoft.Data.SqlClient as a Package Reference with configured "TestMicrosoftDataSqlClientVersion" in "Versions.props" file. > ************** IMPORTANT NOTE BEFORE PROCEEDING WITH "PACKAGE" REFERENCE TYPE *************** > CREATE A NUGET PACKAGE WITH BELOW COMMAND AND ADD TO LOCAL FOLDER + UPDATE NUGET CONFIG FILE TO READ FROM THAT LOCATION > > ```bash -> msbuild -p:configuration=Release +> msbuild -t:BuildAbstractionsPackage -p:Configuration=Release +> msbuild -p:Configuration=Release > ``` A non-AnyCPU platform reference can only be used with package reference type. Otherwise, the specified platform will be replaced with AnyCPU in the build process. ### Building Tests with Reference Type -For .NET, all 4 reference types are supported: +For .NET: ```bash +# Project is the default reference type. The below commands are equivalent: +msbuild -t:BuildTestsNetCore msbuild -t:BuildTestsNetCore -p:ReferenceType=Project -# Default setting uses Project Reference. +# Package reference type: msbuild -t:BuildTestsNetCore -p:ReferenceType=Package ``` -For .NET Framework, below reference types are supported: +For .NET Framework: ```bash +# Project is the default reference type. The below commands are equivalent: +msbuild -t:BuildTestsNetFx -p:TF=net462 msbuild -t:BuildTestsNetFx -p:TF=net462 -p:ReferenceType=Project -# Default setting uses Project Reference. +# Package reference type: msbuild -t:BuildTestsNetFx -p:TF=net462 -p:ReferenceType=Package ``` @@ -241,26 +254,25 @@ Tests can be built and run with custom Target Frameworks. See the below examples ### Building Tests with custom target framework ```bash -msbuild -t:BuildTestsNetFx -p:TF=net462 # Build the tests for custom .NET Framework target +msbuild -t:BuildTestsNetFx -p:TF=net462 ``` ```bash -msbuild -t:BuildTestsNetCore -p:TF=net8.0 # Build the tests for custom .NET target +msbuild -t:BuildTestsNetCore -p:TF=net8.0 ``` ### Running Tests with custom target framework (traditional) ```bash +# Run tests with custom .NET Framework target dotnet test -p:TargetNetFxVersion=net462 ... -# Use above property to run Functional Tests with custom .NET Framework target +# Run tests with custom .NET target dotnet test -p:TargetNetCoreVersion=net8.0 ... -# Use above property to run Functional Tests with custom .NET target ``` - ## Using Managed SNI on Windows Managed SNI can be enabled on Windows by enabling the below AppContext switch: @@ -285,20 +297,6 @@ When connecting to a server, if a protocol lower than TLS 1.2 is negotiated, a s `Switch.Microsoft.Data.SqlClient.SuppressInsecureTLSWarning` -### Troubleshooting Docker issues - -There may be times where connection cannot be made to SQL Server, we found below ideas helpful: - -- Clear Docker images to create clean image from time-to-time, and clear docker cache if needed by running `docker system prune` in Command Prompt. - -- If you face `Microsoft.Data.SqlClient.SNI.dll not found` errors when debugging, try updating the below properties in the netcore\Microsoft.Data.SqlClient.csproj file and try again: - - ```xml - Unix - false - true - ``` - ## Collecting Code Coverage ### Using VSTest diff --git a/NuGet.config b/NuGet.config index d93875f3fb..53f672d23b 100644 --- a/NuGet.config +++ b/NuGet.config @@ -1,11 +1,30 @@  + + - + + + + + + + + diff --git a/build.proj b/build.proj index 0443bbcf4e..fc22196202 100644 --- a/build.proj +++ b/build.proj @@ -29,7 +29,7 @@ true Configuration=$(Configuration);AssemblyVersion=$(SqlServerAssemblyVersion);AssemblyFileVersion=$(SqlServerAssemblyFileVersion);Version=$(SqlServerPackageVersion); Configuration=$(Configuration);AssemblyFileVersion=$(AssemblyFileVersion);TargetsWindows=$(TargetsWindows);TargetsUnix=$(TargetsUnix); - BuildProjectReferences=false;$(ProjectProperties);BuildForRelease=false;TargetNetCoreVersion=$(TargetNetCoreVersion);TargetNetFxVersion=$(TargetNetFxVersion) + $(ProjectProperties);BuildForRelease=false;TargetNetCoreVersion=$(TargetNetCoreVersion);TargetNetFxVersion=$(TargetNetFxVersion) TestResults + + @@ -84,32 +86,91 @@ - - - + + + - - + + + + + + + AbstractionsPackageVersion=$(AbstractionsPackageVersion) + + + + + + + + AbstractionsPackageVersion=$(AbstractionsPackageVersion) + + + + + + + + AbstractionsPackageVersion=$(AbstractionsPackageVersion) + + + + + + + + AbstractionsPackageVersion=$(AbstractionsPackageVersion) + + + + + + - + - + - + - + @@ -122,7 +183,10 @@ - + @@ -139,27 +203,37 @@ - + - + + - + - - + + @@ -168,7 +242,9 @@ - + @@ -177,12 +253,18 @@ - + - + @@ -191,7 +273,10 @@ - + @@ -346,13 +431,13 @@ - + - - - - - + + + + + @@ -388,7 +473,10 @@ - + @@ -398,7 +486,9 @@ - + @@ -408,7 +498,9 @@ - + diff --git a/eng/pipelines/akv-official-pipeline.yml b/eng/pipelines/akv-official-pipeline.yml index d7bc900bb8..fcaa1bb3e2 100644 --- a/eng/pipelines/akv-official-pipeline.yml +++ b/eng/pipelines/akv-official-pipeline.yml @@ -113,7 +113,7 @@ extends: sbom: enabled: ${{ parameters.runSdlTasks }} packageName: 'Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider' - packageVersion: ${{ variables.nugetPackageVersion }} + packageVersion: ${{ variables.akvPackageVersion }} tsa: # OneBranch publishes all sdl results to TSA. If TSA is disabled all SDL tools will @@ -131,8 +131,7 @@ extends: apiScanPdbPath: '${{ variables.apiScanPdbPath }}' assemblyFileVersion: '${{ variables.assemblyFileVersion }}' buildConfiguration: '${{ parameters.buildConfiguration }}' - nugetPackageVersion: '${{ variables.nugetPackageVersion }}' - mdsPackageVersion: '${{ variables.mdsPackageVersion }}' + akvPackageVersion: '${{ variables.akvPackageVersion }}' publishSymbols: '${{ parameters.publishSymbols }}' signingAppRegistrationClientId: '$(SigningAppRegistrationClientId)' signingAppRegistrationTenantId: '$(SigningAppRegistrationTenantId)' diff --git a/eng/pipelines/common/templates/jobs/build-signed-package-job.yml b/eng/pipelines/common/templates/jobs/build-signed-package-job.yml index 91eb864337..53403d9d57 100644 --- a/eng/pipelines/common/templates/jobs/build-signed-package-job.yml +++ b/eng/pipelines/common/templates/jobs/build-signed-package-job.yml @@ -27,8 +27,8 @@ jobs: variables: - template: ../../../libraries/variables.yml@self - ${{ if parameters.isPreview }}: - - name: NugetPackageVersion - value: $(PreviewNugetPackageVersion) + - name: mdsPackageVersion + value: $(previewMdsPackageVersion) steps: - script: SET @@ -64,4 +64,4 @@ jobs: - template: ../steps/publish-symbols-step.yml@self parameters: publishSymbols: ${{ parameters['PublishSymbols'] }} - symbolsArtifactName: mds_symbols_$(System.TeamProject)_$(Build.Repository.Name)_$(Build.SourceBranchName)_$(NuGetPackageVersion)_$(System.TimelineId) + symbolsArtifactName: mds_symbols_$(System.TeamProject)_$(Build.Repository.Name)_$(Build.SourceBranchName)_$(mdsPackageVersion)_$(System.TimelineId) diff --git a/eng/pipelines/common/templates/jobs/ci-build-nugets-job.yml b/eng/pipelines/common/templates/jobs/ci-build-nugets-job.yml index cb3790262c..63f99cae76 100644 --- a/eng/pipelines/common/templates/jobs/ci-build-nugets-job.yml +++ b/eng/pipelines/common/templates/jobs/ci-build-nugets-job.yml @@ -4,6 +4,13 @@ # See the LICENSE file in the project root for more information. # ################################################################################# parameters: + + - name: referenceType + type: string + values: + - Project + - Package + - name: poolName type: string default: $(ci_var_defaultPoolName) @@ -12,9 +19,13 @@ parameters: type: string default: ADO-MMS22-SQL19 - - name: artifactName + - name: abstractionsArtifactName + type: string + default: Abstractions.Artifact + + - name: mdsArtifactName type: string - default: Artifacts + default: MDS.Artifact - name: platform type: string @@ -28,8 +39,12 @@ parameters: type: stepList default: [] + - name: abstractionsPackageVersion + type: string + jobs: -- job: build_nugets +- job: build_mds_packages_job + displayName: Build MDS Packages pool: name: ${{parameters.poolName }} @@ -44,16 +59,26 @@ jobs: - ${{ if ne(parameters.prebuildSteps, '') }}: - ${{ parameters.prebuildSteps }} # extra steps to run before the build like downloading sni and the required configuration + # If we're testing in Package mode, download the Abstractions package + # artifacts and put them in the packages/ directory in the repo root. + - ${{ if eq(parameters.referenceType, 'Package') }}: + - task: DownloadPipelineArtifact@2 + displayName: Download Abstractions Package Artifact + inputs: + artifactName: ${{ parameters.abstractionsArtifactName }} + targetPath: $(Build.SourcesDirectory)/packages + - template: ../steps/ci-project-build-step.yml@self parameters: platform: ${{ parameters.platform }} configuration: ${{ parameters.configuration }} operatingSystem: Windows build: all + abstractionsPackageVersion: ${{parameters.abstractionsPackageVersion}} - template: ../steps/generate-nuget-package-step.yml@self parameters: - NugetPackageVersion: $(NugetPackageVersion) + mdsPackageVersion: $(mdsPackageVersion) configuration: $(Configuration) nuspecPath: 'tools/specs/Microsoft.Data.SqlClient.nuspec' OutputDirectory: $(packagePath) @@ -62,7 +87,7 @@ jobs: - template: ../steps/generate-nuget-package-step.yml@self parameters: - NugetPackageVersion: $(NugetPackageVersion) + mdsPackageVersion: $(mdsPackageVersion) configuration: $(Configuration) nuspecPath: 'tools/specs/add-ons/Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider.nuspec' OutputDirectory: $(packagePath) @@ -70,8 +95,8 @@ jobs: installNuget: false displayName: 'Generate NuGet package AKV Provider' - - task: PublishBuildArtifacts@1 - displayName: 'Publish Artifact: Artifacts' + - task: PublishPipelineArtifact@1 + displayName: 'Publish Pipeline Artifact' inputs: - PathtoPublish: $(packagePath) - ArtifactName: ${{ parameters.artifactName }} + targetPath: $(packagePath) + artifactName: ${{ parameters.mdsArtifactName }} diff --git a/eng/pipelines/common/templates/jobs/ci-run-tests-job.yml b/eng/pipelines/common/templates/jobs/ci-run-tests-job.yml index dbf5b10028..20b39095b5 100644 --- a/eng/pipelines/common/templates/jobs/ci-run-tests-job.yml +++ b/eng/pipelines/common/templates/jobs/ci-run-tests-job.yml @@ -4,12 +4,37 @@ # See the LICENSE file in the project root for more information. # ################################################################################# parameters: + - name: abstractionsArtifactName + type: string + + - name: abstractionsPackageVersion + type: string + + - name: referenceType + type: string + values: + - Project + - Package + + - name: configProperties + type: object + default: {} # - key: 'value' + + - name: configSqlFor + type: string # local, azure, or enclave + default: local + - name: debug type: boolean default: false - - name: poolName - type: string + - name: enableX64Test + type: boolean + default: true + + - name: enableX86Test + type: boolean + default: false - name: hostedPool type: boolean @@ -21,63 +46,45 @@ parameters: - name: jobDisplayName type: string - - name: usemanagedSNI - type: boolean - default: false - - - name: configProperties - type: object - default: {} # - key: 'value' - - - name: prebuildSteps - type: stepList - default: [] - - - name: artifactName + - name: mdsArtifactName type: string - default: Artifacts - - name: targetFramework + - name: mdsPackageVersion type: string - name: netcoreVersionTestUtils type: string + + - name: operatingSystem + type: string + default: '' - - name: enableX86Test - type: boolean - default: false - - - name: enableX64Test - type: boolean - default: true - - - name: testSet + - name: poolName type: string + + - name: prebuildSteps + type: stepList + default: [] - name: publishTestResults type: boolean default: false - - - name: configSqlFor - type: string # local, azure, or enclave - default: local - - - name: operatingSystem + + - name: targetFramework type: string - default: '' - - - name: buildType - displayName: 'Build Type' - default: Project - values: - - Project - - Package + - name: testSet + type: string + # The timeout, in minutes, for this job. - name: timeout type: string default: 90 + - name: usemanagedSNI + type: boolean + default: false + jobs: - job: ${{ format('{0}', coalesce(parameters.jobDisplayName, parameters.image, 'unknown_image')) }} @@ -98,6 +105,22 @@ jobs: value: '$(dotnetx86Path)' steps: + + # If we're testing in Package mode, download the Abstractions and MDS package + # artifacts and put them in the packages/ directory in the repo root. + - ${{ if eq(parameters.referenceType, 'Package') }}: + - task: DownloadPipelineArtifact@2 + displayName: Download Abstractions Package Artifact + inputs: + artifactName: ${{ parameters.abstractionsArtifactName }} + targetPath: $(Build.SourcesDirectory)/packages + + - task: DownloadPipelineArtifact@2 + displayName: Download MDS Package Artifact + inputs: + artifactName: ${{ parameters.mdsArtifactName }} + targetPath: $(Build.SourcesDirectory)/packages + - ${{ if ne(parameters.prebuildSteps, '') }}: - ${{ parameters.prebuildSteps }} # extra steps to run before the build like downloading sni and the required configuration @@ -227,8 +250,10 @@ jobs: - template: ../steps/build-all-tests-step.yml@self # build tests parameters: targetFramework: ${{ parameters.targetFramework }} - referenceType: ${{ parameters.buildType }} + referenceType: ${{ parameters.referenceType }} testSet: ${{ parameters.testSet }} + abstractionsPackageVersion: ${{ parameters.abstractionsPackageVersion }} + mdsPackageVersion: ${{ parameters.mdsPackageVersion }} ${{ if ne(parameters.operatingSystem, 'Windows') }}: OSGroup: Unix @@ -237,7 +262,7 @@ jobs: parameters: debug: ${{ parameters.debug }} targetFramework: ${{ parameters.targetFramework }} - referenceType: ${{ parameters.buildType }} + referenceType: ${{ parameters.referenceType }} testSet: ${{ parameters.testSet }} operatingSystem: ${{ parameters.operatingSystem }} @@ -279,13 +304,13 @@ jobs: parameters: debug: ${{ parameters.debug }} targetFramework: ${{ parameters.targetFramework }} - referenceType: ${{ parameters.buildType }} + referenceType: ${{ parameters.referenceType }} testSet: ${{ parameters.testSet }} msbuildArchitecture: x86 dotnetx86RootPath: $(dotnetx86RootPath) operatingSystem: ${{ parameters.operatingSystem }} - - ${{ if and(eq(parameters.publishTestResults, true), eq(parameters.buildType, 'Project')) }}: # publish test results if build type is project + - ${{ if and(eq(parameters.publishTestResults, true), eq(parameters.referenceType, 'Project')) }}: # publish test results if build type is project - template: ../steps/publish-test-results-step.yml@self parameters: debug: ${{ parameters.debug }} diff --git a/eng/pipelines/common/templates/jobs/run-tests-package-reference-job.yml b/eng/pipelines/common/templates/jobs/run-tests-package-reference-job.yml index 14aea42411..c422ffdc34 100644 --- a/eng/pipelines/common/templates/jobs/run-tests-package-reference-job.yml +++ b/eng/pipelines/common/templates/jobs/run-tests-package-reference-job.yml @@ -52,8 +52,6 @@ jobs: - template: ../steps/update-nuget-config-local-feed-step.yml parameters: downloadedNugetPath: $(Pipeline.Workspace)\${{parameters.packageFolderName }} - ${{ if parameters.isPreview }}: - nugetPackageVersion: $(PreviewNugetPackageVersion) - template: ../steps/update-config-file-step.yml parameters: @@ -68,11 +66,11 @@ jobs: parameters: referenceType: Package ${{ if parameters.isPreview }}: - nugetPackageVersion: $(PreviewNugetPackageVersion) + mdsPackageVersion: $(previewMdsPackageVersion) - template: ../steps/build-and-run-tests-netcore-step.yml parameters: referenceType: Package cleanFirst: true ${{ if parameters.isPreview }}: - nugetPackageVersion: $(PreviewNugetPackageVersion) + mdsPackageVersion: $(previewMdsPackageVersion) diff --git a/eng/pipelines/common/templates/jobs/validate-signed-package-job.yml b/eng/pipelines/common/templates/jobs/validate-signed-package-job.yml index 009e6f2647..333e78ffd4 100644 --- a/eng/pipelines/common/templates/jobs/validate-signed-package-job.yml +++ b/eng/pipelines/common/templates/jobs/validate-signed-package-job.yml @@ -54,18 +54,18 @@ jobs: value: $(Pipeline.Workspace)\${{parameters.packageFolderName }} - name: ProductVersion #MDS product version (MDS validation) - value: $(NugetPackageVersion) + value: $(mdsPackageVersion) - name: BuildType value: $[ stageDependencies.buildMDS.build_signed_package.outputs['GetBuildType.CDP_BUILD_TYPE_COPY'] ] - ${{ if parameters.isPreview }}: - name: extractedNugetPath - value: $(extractedNugetRootPath).$(PreviewNugetPackageVersion) - - name: NugetPackageVersion - value: $(PreviewNugetPackageVersion) + value: $(extractedNugetRootPath).$(previewMdsPackageVersion) + - name: mdsPackageVersion + value: $(previewMdsPackageVersion) - name: ProductVersion - value: $(PreviewNugetPackageVersion) + value: $(previewMdsPackageVersion) steps: - script: SET @@ -75,7 +75,7 @@ jobs: displayName: 'Use NuGet' - powershell: | - #Sets Variables for AssemblyFileVersion, AssemblyVersion and NugetPackageVersion + # Sets the pipeline ASSEMBLY_VERSION variable. [Xml] $versionprops = Get-Content -Path ".\tools\props\Versions.props" Write-Host $versionprops.Project.PropertyGroup[0].AssemblyFileVersion @@ -336,7 +336,7 @@ jobs: [Xml] $versionprops = Get-Content -Path "tools/props/Versions.props" $versionpropspath = "tools\props\Versions.props" - $versionprops.Project.PropertyGroup[$versionprops.Project.PropertyGroup.Count-1].TestMicrosoftDataSqlClientVersion ="$(NugetPackageVersion)" + $versionprops.Project.PropertyGroup[$versionprops.Project.PropertyGroup.Count-1].TestMicrosoftDataSqlClientVersion ="$(mdsPackageVersion)" Write-Host "Saving Test nuget version at $rootfolder\props ...." -ForegroundColor Green $versionprops.Save($versionpropspath) diff --git a/eng/pipelines/common/templates/stages/ci-run-tests-stage.yml b/eng/pipelines/common/templates/stages/ci-run-tests-stage.yml index e07685407f..994bb4f345 100644 --- a/eng/pipelines/common/templates/stages/ci-run-tests-stage.yml +++ b/eng/pipelines/common/templates/stages/ci-run-tests-stage.yml @@ -4,32 +4,44 @@ # See the LICENSE file in the project root for more information. # ################################################################################# parameters: - - name: debug - type: boolean - default: false - - - name: testConfigurations - type: object + - name: abstractionsArtifactName + type: string - - name: dependsOn + - name: abstractionsPackageVersion type: string - default: '' - - name: buildType - displayName: 'Build Type' + - name: referenceType default: Project values: - Project - Package - - name: prebuildSteps - type: stepList + - name: debug + type: boolean + default: false + + - name: dependsOn + type: object default: [] + + - name: mdsArtifactName + type: string + default: MDS.Artifact + + - name: mdsPackageVersion + type: string - name: postTestJobs type: jobList default: [] + - name: prebuildSteps + type: stepList + default: [] + + - name: testConfigurations + type: object + # The timeout, in minutes, for each test job. - name: testsTimeout type: string @@ -39,10 +51,7 @@ stages: - ${{ each config in parameters.testConfigurations }}: - ${{ each image in config.value.images }}: - stage: ${{ image.key }} - ${{ if ne(parameters.dependsOn, '') }}: - dependsOn: ${{ parameters.dependsOn }} - ${{ else }}: - dependsOn: [] + dependsOn: ${{ parameters.dependsOn }} jobs: - ${{ each targetFramework in config.value.TargetFrameworks }}: - ${{ each platform in config.value.buildPlatforms }}: @@ -51,13 +60,17 @@ stages: - template: ../jobs/ci-run-tests-job.yml@self parameters: debug: ${{ parameters.debug }} - buildType: ${{ parameters.buildType }} + referenceType: ${{ parameters.referenceType }} timeout: ${{ parameters.testsTimeout }} poolName: ${{ config.value.pool }} hostedPool: ${{ eq(config.value.hostedPool, true) }} image: ${{ image.value }} jobDisplayName: ${{ format('{0}_{1}_{2}', replace(targetFramework, '.', '_'), platform, testSet) }} configProperties: ${{ config.value.configProperties }} + abstractionsArtifactName: ${{ parameters.abstractionsArtifactName }} + abstractionsPackageVersion: ${{parameters.abstractionsPackageVersion}} + mdsArtifactName: ${{ parameters.mdsArtifactName }} + mdsPackageVersion: ${{ parameters.mdsPackageVersion }} prebuildSteps: ${{ parameters.prebuildSteps }} targetFramework: ${{ targetFramework }} netcoreVersionTestUtils: ${{config.value.netcoreVersionTestUtils }} @@ -77,7 +90,7 @@ stages: - template: ../jobs/ci-run-tests-job.yml@self parameters: debug: ${{ parameters.debug }} - buildType: ${{ parameters.buildType }} + referenceType: ${{ parameters.referenceType }} timeout: ${{ parameters.testsTimeout }} poolName: ${{ config.value.pool }} hostedPool: ${{ eq(config.value.hostedPool, true) }} @@ -88,6 +101,10 @@ stages: jobDisplayName: ${{ format('{0}_{1}_{2}_{3}', replace(targetFramework, '.', '_'), platform, 'NativeSNI', testSet) }} configProperties: ${{ config.value.configProperties }} useManagedSNI: ${{ useManagedSNI }} + abstractionsArtifactName: ${{ parameters.abstractionsArtifactName }} + abstractionsPackageVersion: ${{parameters.abstractionsPackageVersion}} + mdsArtifactName: ${{ parameters.mdsArtifactName }} + mdsPackageVersion: ${{ parameters.mdsPackageVersion }} prebuildSteps: ${{ parameters.prebuildSteps }} targetFramework: ${{ targetFramework }} netcoreVersionTestUtils: ${{config.value.netcoreVersionTestUtils }} diff --git a/eng/pipelines/common/templates/steps/build-all-tests-step.yml b/eng/pipelines/common/templates/steps/build-all-tests-step.yml index 826be1df8b..43ecb6aafa 100644 --- a/eng/pipelines/common/templates/steps/build-all-tests-step.yml +++ b/eng/pipelines/common/templates/steps/build-all-tests-step.yml @@ -4,31 +4,33 @@ # See the LICENSE file in the project root for more information. # ################################################################################# parameters: - - name: targetFramework + - name: abstractionsPackageVersion + type: string + + - name: configuration + type: string + default: '$(Configuration)' + + - name: mdsPackageVersion type: string - - name: nugetPackageVersion + - name: osGroup type: string - default: $(NugetPackageVersion) + default: '' - name: platform type: string default: $(Platform) - - - name: configuration - type: string - default: '$(Configuration)' - name: referenceType - default: Package + type: string values: - Project - Package - - - name: OSGroup - type: string - default: '' + - name: targetFramework + type: string + - name: testSet type: string @@ -40,26 +42,16 @@ steps: solution: build.proj platform: '${{parameters.platform }}' configuration: '${{parameters.configuration }}' - msbuildArguments: '-t:BuildTestsNetFx -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.nugetPackageVersion }}' - -# - ${{else if contains(parameters.targetFramework, 'netstandard')}}: # .NET Standard -# - task: MSBuild@1 -# displayName: 'Build Tests NetStandard' -# inputs: -# solution: build.proj -# platform: '${{parameters.platform }}' -# configuration: '${{parameters.configuration }}' -# msbuildArguments: '-t:BuildTestsNetCore -p:ReferenceType=NetStandard -p:TargetNetStandardVersion=${{parameters.targetNetStandardVersion }} -p:TF=${{parameters.targetFramework }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.nugetPackageVersion }}' -# condition: and(succeeded(), not(startsWith(variables['TF'], 'net4')), startsWith(variables['TargetNetStandardVersion'], 'netstandard')) + msbuildArguments: '-t:BuildTestsNetFx -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }} -p:AbstractionsPackageVersion=${{ parameters.abstractionsPackageVersion }}' -- ${{elseif eq(parameters.OSGroup, '')}}: # .NET on Windows +- ${{elseif eq(parameters.osGroup, '')}}: # .NET on Windows - task: MSBuild@1 displayName: 'Build Tests NetCore [Win]' inputs: solution: build.proj platform: '${{parameters.platform }}' configuration: '${{parameters.configuration }}' - msbuildArguments: '-t:BuildTestsNetCore -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.nugetPackageVersion }}' + msbuildArguments: '-t:BuildTestsNetCore -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }} -p:AbstractionsPackageVersion=${{ parameters.abstractionsPackageVersion }}' condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT')) - ${{ else }}: # .NET on Unix @@ -69,7 +61,7 @@ steps: command: custom projects: build.proj custom: msbuild - arguments: '-t:BuildTestsNetCore -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.nugetPackageVersion }} -p:OSGroup=${{parameters.OSGroup }} -p:platform=${{parameters.platform }} -p:Configuration=${{parameters.configuration }}' + arguments: '-t:BuildTestsNetCore -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }} -p:OSGroup=${{parameters.osGroup }} -p:platform=${{parameters.platform }} -p:Configuration=${{parameters.configuration }} -p:AbstractionsPackageVersion=${{ parameters.abstractionsPackageVersion }}' verbosityRestore: Detailed verbosityPack: Detailed condition: and(succeeded(), ne(variables['Agent.OS'], 'Windows_NT')) diff --git a/eng/pipelines/common/templates/steps/build-and-run-tests-netcore-step.yml b/eng/pipelines/common/templates/steps/build-and-run-tests-netcore-step.yml index c70fe776a7..43eea4449d 100644 --- a/eng/pipelines/common/templates/steps/build-and-run-tests-netcore-step.yml +++ b/eng/pipelines/common/templates/steps/build-and-run-tests-netcore-step.yml @@ -18,9 +18,9 @@ parameters: - Project - Package - - name: NugetPackageVersion + - name: mdsPackageVersion type: string - default: $(NugetPackageVersion) + default: $(mdsPackageVersion) - name: platform type: string @@ -55,14 +55,14 @@ steps: inputs: solution: build.proj msbuildArchitecture: x64 - msbuildArguments: '-p:Configuration=${{parameters.configuration }} -t:BuildAKVNetCore -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.NugetPackageVersion }}' + msbuildArguments: '-p:Configuration=${{parameters.configuration }} -t:BuildAKVNetCore -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }}' - task: MSBuild@1 displayName: 'MSBuild Build Tests for ${{parameters.TargetNetCoreVersion }}' inputs: solution: build.proj msbuildArchitecture: x64 - msbuildArguments: '-t:BuildTestsNetCore -p:ReferenceType=${{parameters.referenceType }} -p:TargetNetCoreVersion=${{parameters.TargetNetCoreVersion }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.NugetPackageVersion }} -p:Configuration=${{parameters.configuration }}' + msbuildArguments: '-t:BuildTestsNetCore -p:ReferenceType=${{parameters.referenceType }} -p:TargetNetCoreVersion=${{parameters.TargetNetCoreVersion }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }} -p:Configuration=${{parameters.configuration }}' # Don't run unit tests using package reference. Unit tests are only run using project reference. @@ -71,12 +71,12 @@ steps: inputs: command: test projects: 'src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.FunctionalTests.csproj' - arguments: '-p:Platform=${{parameters.platform }} -p:TestTargetOS="${{parameters.TestTargetOS }}" -p:TargetNetCoreVersion=${{parameters.TargetNetCoreVersion }} -p:ReferenceType=${{parameters.referenceType }} -p:Configuration=${{parameters.configuration }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.NugetPackageVersion }} --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests"' + arguments: '-p:Platform=${{parameters.platform }} -p:TestTargetOS="${{parameters.TestTargetOS }}" -p:TargetNetCoreVersion=${{parameters.TargetNetCoreVersion }} -p:ReferenceType=${{parameters.referenceType }} -p:Configuration=${{parameters.configuration }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }} --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests"' - task: DotNetCoreCLI@2 displayName: 'Run Manual Tests for ${{parameters.TargetNetCoreVersion }}' inputs: command: test projects: 'src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj' - arguments: '-p:Platform=${{parameters.platform }} -p:TestTargetOS="${{parameters.TestTargetOS }}" -p:TargetNetCoreVersion=${{parameters.TargetNetCoreVersion }} -p:ReferenceType=${{parameters.referenceType }} -p:Configuration=${{parameters.configuration }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.NugetPackageVersion }} --no-build -v n --filter category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests --collect "Code Coverage"' + arguments: '-p:Platform=${{parameters.platform }} -p:TestTargetOS="${{parameters.TestTargetOS }}" -p:TargetNetCoreVersion=${{parameters.TargetNetCoreVersion }} -p:ReferenceType=${{parameters.referenceType }} -p:Configuration=${{parameters.configuration }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }} --no-build -v n --filter category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests --collect "Code Coverage"' retryCountOnTaskFailure: ${{parameters.retryCountOnManualTests }} diff --git a/eng/pipelines/common/templates/steps/build-and-run-tests-netfx-step.yml b/eng/pipelines/common/templates/steps/build-and-run-tests-netfx-step.yml index 5d9f194c48..e7b35f653e 100644 --- a/eng/pipelines/common/templates/steps/build-and-run-tests-netfx-step.yml +++ b/eng/pipelines/common/templates/steps/build-and-run-tests-netfx-step.yml @@ -18,9 +18,9 @@ parameters: - Project - Package - - name: NugetPackageVersion + - name: mdsPackageVersion type: string - default: $(NugetPackageVersion) + default: $(mdsPackageVersion) - name: platform type: string @@ -55,13 +55,13 @@ steps: inputs: solution: build.proj msbuildArchitecture: x64 - msbuildArguments: '-p:Configuration=${{parameters.configuration }} -t:BuildAKVNetFx -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.NugetPackageVersion }}' + msbuildArguments: '-p:Configuration=${{parameters.configuration }} -t:BuildAKVNetFx -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }}' - task: MSBuild@1 displayName: 'MSBuild Build Tests for ${{parameters.TargetNetFxVersion }}' inputs: solution: build.proj - msbuildArguments: ' -t:BuildTestsNetFx -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.NugetPackageVersion }} -p:TargetNetFxVersion=${{parameters.TargetNetFxVersion }} -p:Configuration=${{parameters.configuration }} -p:Platform=${{parameters.platform }}' + msbuildArguments: ' -t:BuildTestsNetFx -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }} -p:TargetNetFxVersion=${{parameters.TargetNetFxVersion }} -p:Configuration=${{parameters.configuration }} -p:Platform=${{parameters.platform }}' # Don't run unit tests using package reference. Unit tests are only run using project reference. @@ -70,12 +70,12 @@ steps: inputs: command: test projects: 'src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.FunctionalTests.csproj' - arguments: '-p:Platform=${{parameters.platform }} -p:TestTargetOS="${{parameters.TestTargetOS }}" -p:TargetNetFxVersion=${{parameters.TargetNetFxVersion }} -p:ReferenceType=${{parameters.referenceType }} -p:Configuration=${{parameters.configuration }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.NugetPackageVersion }} --no-build -v n --filter "category!=nonnetfxtests&category!=failing&category!=nonwindowstests" --collect "Code Coverage"' + arguments: '-p:Platform=${{parameters.platform }} -p:TestTargetOS="${{parameters.TestTargetOS }}" -p:TargetNetFxVersion=${{parameters.TargetNetFxVersion }} -p:ReferenceType=${{parameters.referenceType }} -p:Configuration=${{parameters.configuration }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }} --no-build -v n --filter "category!=nonnetfxtests&category!=failing&category!=nonwindowstests" --collect "Code Coverage"' - task: DotNetCoreCLI@2 displayName: 'Run Manual Tests for ${{parameters.TargetNetFxVersion }}' inputs: command: test projects: 'src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj' - arguments: '-p:Platform=${{parameters.platform }} -p:TestTargetOS="${{parameters.TestTargetOS }}" -p:TargetNetFxVersion=${{parameters.TargetNetFxVersion }} -p:ReferenceType=${{parameters.referenceType }} -p:Configuration=${{parameters.configuration }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.NugetPackageVersion }} --no-build -v n --filter "category!=nonnetfxtests&category!=failing&category!=nonwindowstests" --collect "Code Coverage"' + arguments: '-p:Platform=${{parameters.platform }} -p:TestTargetOS="${{parameters.TestTargetOS }}" -p:TargetNetFxVersion=${{parameters.TargetNetFxVersion }} -p:ReferenceType=${{parameters.referenceType }} -p:Configuration=${{parameters.configuration }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }} --no-build -v n --filter "category!=nonnetfxtests&category!=failing&category!=nonwindowstests" --collect "Code Coverage"' retryCountOnTaskFailure: ${{parameters.retryCountOnManualTests }} diff --git a/eng/pipelines/common/templates/steps/ci-prebuild-step.yml b/eng/pipelines/common/templates/steps/ci-prebuild-step.yml index efe17856d8..4eedd5dfd4 100644 --- a/eng/pipelines/common/templates/steps/ci-prebuild-step.yml +++ b/eng/pipelines/common/templates/steps/ci-prebuild-step.yml @@ -8,13 +8,8 @@ parameters: type: boolean default: false - - name: artifactName + - name: referenceType type: string - default: Artifacts - - - name: buildType - displayName: 'Build Type' - default: Project values: - Project - Package @@ -37,21 +32,8 @@ steps: Get-ChildItem env: | Sort-Object Name displayName: 'List Environment Variables [debug]' -- ${{if eq(parameters.buildType, 'Package')}}: - - task: DownloadPipelineArtifact@2 - displayName: 'Download NuGet Package' - inputs: - buildType: current - artifact: ${{parameters.artifactName }} - patterns: '**/*.nupkg' - targetPath: $(Pipeline.Workspace)/${{parameters.artifactName }} - +- ${{if eq(parameters.referenceType, 'Package')}}: - template: update-nuget-config-local-feed-step.yml@self parameters: - downloadedNugetPath: $(Pipeline.Workspace)\${{parameters.artifactName }} + downloadedNugetPath: $(Build.SourcesDirectory)/packages debug: ${{ parameters.debug }} - -- ${{ else }}: # project - - template: ci-project-build-step.yml@self - parameters: - build: allNoDocs diff --git a/eng/pipelines/common/templates/steps/ci-project-build-step.yml b/eng/pipelines/common/templates/steps/ci-project-build-step.yml index e938c909fd..8353779198 100644 --- a/eng/pipelines/common/templates/steps/ci-project-build-step.yml +++ b/eng/pipelines/common/templates/steps/ci-project-build-step.yml @@ -34,6 +34,10 @@ parameters: - all - allNoDocs + - name: abstractionsPackageVersion + displayName: Abstractions Package Version + type: string + steps: - template: ./ensure-dotnet-version.yml@self parameters: @@ -48,24 +52,24 @@ steps: - ${{ if or(eq(parameters.operatingSystem, 'Windows'), eq(parameters.operatingSystem, 'deferedToRuntime')) }}: - ${{ if or(eq(parameters.build, 'MDS'), eq(parameters.build, 'all'), eq(parameters.build, 'allNoDocs')) }}: - task: MSBuild@1 - displayName: 'Restore nugets [Win]' + displayName: 'Restore [Win]' condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT')) inputs: solution: build.proj msbuildArchitecture: x64 - msbuildArguments: '-t:restore' + msbuildArguments: '-t:restore -p:AbstractionsPackageVersion=${{parameters.abstractionsPackageVersion}}' retryCountOnTaskFailure: 1 - ${{ if eq(parameters.build, 'allNoDocs') }}: - task: MSBuild@1 - displayName: 'Build Driver [Win]' + displayName: 'Build Driver (no docs) [Win]' condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT')) inputs: solution: build.proj msbuildArchitecture: x64 platform: '${{ parameters.platform }}' configuration: '${{ parameters.configuration }}' - msbuildArguments: '-t:BuildAllConfigurations -p:GenerateDocumentationFile=false -p:GenerateNuGet=false -p:BuildNumber=${{ parameters.buildNumber }}' + msbuildArguments: '-t:BuildAllConfigurations -p:GenerateDocumentationFile=false -p:GenerateNuGet=false -p:BuildNumber=${{ parameters.buildNumber }} -p:AbstractionsPackageVersion=${{parameters.abstractionsPackageVersion}}' clean: true - ${{ if or(eq(parameters.build, 'MDS'), eq(parameters.build, 'all')) }}: @@ -77,7 +81,7 @@ steps: msbuildArchitecture: x64 platform: '${{ parameters.platform }}' configuration: '${{ parameters.configuration }}' - msbuildArguments: '-t:BuildAllConfigurations -p:GenerateNuGet=false -p:BuildNumber=${{ parameters.buildNumber }}' + msbuildArguments: '-t:BuildAllConfigurations -p:GenerateNuGet=false -p:BuildNumber=${{ parameters.buildNumber }} -p:AbstractionsPackageVersion=${{parameters.abstractionsPackageVersion}}' clean: true - ${{ if or(eq(parameters.build, 'AKV'), eq(parameters.build, 'all'), eq(parameters.build, 'allNoDocs')) }}: @@ -89,7 +93,7 @@ steps: msbuildArchitecture: x64 platform: '${{ parameters.platform }}' configuration: '${{ parameters.configuration }}' - msbuildArguments: '-t:BuildAKVNetFx -p:BuildNumber=${{ parameters.buildNumber }}' + msbuildArguments: '-t:BuildAKVNetFx -p:BuildNumber=${{ parameters.buildNumber }} -p:AbstractionsPackageVersion=${{parameters.abstractionsPackageVersion}}' - task: MSBuild@1 displayName: 'Build AKV Provider NetCore All OS [Win]' @@ -99,17 +103,17 @@ steps: msbuildArchitecture: x64 platform: '${{ parameters.platform }}' configuration: '${{ parameters.configuration }}' - msbuildArguments: '-t:BuildAKVNetCoreAllOS -p:BuildNumber=${{ parameters.buildNumber }}' + msbuildArguments: '-t:BuildAKVNetCoreAllOS -p:BuildNumber=${{ parameters.buildNumber }} -p:AbstractionsPackageVersion=${{parameters.abstractionsPackageVersion}}' - ${{ if or(eq(parameters.operatingSystem, 'Linux'), eq(parameters.operatingSystem, 'MacOS'), eq(parameters.operatingSystem, 'deferedToRuntime')) }}: - task: DotNetCoreCLI@2 - displayName: 'Build Driver [non-Win]' + displayName: 'Build Driver [${{ parameters.operatingSystem }}]' condition: and(succeeded(), ne(variables['Agent.OS'], 'Windows_NT')) inputs: command: custom projects: build.proj custom: msbuild - arguments: '-t:BuildAll -p:TestEnabled=true -p:GenerateDocumentationFile=false -p:configuration=${{ parameters.configuration }}' + arguments: '-t:BuildAll -p:TestEnabled=true -p:GenerateDocumentationFile=false -p:configuration=${{ parameters.configuration }} -p:AbstractionsPackageVersion=${{parameters.abstractionsPackageVersion}}' verbosityRestore: Detailed verbosityPack: Detailed retryCountOnTaskFailure: 1 diff --git a/eng/pipelines/common/templates/steps/generate-nuget-package-step.yml b/eng/pipelines/common/templates/steps/generate-nuget-package-step.yml index 4e32f989c3..1afd22c063 100644 --- a/eng/pipelines/common/templates/steps/generate-nuget-package-step.yml +++ b/eng/pipelines/common/templates/steps/generate-nuget-package-step.yml @@ -8,9 +8,9 @@ parameters: type: string default: '$(nuspecPath)' - - name: NugetPackageVersion + - name: mdsPackageVersion type: string - default: '$(NugetPackageVersion)' + default: '$(mdsPackageVersion)' - name: OutputDirectory type: string @@ -55,6 +55,6 @@ steps: inputs: command: custom ${{ if parameters.generateSymbolsPackage }}: - arguments: 'pack -Symbols -SymbolPackageFormat snupkg ${{parameters.nuspecPath}} -Version ${{parameters.NugetPackageVersion}} -OutputDirectory ${{parameters.OutputDirectory}} -properties "COMMITID=$(CommitHead);Configuration=${{parameters.Configuration}};ReferenceType=${{parameters.referenceType}}"' + arguments: 'pack -Symbols -SymbolPackageFormat snupkg ${{parameters.nuspecPath}} -Version ${{parameters.mdsPackageVersion}} -OutputDirectory ${{parameters.OutputDirectory}} -properties "COMMITID=$(CommitHead);Configuration=${{parameters.Configuration}};ReferenceType=${{parameters.referenceType}}"' ${{else }}: - arguments: 'pack ${{parameters.nuspecPath}} -Version ${{parameters.NugetPackageVersion}} -OutputDirectory ${{parameters.OutputDirectory}} -properties "COMMITID=$(CommitHead);Configuration=${{parameters.Configuration}};ReferenceType=${{parameters.referenceType}}"' + arguments: 'pack ${{parameters.nuspecPath}} -Version ${{parameters.mdsPackageVersion}} -OutputDirectory ${{parameters.OutputDirectory}} -properties "COMMITID=$(CommitHead);Configuration=${{parameters.Configuration}};ReferenceType=${{parameters.referenceType}}"' diff --git a/eng/pipelines/common/templates/steps/publish-symbols-step.yml b/eng/pipelines/common/templates/steps/publish-symbols-step.yml index 5f8d2e6a7d..8999a6cc1d 100644 --- a/eng/pipelines/common/templates/steps/publish-symbols-step.yml +++ b/eng/pipelines/common/templates/steps/publish-symbols-step.yml @@ -15,7 +15,7 @@ parameters: - name: symbolsVersion type: string - default: '$(NuGetPackageVersion)' + default: '$(mdsPackageVersion)' - name: symbolServer type: string diff --git a/eng/pipelines/common/templates/steps/run-all-tests-step.yml b/eng/pipelines/common/templates/steps/run-all-tests-step.yml index b9a870ada4..27da9e4e73 100644 --- a/eng/pipelines/common/templates/steps/run-all-tests-step.yml +++ b/eng/pipelines/common/templates/steps/run-all-tests-step.yml @@ -11,9 +11,9 @@ parameters: - name: targetFramework type: string - - name: nugetPackageVersion + - name: mdsPackageVersion type: string - default: $(NugetPackageVersion) + default: $(mdsPackageVersion) - name: platform type: string @@ -62,9 +62,9 @@ steps: platform: '${{parameters.platform }}' configuration: '${{parameters.configuration }}' ${{ if eq(parameters.msbuildArchitecture, 'x64') }}: - msbuildArguments: '-t:RunUnitTests -p:TF=${{parameters.targetFramework }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.nugetPackageVersion }}' + msbuildArguments: '-t:RunUnitTests -p:TF=${{parameters.targetFramework }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }}' ${{ else }}: # x86 - msbuildArguments: '-t:RunUnitTests -p:TF=${{parameters.targetFramework }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.nugetPackageVersion }} -p:DotnetPath=${{parameters.dotnetx86RootPath }}' + msbuildArguments: '-t:RunUnitTests -p:TF=${{parameters.targetFramework }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }} -p:DotnetPath=${{parameters.dotnetx86RootPath }}' condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT')) retryCountOnTaskFailure: 1 @@ -76,9 +76,9 @@ steps: platform: '${{parameters.platform }}' configuration: '${{parameters.configuration }}' ${{ if eq(parameters.msbuildArchitecture, 'x64') }}: - msbuildArguments: '-t:RunFunctionalTests -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.nugetPackageVersion }}' + msbuildArguments: '-t:RunFunctionalTests -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }}' ${{ else }}: # x86 - msbuildArguments: '-t:RunFunctionalTests -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.nugetPackageVersion }} -p:DotnetPath=${{parameters.dotnetx86RootPath }}' + msbuildArguments: '-t:RunFunctionalTests -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }} -p:DotnetPath=${{parameters.dotnetx86RootPath }}' condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT')) retryCountOnTaskFailure: 1 @@ -90,9 +90,9 @@ steps: platform: '${{parameters.platform }}' configuration: '${{parameters.configuration }}' ${{ if eq(parameters.msbuildArchitecture, 'x64') }}: - msbuildArguments: '-t:RunManualTests -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.nugetPackageVersion }}' + msbuildArguments: '-t:RunManualTests -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }}' ${{ else }}: # x86 - msbuildArguments: '-t:RunManualTests -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.nugetPackageVersion }} -p:DotnetPath=${{parameters.dotnetx86RootPath }}' + msbuildArguments: '-t:RunManualTests -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }} -p:DotnetPath=${{parameters.dotnetx86RootPath }}' condition: eq(variables['Agent.OS'], 'Windows_NT') retryCountOnTaskFailure: 2 @@ -104,7 +104,7 @@ steps: command: custom projects: build.proj custom: msbuild - arguments: '-t:RunUnitTests -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.nugetPackageVersion }} -p:platform=${{parameters.platform }} -p:Configuration=${{parameters.configuration }}' + arguments: '-t:RunUnitTests -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }} -p:platform=${{parameters.platform }} -p:Configuration=${{parameters.configuration }}' verbosityRestore: Detailed verbosityPack: Detailed retryCountOnTaskFailure: 1 @@ -116,7 +116,7 @@ steps: command: custom projects: build.proj custom: msbuild - arguments: '-t:RunFunctionalTests -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.nugetPackageVersion }} -p:platform=${{parameters.platform }} -p:Configuration=${{parameters.configuration }}' + arguments: '-t:RunFunctionalTests -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }} -p:platform=${{parameters.platform }} -p:Configuration=${{parameters.configuration }}' verbosityRestore: Detailed verbosityPack: Detailed retryCountOnTaskFailure: 1 @@ -128,7 +128,7 @@ steps: command: custom projects: build.proj custom: msbuild - arguments: '-t:RunManualTests -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.nugetPackageVersion }} -p:platform=${{parameters.platform }} -p:Configuration=${{parameters.configuration }}' + arguments: '-t:RunManualTests -p:TF=${{parameters.targetFramework }} -p:TestSet=${{parameters.testSet }} -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.mdsPackageVersion }} -p:platform=${{parameters.platform }} -p:Configuration=${{parameters.configuration }}' verbosityRestore: Detailed verbosityPack: Detailed retryCountOnTaskFailure: 2 diff --git a/eng/pipelines/common/templates/steps/update-nuget-config-local-feed-step.yml b/eng/pipelines/common/templates/steps/update-nuget-config-local-feed-step.yml index 4eac341108..f7bf252ebe 100644 --- a/eng/pipelines/common/templates/steps/update-nuget-config-local-feed-step.yml +++ b/eng/pipelines/common/templates/steps/update-nuget-config-local-feed-step.yml @@ -11,10 +11,6 @@ parameters: - name: downloadedNugetPath # path to the downloaded nuget files type: string - - name: nugetPackageVersion - type: string - default: $(NugetPackageVersion) - steps: - powershell: | # Get a list of package sources available @@ -34,7 +30,7 @@ steps: [Xml] $nugetConfig = Get-Content -Path "NuGet.config" $Value = Resolve-Path ${{parameters.downloadedNugetPath }} $newAdd = $nugetConfig.CreateElement("add") - $newAdd.SetAttribute("key","Package source") + $newAdd.SetAttribute("key","pipeline") $newAdd.SetAttribute("value", "$Value/" ) $nugetConfig.configuration.packageSources.AppendChild($newAdd) $nugetConfig.Save("$rootFolder/NuGet.config") @@ -45,39 +41,3 @@ steps: # Display the content of the NuGet.config file Get-Content -Path "NuGet.config" displayName: 'Read NuGet.config [debug]' - -- task: DotNetCoreCLI@2 - displayName: 'Restore NuGets' - inputs: - command: 'custom' - custom: 'msbuild' - arguments: 'build.proj -t:restore' - feedsToUse: 'select' - -- powershell: | - $Doc = [xml](Get-Content "./Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider.csproj") - $parent_xpath = '/Project/ItemGroup/ProjectReference' - $node = $Doc.SelectSingleNode($parent_xpath) - $parentNode = $node.ParentNode - while($node -ne $null) { - $node.ParentNode.RemoveChild($node) - $node = $Doc.SelectSingleNode($parent_xpath) - } - - $parent_xpath = '/Project/ItemGroup/PackageReference[@Include="Microsoft.Data.SqlClient"]' - $node = $Doc.SelectSingleNode($parent_xpath) - - if($node -eq $null){ - $packagerefnode = $doc.createelement("packagereference") - $value = $doc.selectsinglenode('/project/itemgroup/projectreference') - $attrinclude = $doc.createattribute("include") - $attrinclude.value = "microsoft.data.sqlclient" - $packagerefnode.attributes.append($attrinclude) - $parentNode.AppendChild($packageRefNode) - } - - $currentFolder = Get-Location - $filePath = Join-Path $currentFolder "Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider.csproj" - $Doc.Save($filePath) - workingDirectory: 'src/Microsoft.Data.SqlClient/add-ons/AzureKeyVaultProvider' - displayName: 'Update AKV Project Ref to Package Ref (.NET Framework/Core)' diff --git a/eng/pipelines/dotnet-sqlclient-ci-core.yml b/eng/pipelines/dotnet-sqlclient-ci-core.yml index 353122828b..e9b979a1f5 100644 --- a/eng/pipelines/dotnet-sqlclient-ci-core.yml +++ b/eng/pipelines/dotnet-sqlclient-ci-core.yml @@ -58,9 +58,12 @@ parameters: type: object default: [net462, net8.0] -- name: buildType - displayName: 'Build Type' - default: Project +# The way we will reference sibling projects in the .csproj files: +# Project - use references. +# Package - use references to NuGet packages in the +# packages/ directory. +- name: referenceType + displayName: 'Reference Type' values: - Project - Package @@ -89,20 +92,46 @@ parameters: variables: - template: libraries/ci-build-variables.yml@self - - name: artifactName - value: Artifacts + - name: abstractionsArtifactName + value: Abstractions.Artifact + + - name: mdsArtifactName + value: MDS.Artifact - name: defaultHostedPoolName value: 'Azure Pipelines' stages: - - stage: build_nugets - displayName: 'Build NuGet Packages' + + # Build the Abstractions package, and publish it to the pipeline artifacts + # under the name specified by the 'abstractionsArtifactName' variable. + - template: stages/build-abstractions-package-ci-stage.yml@self + parameters: + buildConfiguration: Release + packageVersion: $(abstractionsPackageVersion) + buildNumber: $(buildNumber) + artifactName: $(abstractionsArtifactName) + ${{if eq(parameters.debug, 'true')}}: + verbosity: diagnostic + + # Build MDS and its NuGet packages. + - stage: build_mds_package + displayName: 'Build MDS Package' + + # When building MDS via packages, we must depend on the Abstractions + # package. + ${{ if eq(parameters.referenceType, 'Package') }}: + dependsOn: + - build_abstractions_package_stage + jobs: - template: common/templates/jobs/ci-build-nugets-job.yml@self parameters: + referenceType: ${{ parameters.referenceType }} configuration: ${{ parameters.buildConfiguration }} - artifactName: $(artifactName) + abstractionsPackageVersion: $(abstractionsPackageVersion) + abstractionsArtifactName: $(abstractionsArtifactName) + mdsArtifactName: $(mdsArtifactName) ${{if ne(parameters.SNIVersion, '')}}: prebuildSteps: - template: common/templates/steps/override-sni-version.yml@self @@ -114,40 +143,42 @@ stages: - template: stages/stress-tests-ci-stage.yml@self parameters: buildConfiguration: ${{ parameters.buildConfiguration }} - dependsOn: [build_nugets] + dependsOn: [build_mds_packages_job] pipelineArtifactName: $(artifactName) - mdsPackageVersion: $(NugetPackageVersion) + mdsPackageVersion: $(mdsPackageVersion) ${{ if eq(parameters.debug, 'true') }}: verbosity: 'detailed' - template: common/templates/stages/ci-run-tests-stage.yml@self parameters: debug: ${{ parameters.debug }} - buildType: ${{ parameters.buildType }} + referenceType: ${{ parameters.referenceType }} testsTimeout: ${{ parameters.testsTimeout }} - ${{ if eq(parameters.buildType, 'Package') }}: - dependsOn: build_nugets - - ${{if ne(parameters.SNIVersion, '')}}: - prebuildSteps: # steps to run prior to building and running tests on each job + abstractionsArtifactName: $(abstractionsArtifactName) + abstractionsPackageVersion: $(abstractionsPackageVersion) + mdsArtifactName: $(mdsArtifactName) + mdsPackageVersion: $(mdsPackageVersion) + + # When testing MDS via packages, we must depend on the Abstractions and + # MDS packages. + ${{ if eq(parameters.referenceType, 'Package') }}: + dependsOn: + - build_abstractions_package_stage + - build_nugets + + prebuildSteps: # steps to run prior to building and running tests on each job + - ${{if ne(parameters.SNIVersion, '')}}: - template: common/templates/steps/override-sni-version.yml@self parameters: SNIVersion: ${{parameters.SNIVersion}} SNIValidationFeed: ${{parameters.SNIValidationFeed}} - - template: common/templates/steps/ci-prebuild-step.yml@self - parameters: - debug: ${{ parameters.debug }} - artifactName: $(artifactName) - buildType: ${{ parameters.buildType }} - ${{else}}: - prebuildSteps: # steps to run prior to building and running tests on each job - - template: common/templates/steps/ci-prebuild-step.yml@self - parameters: - debug: ${{ parameters.debug }} - artifactName: $(artifactName) - buildType: ${{ parameters.buildType }} - ${{ if eq(parameters.buildType, 'Project') }}: # only run the code coverage job if the build type is project + - template: common/templates/steps/ci-prebuild-step.yml@self + parameters: + debug: ${{ parameters.debug }} + referenceType: ${{ parameters.referenceType }} + + ${{ if eq(parameters.referenceType, 'Project') }}: # only run the code coverage job if the build type is project postTestJobs: # jobs to run after the tests are done - template: common/templates/jobs/ci-code-coverage-job.yml@self parameters: @@ -354,9 +385,8 @@ stages: # ways to detect if they were present) won't run consistently across forks and non-forks. ${{ if eq(variables['system.pullRequest.isFork'], 'False') }}: AADPasswordConnectionString: $(AAD_PASSWORD_CONN_STR) - AADServicePrincipalId: $(AADServicePrincipalId) - ${{ if eq(variables['system.pullRequest.isFork'], 'False') }}: AADServicePrincipalSecret: $(AADServicePrincipalSecret) + AADServicePrincipalId: $(AADServicePrincipalId) AzureKeyVaultUrl: $(AzureKeyVaultUrl) AzureKeyVaultTenantId: $(AzureKeyVaultTenantId) SupportsIntegratedSecurity: false @@ -383,9 +413,8 @@ stages: AADAuthorityURL: $(AADAuthorityURL) ${{ if eq(variables['system.pullRequest.isFork'], 'False') }}: AADPasswordConnectionString: $(AAD_PASSWORD_CONN_STR_eastus) - AADServicePrincipalId: $(AADServicePrincipalId) - ${{ if eq(variables['system.pullRequest.isFork'], 'False') }}: AADServicePrincipalSecret: $(AADServicePrincipalSecret) + AADServicePrincipalId: $(AADServicePrincipalId) AzureKeyVaultUrl: $(AzureKeyVaultUrl) AzureKeyVaultTenantId: $(AzureKeyVaultTenantId) SupportsIntegratedSecurity: false @@ -393,37 +422,6 @@ stages: LocalDbAppName: $(LocalDbAppName) LocalDbSharedInstanceName: $(LocalDbSharedInstanceName) - ${{ if eq(variables['system.pullRequest.isFork'], 'False') }}: # only run enclave jobs if the password is available - windows_enclave_sql: - pool: ADO-CI-AE-1ES-Pool - images: - Win22_Enclave_Sql19: ADO-MMS22-SQL19 - TargetFrameworks: ${{parameters.targetFrameworks }} - netcoreVersionTestUtils: ${{parameters.netcoreVersionTestUtils }} - buildPlatforms: ${{parameters.buildPlatforms }} - testSets: [AE] - useManagedSNI: ${{parameters.useManagedSNI }} - codeCovTargetFrameworks: ${{parameters.codeCovTargetFrameworks }} - configSqlFor: enclave - operatingSystem: Windows - configProperties: - # config.json properties - TCPConnectionStringHGSVBS: $(SQL_TCP_CONN_STRING_HGSVBS) - TCPConnectionStringNoneVBS: $(SQL_TCP_CONN_STRING_NoneVBS) - TCPConnectionStringAASSGX: $(SQL_TCP_CONN_STRING_AASSGX) - EnclaveEnabled: true - AADAuthorityURL: $(AADAuthorityURL) - AADServicePrincipalId: $(AADServicePrincipalId) - ${{ if eq(variables['system.pullRequest.isFork'], 'False') }}: - AADServicePrincipalSecret: $(AADServicePrincipalSecret) - AzureKeyVaultUrl: $(AzureKeyVaultUrl) - AzureKeyVaultTenantId: $(AzureKeyVaultTenantId) - SupportsIntegratedSecurity: $(SupportsIntegratedSecurity) - UserManagedIdentityClientId: $(UserManagedIdentityClientId) - AliasName: $(SQLAliasName) - LocalDbAppName: $(LocalDbAppName) - LocalDbSharedInstanceName: $(LocalDbSharedInstanceName) - # self hosted SQL Server on Linux linux_sql_19_22: pool: ${{parameters.defaultPoolName }} @@ -469,9 +467,8 @@ stages: AADAuthorityURL: $(AADAuthorityURL) ${{ if eq(variables['system.pullRequest.isFork'], 'False') }}: AADPasswordConnectionString: $(AAD_PASSWORD_CONN_STR) - AADServicePrincipalId: $(AADServicePrincipalId) - ${{ if eq(variables['system.pullRequest.isFork'], 'False') }}: AADServicePrincipalSecret: $(AADServicePrincipalSecret) + AADServicePrincipalId: $(AADServicePrincipalId) AzureKeyVaultUrl: $(AzureKeyVaultUrl) AzureKeyVaultTenantId: $(AzureKeyVaultTenantId) SupportsIntegratedSecurity: false @@ -479,7 +476,65 @@ stages: LocalDbAppName: $(LocalDbAppName) LocalDbSharedInstanceName: $(LocalDbSharedInstanceName) - ${{ if eq(variables['system.pullRequest.isFork'], 'False') }}: # only run enclave jobs if the password is available + # Self hosted SQL Server on Mac + mac_sql_22: + pool: $(defaultHostedPoolName) + hostedPool: true + images: + MacOSLatest_Sql22: macos-latest + TargetFrameworks: ${{parameters.targetFrameworksLinux }} + netcoreVersionTestUtils: ${{parameters.netcoreVersionTestUtils }} + buildPlatforms: [AnyCPU] + testSets: ${{parameters.testSets }} + useManagedSNI: [true] + codeCovTargetFrameworks: ${{parameters.codeCovTargetFrameworks }} + configSqlFor: local + operatingSystem: Mac + configProperties: + # config.json properties + TCPConnectionString: $(SQL_TCP_CONN_STRING) + NPConnectionString: $(SQL_NP_CONN_STRING) + SupportsIntegratedSecurity: false + ManagedIdentitySupported: false + LocalDbAppName: $(LocalDbAppName) + LocalDbSharedInstanceName: $(LocalDbSharedInstanceName) + + # Enclave tests + # + # Only run enclave jobs if the password is available, which it won't be + # for forked PRs. + # + ${{ if eq(variables['system.pullRequest.isFork'], 'False') }}: + windows_enclave_sql: + pool: ADO-CI-AE-1ES-Pool + images: + Win22_Enclave_Sql19: ADO-MMS22-SQL19 + TargetFrameworks: ${{parameters.targetFrameworks }} + netcoreVersionTestUtils: ${{parameters.netcoreVersionTestUtils }} + buildPlatforms: ${{parameters.buildPlatforms }} + testSets: [AE] + useManagedSNI: ${{parameters.useManagedSNI }} + codeCovTargetFrameworks: ${{parameters.codeCovTargetFrameworks }} + configSqlFor: enclave + operatingSystem: Windows + configProperties: + # config.json properties + TCPConnectionStringHGSVBS: $(SQL_TCP_CONN_STRING_HGSVBS) + TCPConnectionStringNoneVBS: $(SQL_TCP_CONN_STRING_NoneVBS) + TCPConnectionStringAASSGX: $(SQL_TCP_CONN_STRING_AASSGX) + EnclaveEnabled: true + AADAuthorityURL: $(AADAuthorityURL) + AADServicePrincipalId: $(AADServicePrincipalId) + ${{ if eq(variables['system.pullRequest.isFork'], 'False') }}: + AADServicePrincipalSecret: $(AADServicePrincipalSecret) + AzureKeyVaultUrl: $(AzureKeyVaultUrl) + AzureKeyVaultTenantId: $(AzureKeyVaultTenantId) + SupportsIntegratedSecurity: $(SupportsIntegratedSecurity) + UserManagedIdentityClientId: $(UserManagedIdentityClientId) + AliasName: $(SQLAliasName) + LocalDbAppName: $(LocalDbAppName) + LocalDbSharedInstanceName: $(LocalDbSharedInstanceName) + linux_enclave_sql: pool: ADO-CI-AE-1ES-Pool images: @@ -507,26 +562,3 @@ stages: UserManagedIdentityClientId: $(UserManagedIdentityClientId) LocalDbAppName: $(LocalDbAppName) LocalDbSharedInstanceName: $(LocalDbSharedInstanceName) - - # Self hosted SQL Server on Mac - mac_sql_22: - pool: $(defaultHostedPoolName) - hostedPool: true - images: - MacOSLatest_Sql22: macos-latest - TargetFrameworks: ${{parameters.targetFrameworksLinux }} - netcoreVersionTestUtils: ${{parameters.netcoreVersionTestUtils }} - buildPlatforms: [AnyCPU] - testSets: ${{parameters.testSets }} - useManagedSNI: [true] - codeCovTargetFrameworks: ${{parameters.codeCovTargetFrameworks }} - configSqlFor: local - operatingSystem: Mac - configProperties: - # config.json properties - TCPConnectionString: $(SQL_TCP_CONN_STRING) - NPConnectionString: $(SQL_NP_CONN_STRING) - SupportsIntegratedSecurity: false - ManagedIdentitySupported: false - LocalDbAppName: $(LocalDbAppName) - LocalDbSharedInstanceName: $(LocalDbSharedInstanceName) diff --git a/eng/pipelines/dotnet-sqlclient-ci-package-reference-pipeline.yml b/eng/pipelines/dotnet-sqlclient-ci-package-reference-pipeline.yml index 336bd97ab5..6eafba83cf 100644 --- a/eng/pipelines/dotnet-sqlclient-ci-package-reference-pipeline.yml +++ b/eng/pipelines/dotnet-sqlclient-ci-package-reference-pipeline.yml @@ -74,13 +74,6 @@ parameters: # parameters are shown up in ADO UI in a build queue time type: object default: [net462, net8.0] -- name: buildType - displayName: 'Build Type' - default: Package - values: - - Project - - Package - - name: buildConfiguration displayName: 'Build Configuration' default: Release @@ -109,7 +102,7 @@ extends: testSets: ${{ parameters.testSets }} useManagedSNI: ${{ parameters.useManagedSNI }} codeCovTargetFrameworks: ${{ parameters.codeCovTargetFrameworks }} - buildType: ${{ parameters.buildType }} + referenceType: Package buildConfiguration: ${{ parameters.buildConfiguration }} enableStressTests: ${{ parameters.enableStressTests }} testsTimeout: ${{ parameters.testsTimeout }} diff --git a/eng/pipelines/dotnet-sqlclient-ci-project-reference-pipeline.yml b/eng/pipelines/dotnet-sqlclient-ci-project-reference-pipeline.yml index 38325d38ca..6169893061 100644 --- a/eng/pipelines/dotnet-sqlclient-ci-project-reference-pipeline.yml +++ b/eng/pipelines/dotnet-sqlclient-ci-project-reference-pipeline.yml @@ -66,13 +66,6 @@ parameters: # parameters are shown up in ADO UI in a build queue time type: object default: [net462, net8.0] -- name: buildType - displayName: 'Build Type' - default: Project - values: - - Project - - Package - - name: buildConfiguration displayName: 'Build Configuration' default: Release @@ -101,7 +94,7 @@ extends: testSets: ${{ parameters.testSets }} useManagedSNI: ${{ parameters.useManagedSNI }} codeCovTargetFrameworks: ${{ parameters.codeCovTargetFrameworks }} - buildType: ${{ parameters.buildType }} + referenceType: Project buildConfiguration: ${{ parameters.buildConfiguration }} enableStressTests: ${{ parameters.enableStressTests }} testsTimeout: ${{ parameters.testsTimeout }} diff --git a/eng/pipelines/dotnet-sqlclient-signing-pipeline.yml b/eng/pipelines/dotnet-sqlclient-signing-pipeline.yml index b494a87426..ca49e3d402 100644 --- a/eng/pipelines/dotnet-sqlclient-signing-pipeline.yml +++ b/eng/pipelines/dotnet-sqlclient-signing-pipeline.yml @@ -114,7 +114,7 @@ extends: sbom: enabled: ${{ not(parameters['isPreview']) }} packageName: Microsoft.Data.SqlClient - packageVersion: $(NugetPackageVersion) + packageVersion: $(mdsPackageVersion) policheck: enabled: ${{ not(parameters['isPreview']) }} break: true # always break the build on policheck issues. You can disable it by setting to 'false' diff --git a/eng/pipelines/jobs/build-akv-official-job.yml b/eng/pipelines/jobs/build-akv-official-job.yml index a4374b773b..cbed1e2cbc 100644 --- a/eng/pipelines/jobs/build-akv-official-job.yml +++ b/eng/pipelines/jobs/build-akv-official-job.yml @@ -5,6 +5,9 @@ ################################################################################# parameters: + - name: akvPackageVersion + type: string + - name: apiScanDllPath type: string @@ -17,12 +20,6 @@ parameters: - name: buildConfiguration type: string - - name: nugetPackageVersion - type: string - - - name: mdsPackageVersion - type: string - - name: publishSymbols type: boolean @@ -90,7 +87,7 @@ jobs: parameters: assemblyFileVersion: '${{ parameters.assemblyFileVersion }}' buildConfiguration: '${{ parameters.buildConfiguration }}' - mdsPackageVersion: '${{ parameters.mdsPackageVersion }}' + akvPackageVersion: '${{ parameters.akvPackageVersion }}' - ${{ each targetFramework in parameters.targetFrameworks }}: - template: ../steps/compound-extract-akv-apiscan-files-step.yml @@ -104,7 +101,7 @@ jobs: - template: ../steps/roslyn-analyzers-akv-step.yml@self parameters: buildConfiguration: '${{ parameters.buildConfiguration }}' - mdsPackageVersion: '${{ parameters.mdsPackageVersion }}' + akvPackageVersion: '${{ parameters.akvPackageVersion }}' - template: ../steps/compound-esrp-code-signing-step.yml@self parameters: @@ -120,7 +117,7 @@ jobs: parameters: buildConfiguration: '${{ parameters.buildConfiguration }}' generateSymbolsPackage: true # Always generate symbols, even if they are not published - packageVersion: '${{ parameters.nugetPackageVersion }}' + packageVersion: '${{ parameters.akvPackageVersion }}' nuspecPath: '$(REPO_ROOT)/tools/specs/add-ons/$(PACKAGE_NAME).nuspec' outputDirectory: '$(ARTIFACT_PATH)' referenceType: 'Package' @@ -138,7 +135,7 @@ jobs: - ${{ if parameters.publishSymbols }}: - template: ../steps/compound-publish-symbols-step.yml@self parameters: - artifactName: 'akv_symbols_$(System.TeamProject)_$(Build.Repository.Name)_$(Build.SourceBranchName)_${{ parameters.nugetPackageVersion }}_$(System.TimelineId)' + artifactName: 'akv_symbols_$(System.TeamProject)_$(Build.Repository.Name)_$(Build.SourceBranchName)_${{ parameters.akvPackageVersion }}_$(System.TimelineId)' azureSubscription: '${{ parameters.symbolsAzureSubscription }}' publishProjectName: '${{ parameters.symbolsPublishProjectName }}' packageName: '$(PACKAGE_NAME)' @@ -151,4 +148,4 @@ jobs: Windows_NT/${{ parameters.buildConfiguration }}.AnyCPU/AzureKeyVaultProvider/**/$(PACKAGE_NAME).pdb AnyOS/${{ parameters.buildConfiguration }}.AnyCPU/AzureKeyVaultProvider/**/$(PACKAGE_NAME).pdb uploadAccount: '${{ parameters.symbolsUploadAccount }}' - version: '${{ parameters.nugetPackageVersion }}' + version: '${{ parameters.akvPackageVersion }}' diff --git a/eng/pipelines/jobs/pack-abstractions-package-ci-job.yml b/eng/pipelines/jobs/pack-abstractions-package-ci-job.yml new file mode 100644 index 0000000000..d7a6807474 --- /dev/null +++ b/eng/pipelines/jobs/pack-abstractions-package-ci-job.yml @@ -0,0 +1,143 @@ +################################################################################ +# Licensed to the .NET Foundation under one or more agreements. The .NET +# Foundation licenses this file to you under the MIT license. See the LICENSE +# file in the project root for more information. +################################################################################ + +# This job packs the Abstractions package into NuGet and symbols packages and +# publishes them as a named pipeline artifact. +# +# This template defines a job named 'pack_abstractions_package_job' that can be +# depended on by downstream jobs. + +parameters: + + # The name to apply to the published pipeline artifact. + - name: artifactName + type: string + default: Abstractions.Artifact + + # The type of build to test (Release or Debug) + - name: buildConfiguration + type: string + values: + - Release + - Debug + + # The list of upstream jobs to depend on. + - name: dependsOn + type: object + default: [] + + # The verbosity level for the dotnet CLI commands. + - name: verbosity + type: string + default: normal + values: + - quiet + - minimal + - normal + - detailed + - diagnostic + +jobs: + + - job: pack_abstractions_package_job + displayName: 'Pack Abstractions Package' + + dependsOn: ${{ parameters.dependsOn }} + + pool: + name: Azure Pipelines + vmImage: ubuntu-latest + + variables: + + # The Abstractions solution file to use for all dotnet CLI commands. + - name: solution + value: src/Microsoft.Data.SqlClient.Extensions/Abstractions/Abstractions.slnx + + # The directory where the NuGet packages will be staged before being + # published as pipeline artifacts. + - name: dotnetPackagesDir + value: $(Build.StagingDirectory)/dotnetPackages + + # dotnet CLI arguments common to all commands. + - name: commonArguments + value: >- + --verbosity ${{ parameters.verbosity }} + + # dotnet CLI arguments for build/test/pack commands + - name: buildArguments + value: >- + $(commonArguments) + --configuration ${{ parameters.buildConfiguration }} + + # Explicitly unset the $PLATFORM environment variable that is set by the + # 'ADO Build properties' Library in the ADO SqlClientDrivers public project. + # This is defined with a non-standard Platform of 'AnyCPU', and will fail + # the builds if left defined. The stress tests solution does not require + # any specific Platform, and so its solution file doesn't support any + # non-standard platforms. + # + # Note that Azure Pipelines will inject this variable as PLATFORM into the + # environment of all tasks in this job. + # + # See: + # https://learn.microsoft.com/en-us/azure/devops/pipelines/process/variables?view=azure-devops&tabs=yaml%2Cbatch + # + - name: Platform + value: '' + + # Do the same for $CONFIGURATION since we explicitly set it using our + # 'buildConfiguration' parameter, and we don't want the environment to + # override us. + - name: Configuration + value: '' + + steps: + + # Install the .NET 9.0 SDK. + - task: UseDotNet@2 + displayName: Install .NET 9.0 SDK + inputs: + packageType: sdk + version: 9.x + + # We use the 'custom' command because the DotNetCoreCLI@2 task doesn't + # support all of our argument combinations for the different build steps. + + # Restore the solution. + - task: DotNetCoreCLI@2 + displayName: Restore Solution + inputs: + command: custom + custom: restore + projects: $(solution) + arguments: $(commonArguments) + + # Build the solution. + - task: DotNetCoreCLI@2 + displayName: Build Solution + inputs: + command: custom + custom: build + projects: $(solution) + arguments: $(buildArguments) --no-restore + + # Create the NuGet packages. + - task: DotNetCoreCLI@2 + displayName: Create NuGet Package + inputs: + command: custom + custom: pack + projects: $(solution) + arguments: $(buildArguments) --no-build -o $(dotnetPackagesDir) + + # Publish the NuGet packages as a named pipeline artifact. + - task: PublishPipelineArtifact@1 + displayName: Publish Pipeline Artifact + inputs: + targetPath: $(dotnetPackagesDir) + artifactName: ${{ parameters.artifactName }} + publishLocation: pipeline diff --git a/eng/pipelines/jobs/stress-tests-ci-job.yml b/eng/pipelines/jobs/stress-tests-ci-job.yml index 2e01470fe5..cc2913c367 100644 --- a/eng/pipelines/jobs/stress-tests-ci-job.yml +++ b/eng/pipelines/jobs/stress-tests-ci-job.yml @@ -4,7 +4,7 @@ # file in the project root for more information. ################################################################################ -# This stage builds and runs stress tests against an MDS NuGet package available +# This job builds and runs stress tests against an MDS NuGet package available # as a pipeline artifact. # # The stress tests are located here: diff --git a/eng/pipelines/jobs/test-abstractions-package-ci-job.yml b/eng/pipelines/jobs/test-abstractions-package-ci-job.yml new file mode 100644 index 0000000000..a2b25966d4 --- /dev/null +++ b/eng/pipelines/jobs/test-abstractions-package-ci-job.yml @@ -0,0 +1,174 @@ +################################################################################ +# Licensed to the .NET Foundation under one or more agreements. The .NET +# Foundation licenses this file to you under the MIT license. See the LICENSE +# file in the project root for more information. +################################################################################ + +# This job builds the Abstractions package and runs its tests for a set of .NET +# runtimes. +# +# This template defines a job named 'test_abstractions_package_job_' +# that can be depended on by downstream jobs. + +parameters: + + # The type of build to test (Release or Debug) + - name: buildConfiguration + type: string + values: + - Release + - Debug + + # The prefix to prepend to the job's display name: + # + # [] Run Stress Tests + # + - name: displayNamePrefix + type: string + + # The suffix to append to the job name. + - name: jobNameSuffix + type: string + + # The list of .NET Framework runtimes to test against. + - name: netFrameworkRuntimes + type: object + default: [] + + # The list of .NET runtimes to test against. + - name: netRuntimes + type: object + default: [] + + # The name of the Azure Pipelines pool to use. + - name: poolName + type: string + + # The verbosity level for the dotnet CLI commands. + - name: verbosity + type: string + default: normal + values: + - quiet + - minimal + - normal + - detailed + - diagnostic + + # The pool VM image to use. + - name: vmImage + type: string + +jobs: + + - job: test_abstractions_package_job_${{ parameters.jobNameSuffix }} + displayName: '[${{ parameters.displayNamePrefix }}] Test Abstractions Package' + pool: + name: ${{ parameters.poolName }} + + # Images provided by Azure Pipelines must be selected using 'vmImage'. + ${{ if eq(parameters.poolName, 'Azure Pipelines') }}: + vmImage: ${{ parameters.vmImage }} + # Images provided by 1ES must be selected using a demand. + ${{ else }}: + demands: + - imageOverride -equals ${{ parameters.vmImage }} + + variables: + + # The Abstractions solution file to use for all dotnet CLI commands. + - name: solution + value: src/Microsoft.Data.SqlClient.Extensions/Abstractions/Abstractions.slnx + + # dotnet CLI arguments common to all commands. + - name: commonArguments + value: >- + --verbosity ${{ parameters.verbosity }} + + # dotnet CLI arguments for build/test/pack commands + - name: buildArguments + value: >- + $(commonArguments) + --configuration ${{ parameters.buildConfiguration }} + + # Explicitly unset the $PLATFORM environment variable that is set by the + # 'ADO Build properties' Library in the ADO SqlClientDrivers public project. + # This is defined with a non-standard Platform of 'AnyCPU', and will fail + # the builds if left defined. The stress tests solution does not require + # any specific Platform, and so its solution file doesn't support any + # non-standard platforms. + # + # Note that Azure Pipelines will inject this variable as PLATFORM into the + # environment of all tasks in this job. + # + # See: + # https://learn.microsoft.com/en-us/azure/devops/pipelines/process/variables?view=azure-devops&tabs=yaml%2Cbatch + # + - name: Platform + value: '' + + # Do the same for $CONFIGURATION since we explicitly set it using our + # 'buildConfiguration' parameter, and we don't want the environment to + # override us. + - name: Configuration + value: '' + + steps: + + # Install the .NET 9.0 SDK. + - task: UseDotNet@2 + displayName: Install .NET 9.0 SDK + inputs: + packageType: sdk + version: 9.x + + # Install the .NET 8.0 runtime. + - task: UseDotNet@2 + displayName: Install .NET 8.0 Runtime + inputs: + packageType: runtime + version: 8.x + + # The Windows agent images include a suitable .NET Framework runtime, so + # we don't have to install one explicitly. + + # We use the 'custom' command because the DotNetCoreCLI@2 task doesn't + # support all of our argument combinations for the different build steps. + + # Restore the solution. + - task: DotNetCoreCLI@2 + displayName: Restore Solution + inputs: + command: custom + custom: restore + projects: $(solution) + arguments: $(commonArguments) + + # Build the solution. + - task: DotNetCoreCLI@2 + displayName: Build Solution + inputs: + command: custom + custom: build + projects: $(solution) + arguments: $(buildArguments) --no-restore + + # Run the tests for each .NET runtime. + - ${{ each runtime in parameters.netRuntimes }}: + - task: DotNetCoreCLI@2 + displayName: Test [${{ runtime }}] + inputs: + command: custom + custom: test + projects: $(solution) + arguments: $(buildArguments) --no-build -f ${{ runtime }} + + # Run the tests for each .NET Framework runtime. + - ${{ each runtime in parameters.netFrameworkRuntimes }}: + - task: DotNetCoreCLI@2 + displayName: Test [${{ runtime }}] + inputs: + command: custom + custom: test + projects: $(solution) + arguments: $(buildArguments) --no-build -f ${{ runtime }} diff --git a/eng/pipelines/libraries/ci-build-variables.yml b/eng/pipelines/libraries/ci-build-variables.yml index 122281e083..ac39665b62 100644 --- a/eng/pipelines/libraries/ci-build-variables.yml +++ b/eng/pipelines/libraries/ci-build-variables.yml @@ -15,7 +15,9 @@ variables: value: 'net8.0' - name: SQLTarget value: 'localhost' - - name: NugetPackageVersion + - name: akvPackageVersion + value: 1.0.0.$(buildNumber) + - name: mdsPackageVersion value: $(Major).$(Minor)$(Patch)-pull.1$(buildnumber) - name: skipComponentGovernanceDetection value: true diff --git a/eng/pipelines/libraries/common-variables.yml b/eng/pipelines/libraries/common-variables.yml index 8fc6aec755..b7df898497 100644 --- a/eng/pipelines/libraries/common-variables.yml +++ b/eng/pipelines/libraries/common-variables.yml @@ -40,9 +40,9 @@ variables: - name: Revision value: '1' - - name: NugetPackageVersion + - name: mdsPackageVersion value: $(Major).$(Minor).$(Patch) - - name: PreviewNugetPackageVersion + - name: previewMdsPackageVersion value: $(Major).$(Minor).$(Patch)$(Preview)$(Revision).$(Build.BuildNumber) - name: AssemblyFileVersion value: '$(Major).$(Minor)$(Patch).$(Build.BuildNumber)' diff --git a/eng/pipelines/libraries/mds-validation-variables.yml b/eng/pipelines/libraries/mds-validation-variables.yml index d7723a059f..93dc0804ff 100644 --- a/eng/pipelines/libraries/mds-validation-variables.yml +++ b/eng/pipelines/libraries/mds-validation-variables.yml @@ -13,7 +13,7 @@ variables: - name: extractedNugetRootPath value: $(Build.SourcesDirectory)\$(TempFolderName)\Microsoft.Data.SqlClient - name: extractedNugetPath - value: $(extractedNugetRootPath).$(NugetPackageVersion) + value: $(extractedNugetRootPath).$(mdsPackageVersion) - name: expectedFolderNames value: lib,ref,runtimes - name: expectedDotnetVersions diff --git a/eng/pipelines/stages/build-abstractions-package-ci-stage.yml b/eng/pipelines/stages/build-abstractions-package-ci-stage.yml new file mode 100644 index 0000000000..8e71ffad66 --- /dev/null +++ b/eng/pipelines/stages/build-abstractions-package-ci-stage.yml @@ -0,0 +1,124 @@ +################################################################################ +# Licensed to the .NET Foundation under one or more agreements. The .NET +# Foundation licenses this file to you under the MIT license. See the LICENSE +# file in the project root for more information. +################################################################################ + +# This stage builds the Abstractions package, runs tests, and publishes the +# resulting NuGet packages as pipeline artifacts. +# +# The NuGet packages have the following properties: +# +# Name: Microsoft.Data.SqlClient.Extensions.Abstractions Version: +# . +# +# Where and are the values of the +# 'packageVersion' and 'buildNumber' parameters, respectively. +# +# The following NuGet packages are published: +# +# Microsoft.Data.SqlClient.Extensions.Abstractions..nupkg +# Microsoft.Data.SqlClient.Extensions.Abstractions..snupkg (symbols) +# +# The packages are published to pipeline artifacts with the name specified by +# the 'artifactName' parameter. +# +# This template defines a stage named 'build_abstractions_package_stage' that +# can be depended on by downstream stages. + +parameters: + + # The name of the pipeline artifact to publish. + - name: artifactName + type: string + default: Abstractions.Artifact + + # The type of build to produce (Release or Debug) + - name: buildConfiguration + type: string + default: Release + values: + - Release + - Debug + + # The build number of the pipeline. + - name: buildNumber + type: string + default: $(Build.BuildNumber) + + # The version (Major.Minor.Patch) to apply to the package. + - name: packageVersion + type: string + default: '' + + # The verbosity level for the dotnet CLI commands. + - name: verbosity + type: string + default: normal + values: + - quiet + - minimal + - normal + - detailed + - diagnostic + +stages: + + - stage: build_abstractions_package_stage + displayName: Build Abstractions Package + + jobs: + + # ------------------------------------------------------------------------ + # Build and test on Linux. + + - template: ../jobs/test-abstractions-package-ci-job.yml@self + parameters: + jobNameSuffix: linux + displayNamePrefix: Linux + poolName: Azure Pipelines + vmImage: ubuntu-latest + buildConfiguration: ${{ parameters.buildConfiguration }} + netRuntimes: [net8.0, net9.0] + netFrameworkRuntimes: [] + + # ------------------------------------------------------------------------ + # Build and test on Windows + + - template: ../jobs/test-abstractions-package-ci-job.yml@self + parameters: + jobNameSuffix: windows + displayNamePrefix: Win + poolName: Azure Pipelines + vmImage: windows-latest + buildConfiguration: ${{ parameters.buildConfiguration }} + netRuntimes: [net8.0, net9.0] + netFrameworkRuntimes: [net462, net47, net471, net472, net48, net481] + + # ------------------------------------------------------------------------ + # Build and test on macOS. + + - template: ../jobs/test-abstractions-package-ci-job.yml + parameters: + jobNameSuffix: macos + displayNamePrefix: macOS + poolName: Azure Pipelines + vmImage: macos-latest + buildConfiguration: ${{ parameters.buildConfiguration }} + netRuntimes: [net8.0, net9.0] + netFrameworkRuntimes: [] + + # ------------------------------------------------------------------------ + # Create and publish the NuGet package. + + - template: ../jobs/pack-abstractions-package-ci-job.yml@self + parameters: + artifactName: ${{ parameters.artifactName }} + buildConfiguration: ${{ parameters.buildConfiguration }} + verbosity: ${{ parameters.verbosity }} + dependsOn: + # We depend on all of the test jobs to ensure the tests pass before + # producing the NuGet package. + - test_abstractions_package_job_linux + - test_abstractions_package_job_windows + - test_abstractions_package_job_macos diff --git a/eng/pipelines/steps/compound-build-akv-step.yml b/eng/pipelines/steps/compound-build-akv-step.yml index 906dcfaf72..a547604a2c 100644 --- a/eng/pipelines/steps/compound-build-akv-step.yml +++ b/eng/pipelines/steps/compound-build-akv-step.yml @@ -7,16 +7,16 @@ # @TODO: This can probably be made generic and pass in the command lines for msbuild # BUT, they should be kept separate by now as we rebuild build.proj in parallel, we won't # affect >1 project at a time. -# @TODO: NugetPackageVersion should not be used for MDS package version +# @TODO: mdsPackageVersion should not be used for MDS package version parameters: - - name: assemblyFileVersion + - name: akvPackageVersion type: string - - name: buildConfiguration + - name: assemblyFileVersion type: string - - name: mdsPackageVersion + - name: buildConfiguration type: string steps: @@ -46,7 +46,7 @@ steps: msbuildArguments: >- -t:BuildAkv -p:AssemblyFileVersion=${{ parameters.assemblyFileVersion }} - -p:NugetPackageVersion=${{ parameters.mdsPackageVersion }} + -p:AkvPackageVersion=${{ parameters.akvPackageVersion }} -p:ReferenceType=Package -p:SigningKeyPath=$(Agent.TempDirectory)/netfxKeypair.snk diff --git a/eng/pipelines/steps/roslyn-analyzers-akv-step.yml b/eng/pipelines/steps/roslyn-analyzers-akv-step.yml index 0e05177d5a..c7acc84088 100644 --- a/eng/pipelines/steps/roslyn-analyzers-akv-step.yml +++ b/eng/pipelines/steps/roslyn-analyzers-akv-step.yml @@ -9,10 +9,10 @@ # affect >1 project at a time. parameters: - - name: buildConfiguration + - name: akvPackageVersion type: string - - name: mdsPackageVersion + - name: buildConfiguration type: string steps: @@ -25,7 +25,7 @@ steps: $(REPO_ROOT)/build.proj -t:BuildAkv -p:Configuration=${{ parameters.buildConfiguration }} - -p:NugetPackageVersion=${{ parameters.mdsPackageVersion }} + -p:AkvPackageVersion=${{ parameters.akvPackageVersion }} -p:ReferenceType=Package msBuildVersion: 17.0 setupCommandLinePicker: vs2022 diff --git a/eng/pipelines/variables/akv-official-variables.yml b/eng/pipelines/variables/akv-official-variables.yml index aaf8de7c5e..b22044548d 100644 --- a/eng/pipelines/variables/akv-official-variables.yml +++ b/eng/pipelines/variables/akv-official-variables.yml @@ -37,7 +37,5 @@ variables: # Compound Variables --------------------------------------------------- - name: assemblyFileVersion value: '${{ variables.versionMajor }}.${{ variables.versionMinor }}${{ variables.versionPatch }}.$(Build.BuildNumber)' - - name: nugetPackageVersion + - name: akvPackageVersion value: '${{ variables.versionMajor }}.${{ variables.versionMinor }}.${{ variables.versionPatch }}${{ variables.versionPreview }}' - - diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 4c210df737..69143965a9 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -20,6 +20,21 @@ > msbuild -p:configuration=Release --> Project + + + $(AllowedOutputExtensionsInPackageBuildOutputFolder) + $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props index 6ceddccd37..6cf7a6bc93 100644 --- a/src/Directory.Packages.props +++ b/src/Directory.Packages.props @@ -7,6 +7,13 @@ + + + + + diff --git a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/Abstractions.slnx b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/Abstractions.slnx new file mode 100644 index 0000000000..9632efff88 --- /dev/null +++ b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/Abstractions.slnx @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/README.md b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/README.md new file mode 100644 index 0000000000..d2a24b898c --- /dev/null +++ b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/README.md @@ -0,0 +1,285 @@ +# MDS Azure Extension Design + +## Overview + +For the MDS 7.0.0 release, we are proposing the following package architecture +changes that will decouple several large dependencies from MDS and move them +into a new `Azure` extension package: + +- Create a new `Abstractions` package that all other MDS packages depend on. + - This will contain types and definitions common to the other MDS packages, + such as base classes, enums, delegates, etc. +- Create a new `Azure` package that will own the following implementations: + - Azure Authentication + - Azure Attestation + - Azure Key Vault interactions +- Move the above implementations out of MDS and into the new `Azure` package. +- Move the existing `AzureKeyVaultProvider` (AKV) implementation into the new + `Azure` extension package. + +This will reduce the main MDS package dependency tree along with a moderate +package size reduction. + +## Motivation + +Issue: [#1108](https://github.com/dotnet/SqlClient/issues/1108) + +Customers and the developer community have voiced concerns with MDS being +tightly coupled to Azure dependencies. Many customers do not use Azure and do +not want to deploy unnecessary DLLs with their applications. + +Moving the Azure dependent implementations into a separate `Azure` extension +package achieves two goals: + +- Remove Azure packages as direct dependencies of MDS and reduce the MDS + dependency tree. +- Clearly expose existing MDS extension points, prove their functionality, and + demonstrate how to use them. + +The following dependencies will be removed from the main MDS package: + +- `Azure.Identity` + - `Azure.Core` (transitive) + - `Microsoft.Identity.Client` (transitive) +- `Microsoft.IdentityModel.JsonWebTokens` + - `Microsoft.IdentityModel.Tokens` (transitive) + - `Microsoft.IdentityModel.Logging` (transitive) +- `Microsoft.IdentityModel.Protocols.OpenIdConnect` + - `Microsoft.IdentityModel.Protocols` (transitive) + +The following dependencies will be removed from the AKV Provider package: + +- `Azure.Core` +- `Azure.Security.KeyVault.Keys` + +## Package Architecture + +```mermaid +classDiagram +class MDS +class MDS.Extensions.Abstractions +class MDS.Extensions.Azure +class AKV Provider + +MDS --> MDS.Extensions.Abstractions +MDS ..> MDS.Extensions.Azure +MDS ..> AKV Provider +MDS.Extensions.Azure --> MDS.Extensions.Abstractions +AKV Provider --> MDS.Extensions.Azure + +MDS: Depend on MDS.Extensions.Abstractions +MDS: Load Azure or AKV assembly +MDS.Extensions.Abstractions: Azure Authentication Types +MDS.Extensions.Abstractions: Azure Attestation Types +MDS.Extensions.Abstractions: Azure Key Vault Types +MDS.Extensions.Azure: Depend on MDS.Extensions.Abstractions +MDS.Extensions.Azure: Authentication Implementation +MDS.Extensions.Azure: Attestation Implementation +MDS.Extensions.Azure: Key Vault Implementation +AKV Provider: Depend on MDS.Extensions.Azure +``` + +In previous MDS versions, the AKV package depended directly on the main MDS +package through a ranged version (for example [6.0.0, 7.0.0) - all 6.x +versions). With the new package architecture this is no longer the case. +Extension packages will not depend on the main MDS package, nor will the main +MDS package depend on any extension packages. All dependencies between MDS and +its extensions will occur through the `Abstractions` package. + +This new looser coupling gives applications the flexibility to depend on only +the main MDS package, or on MDS and a subset of it extension packages if +desired. + +## Consuming + +There are several ways that applications may consume MDS and its extensions: + +- MDS with without Azure features +- MDS with MDS-supplied Azure features +- MDS with externally supplied Azure features + +Applications never need to directly depend on the `Abstractions` base package. +This will be transitively depended on by other MDS packages. + +### Without Azure Features + +Applications that do not use any Azure features will no longer bring in those +unwanted dependencies transitively. Simply include the main MDS package by +itself: + +```xml + + + +``` + +Calls to MDS APIs that require Azure features will throw an exception, since +no Azure feature implementation is present. + +### With MDS Azure Features + +Applications that wish to use MDS-supplied Azure features will need to include +the new `Azure` extension package as a direct dependency alongside the main MDS +package: + +```xml + + + + +``` + +MDS will automatically detect the `Azure` extension assemblies and load them. + +### With External Azure Features + +Applications that wish to use Azure features supplied by another (non-MDS) +package will need to include that package as a direct dependency alongside the +main MDS package: + +```xml + + + + +``` + +Additionally, applications will need to instruct MDS to use the external Azure +feature implementations via the appropriate APIs at runtime: + +- Authentication: [SqlAuthenticationProvider](https://learn.microsoft.com/en-us/dotnet/api/microsoft.data.sqlclient.sqlauthenticationprovider?view=sqlclient-dotnet-core-6.0) +- Attestation: _**New API will be exposed.**_ +- Key Valut: [SqlColumnEncryptionKeyStoreProvider](https://learn.microsoft.com/en-us/dotnet/api/microsoft.data.sqlclient.sqlcolumnencryptionkeystoreprovider?view=sqlclient-dotnet-core-6.0) + +## Versioning Strategy + +The MDS suite of packages will be versioned independently. This provides +flexibility to update APIs and implementations for packages as needed, avoiding +unnecessary version bumps and releases. The initial release of these packages +will have the following versions: + +|Package|Version|Comment| +|-|-|-| +|`Microsoft.Data.SqlClient.Extensions.Abstractions`|1.0.0|First version of this package.| +|`Microsoft.Data.SqlClient`|7.0.0|Major version bump due to breaking changes described in this document.| +|`Microsoft.Data.SqlClient.Extensions.Azure`|1.0.0|First version of this package.| +|`Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider`|7.0.0|_**Deprecated.**_| + +Going forward, each package will be versioned appropriately based on the nature +of the changes included with subsequent releases. + +**Note**: The `AzureKeyVaultProvider` package will remain at 7.0.0. It will be +deprecated and eventually removed, as it has been replaced by the `Azure` +extension package. + +## Intradependence + +The main MDS package and the new `Azure` package will depend on the +`Abstractions` package. When APIs are added, modified, or removed from the +`Abstractions` package, corresponding changes will be made to the dependent +packages as well. Those dependent packages will then take a strict dependency +on the appropriate `Abstractions` package version. This ensures that only +compatible extensions package versions can co-exist with the main MDS package. + +For example, imagine that a new extensible conenction pooling feature is added +to MDS. The `Abstractions` package would be updated to include any new pooling +APIs, the main MDS package would be updated to accept extensible pooling, and +the new pooling implementation would be included in a new `ConnectionPooling` +extension package. The versions of these packages would look something like +this: + +|Package|Version| +|-|-| +|`Microsoft.Data.SqlClient.Extensions.Abstractions`|1.1.0| +|`Microsoft.Data.SqlClient`|7.1.0| +|`Microsoft.Data.SqlClient.Extensions.ConnectionPooling`|1.0.0| + +Both the main MDS package and the new `ConnectionPooling` package would depend +on `Abstractions` v1.1.0. + +An application wishing to use the new `ConnectionPooling` v1.0.0 package must +also update the main MDS package to v7.1.0. The applictaion would not be able +to use `ConnectionPooling` v1.0.0 and MDS v7.0.0. + +## Backwards Compatibility + +There are several backwards compatibility scenarios to consider for applications +that rely on MDS Azure features currently implemented in the main MDS package +and the AKV package. The new extensions package architecture aims to reduce the +friction for these apps, but not all scenarios will be seamless. + +All of the scenarios below assume that the application is upgrading to the +latest versions of MDS packages. + +### Apps using MDS Azure Authentication + +Applications currently using the MDS-supplied Azure Authentication features will +need to add a dependency on the `Azure` extension package to their project +alongside the main MDS package: + +```xml + + + + +``` + +All Azure Authentication namespaces and types will remain the same, so this +should be the only change necessary for applications. + +### Apps using MDS Azure Attestation + +Applications currently using the MDS-supplied Azure Attestation features will +need to add a dependency on the `Azure` extension package to their project +alongside the main MDS package: + +```xml + + + + +``` + +All Azure Attestation namespaces and types will remain the same, so this should +be the only change necessary for applications. + +### Apps using AKV Provider + +Applications currently using the MDS-supplied AKV provider will have two options +when upgrading to MDS v7.0.0. Both options rely on the main MDS package finding +and loading an appropriate DLL (assembly) at runtime. The absence of an +appropriate DLL will cause Azure Key Vault operations to throw an exception. + +#### Use Azure Extension + +This is the preferred approach. The application would be updated to depend +on the main MDS package and the `Azure` extension package: + +```xml + + + + +``` + +The `Azure` extension package will contain the same namespaces and types as the +current AKV provider and will be a drop-in replacement. The main MDS v7.0.0 +package will look for the `Azure` extension assembly and automatically load it. + +#### Use AKV Provider v7.0.0 + +This is a temporary solution. The AKV provider v7.0.0 will be marked as +deprecated and removed entirely at some point in the future. The applictaion +would remain dependent on the AKV provider, but must update to the v7.0.0 +package. Previous AKV package versions do not support main MDS package versions +beyond the v6.x range. + +```xml + + + + +``` + +This AKV Provider v7.0.0 package will be empty and simply depend on the `Azure` +extension package to transitively provide the Azure Key Vault features. diff --git a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/doc/Sample.xml b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/doc/Sample.xml new file mode 100644 index 0000000000..8d5f5c44d5 --- /dev/null +++ b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/doc/Sample.xml @@ -0,0 +1,18 @@ + + + + + + Sample class to demonstrate packaging and pipelines. + + + + Construct with a name. + The name. + + + Gets the name. + The name. + + + diff --git a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/Abstractions.csproj b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/Abstractions.csproj new file mode 100644 index 0000000000..8844458f1b --- /dev/null +++ b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/Abstractions.csproj @@ -0,0 +1,109 @@ + + + + + + + + + 1 + + + $(AbstractionsPackageMajorVersion).0.0 + + + $(AbstractionsPackageVersion).$(BuildNumber) + + + $(AbstractionsPackageMajorVersion).0.0.0 + + + + + netstandard2.0 + + + + + enable + enable + + + + + Microsoft.Data.SqlClient.Extensions.Abstractions + + $(AbstractionsPackageVersion) + $(AbstractionsPackageAssemblyVersion) + $(PackageVersion) + $(AssemblyFileVersion) + + Microsoft.Data.SqlClient.Extensions.Abstractions + + + + + <_Parameter1>true + + + + + + + + + + + + + $(PackagesDir) + true + snupkg + + + $(OriginalAllowedOutputExtensions) + + Microsoft Corporation + Microsoft Corporation + Microsoft.Data.SqlClient Extensions Abstractions + https://github.com/dotnet/SqlClient + MIT + dotnet.png + + + + + + diff --git a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/Sample.cs b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/Sample.cs new file mode 100644 index 0000000000..bf22119436 --- /dev/null +++ b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/Sample.cs @@ -0,0 +1,20 @@ +namespace Microsoft.Data.SqlClient.Extensions.Abstractions; + +/// +public class Sample +{ + /// + public Sample(string name) + { + Name = name; + } + + /// + public string Name { get; private set; } + + // Update the name. + internal void SetName(string name) + { + Name = name; + } +} diff --git a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/test/Abstractions.Test.csproj b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/test/Abstractions.Test.csproj new file mode 100644 index 0000000000..118b215737 --- /dev/null +++ b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/test/Abstractions.Test.csproj @@ -0,0 +1,26 @@ + + + + net462;net47;net471;net472;net48;net481;net8.0;net9.0 + enable + enable + false + true + Microsoft.Data.SqlClient.Extensions.Abstractions.Test + + + + + + + + + + + + + + + + + diff --git a/src/Microsoft.Data.SqlClient.Extensions/Abstractions/test/SampleTest.cs b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/test/SampleTest.cs new file mode 100644 index 0000000000..ab8e9da052 --- /dev/null +++ b/src/Microsoft.Data.SqlClient.Extensions/Abstractions/test/SampleTest.cs @@ -0,0 +1,19 @@ +namespace Microsoft.Data.SqlClient.Extensions.Abstractions.Test; + +public class SampleTest +{ + [Fact] + public void Construction() + { + Assert.Equal("test", new Sample("test").Name); + } + + [Fact] + public void SetName() + { + var sample = new Sample("test"); + Assert.Equal("test", sample.Name); + sample.SetName("new name"); + Assert.Equal("new name", sample.Name); + } +} diff --git a/src/Microsoft.Data.SqlClient.sln b/src/Microsoft.Data.SqlClient.sln index e4d29d999c..2b8e583a8d 100644 --- a/src/Microsoft.Data.SqlClient.sln +++ b/src/Microsoft.Data.SqlClient.sln @@ -1,6 +1,7 @@ + Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 -VisualStudioVersion = 17.0.31912.275 +VisualStudioVersion = 17.14.36203.30 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Data.SqlClient", "Microsoft.Data.SqlClient\netfx\src\Microsoft.Data.SqlClient.csproj", "{407890AC-9876-4FEF-A6F1-F36A876BAADE}" EndProject @@ -303,6 +304,18 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Data.SqlClient.Un EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Common", "Microsoft.Data.SqlClient\tests\Common\Common.csproj", "{67128EC0-30F5-6A98-448B-55F88A1DE707}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Microsoft.Data.SqlClient.Extensions", "Microsoft.Data.SqlClient.Extensions", "{19F1F1E5-3013-7660-661A-2A15F7D606C1}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Abstractions", "Abstractions", "{556B486E-F9B0-7EA9-6A25-DA560C312761}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{210228A5-979A-DE06-EE1F-B35C65E1583C}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Abstractions", "Microsoft.Data.SqlClient.Extensions\Abstractions\src\Abstractions.csproj", "{B21E7C94-D805-427E-928A-8DE8EA2F08CC}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{59667E4C-0BD2-9F48-FB50-9E55DD8B1011}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Abstractions.Test", "Microsoft.Data.SqlClient.Extensions\Abstractions\test\Abstractions.Test.csproj", "{04ACBF75-CFF2-41AB-B652-776BC0533490}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -571,6 +584,30 @@ Global {67128EC0-30F5-6A98-448B-55F88A1DE707}.Release|x64.Build.0 = Release|x64 {67128EC0-30F5-6A98-448B-55F88A1DE707}.Release|x86.ActiveCfg = Release|x86 {67128EC0-30F5-6A98-448B-55F88A1DE707}.Release|x86.Build.0 = Release|x86 + {B21E7C94-D805-427E-928A-8DE8EA2F08CC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B21E7C94-D805-427E-928A-8DE8EA2F08CC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B21E7C94-D805-427E-928A-8DE8EA2F08CC}.Debug|x64.ActiveCfg = Debug|Any CPU + {B21E7C94-D805-427E-928A-8DE8EA2F08CC}.Debug|x64.Build.0 = Debug|Any CPU + {B21E7C94-D805-427E-928A-8DE8EA2F08CC}.Debug|x86.ActiveCfg = Debug|Any CPU + {B21E7C94-D805-427E-928A-8DE8EA2F08CC}.Debug|x86.Build.0 = Debug|Any CPU + {B21E7C94-D805-427E-928A-8DE8EA2F08CC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B21E7C94-D805-427E-928A-8DE8EA2F08CC}.Release|Any CPU.Build.0 = Release|Any CPU + {B21E7C94-D805-427E-928A-8DE8EA2F08CC}.Release|x64.ActiveCfg = Release|Any CPU + {B21E7C94-D805-427E-928A-8DE8EA2F08CC}.Release|x64.Build.0 = Release|Any CPU + {B21E7C94-D805-427E-928A-8DE8EA2F08CC}.Release|x86.ActiveCfg = Release|Any CPU + {B21E7C94-D805-427E-928A-8DE8EA2F08CC}.Release|x86.Build.0 = Release|Any CPU + {04ACBF75-CFF2-41AB-B652-776BC0533490}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {04ACBF75-CFF2-41AB-B652-776BC0533490}.Debug|Any CPU.Build.0 = Debug|Any CPU + {04ACBF75-CFF2-41AB-B652-776BC0533490}.Debug|x64.ActiveCfg = Debug|Any CPU + {04ACBF75-CFF2-41AB-B652-776BC0533490}.Debug|x64.Build.0 = Debug|Any CPU + {04ACBF75-CFF2-41AB-B652-776BC0533490}.Debug|x86.ActiveCfg = Debug|Any CPU + {04ACBF75-CFF2-41AB-B652-776BC0533490}.Debug|x86.Build.0 = Debug|Any CPU + {04ACBF75-CFF2-41AB-B652-776BC0533490}.Release|Any CPU.ActiveCfg = Release|Any CPU + {04ACBF75-CFF2-41AB-B652-776BC0533490}.Release|Any CPU.Build.0 = Release|Any CPU + {04ACBF75-CFF2-41AB-B652-776BC0533490}.Release|x64.ActiveCfg = Release|Any CPU + {04ACBF75-CFF2-41AB-B652-776BC0533490}.Release|x64.Build.0 = Release|Any CPU + {04ACBF75-CFF2-41AB-B652-776BC0533490}.Release|x86.ActiveCfg = Release|Any CPU + {04ACBF75-CFF2-41AB-B652-776BC0533490}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -621,6 +658,11 @@ Global {AD738BD4-6A02-4B88-8F93-FBBBA49A74C8} = {4CAE9195-4F1A-4D48-854C-1C9FBC512C66} {4461063D-2F2B-274C-7E6F-F235119D258E} = {0CC4817A-12F3-4357-912C-09315FAAD008} {67128EC0-30F5-6A98-448B-55F88A1DE707} = {0CC4817A-12F3-4357-912C-09315FAAD008} + {556B486E-F9B0-7EA9-6A25-DA560C312761} = {19F1F1E5-3013-7660-661A-2A15F7D606C1} + {210228A5-979A-DE06-EE1F-B35C65E1583C} = {556B486E-F9B0-7EA9-6A25-DA560C312761} + {B21E7C94-D805-427E-928A-8DE8EA2F08CC} = {210228A5-979A-DE06-EE1F-B35C65E1583C} + {59667E4C-0BD2-9F48-FB50-9E55DD8B1011} = {556B486E-F9B0-7EA9-6A25-DA560C312761} + {04ACBF75-CFF2-41AB-B652-776BC0533490} = {59667E4C-0BD2-9F48-FB50-9E55DD8B1011} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {01D48116-37A2-4D33-B9EC-94793C702431} diff --git a/src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.csproj index 0944a4aea0..4b658f409a 100644 --- a/src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.csproj @@ -46,7 +46,20 @@ - + + + + + + + diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj index 50b04819ba..19951ebc96 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj @@ -1067,6 +1067,19 @@ + + + + + + diff --git a/src/Microsoft.Data.SqlClient/netfx/ref/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netfx/ref/Microsoft.Data.SqlClient.csproj index 380a2aa746..f73b8682a0 100644 --- a/src/Microsoft.Data.SqlClient/netfx/ref/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netfx/ref/Microsoft.Data.SqlClient.csproj @@ -49,5 +49,19 @@ + + + + + + + diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj index 17eeb3a472..a378ef5f51 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj @@ -1040,6 +1040,20 @@ + + + + + + + diff --git a/tools/props/Versions.props b/tools/props/Versions.props index ad42c4964a..e37e4c7fb1 100644 --- a/tools/props/Versions.props +++ b/tools/props/Versions.props @@ -1,29 +1,40 @@ - + + + - 7.0.0 0 + + + + + 7.0.0 + + $(MdsVersionDefault).$(BuildNumber)-dev + + $(MdsVersionDefault).$(BuildNumber) - + + 7.0.0.0 $(AssemblyFileVersion) - $(MdsVersionDefault)-dev - $(NugetPackageVersion) + $(MdsPackageVersion) + + @@ -33,8 +44,10 @@ 1.0.0-dev $(SqlServerPackageVersion) + + - $(NugetPackageVersion) + $(AkvPackageVersion) - $(NugetPackageVersion) + $(MdsPackageVersion) diff --git a/tools/specs/Microsoft.Data.SqlClient.nuspec b/tools/specs/Microsoft.Data.SqlClient.nuspec index 67d0078279..204f6b110b 100644 --- a/tools/specs/Microsoft.Data.SqlClient.nuspec +++ b/tools/specs/Microsoft.Data.SqlClient.nuspec @@ -32,6 +32,7 @@ + @@ -48,6 +49,7 @@ + @@ -62,6 +64,7 @@ + @@ -76,6 +79,7 @@ + diff --git a/tools/targets/GenerateNugetPackage.targets b/tools/targets/GenerateNugetPackage.targets index 4c8cea4159..7b674ebfdb 100644 --- a/tools/targets/GenerateNugetPackage.targets +++ b/tools/targets/GenerateNugetPackage.targets @@ -1,10 +1,10 @@ - + - $(NugetPackageVersion)-debug + $(MdsPackageVersion)-debug - + @@ -12,7 +12,7 @@ - + diff --git a/tools/targets/add-ons/GenerateAKVProviderNugetPackage.targets b/tools/targets/add-ons/GenerateAKVProviderNugetPackage.targets index 78da74bf32..aa50a32463 100644 --- a/tools/targets/add-ons/GenerateAKVProviderNugetPackage.targets +++ b/tools/targets/add-ons/GenerateAKVProviderNugetPackage.targets @@ -2,11 +2,11 @@ - $(NugetPackageVersion)-debug + $(AkvPackageVersion)-debug - + - + From 50c52c177144792347d5043d137eacdc12b42a3c Mon Sep 17 00:00:00 2001 From: Paul Medynski <31868385+paulmedynski@users.noreply.github.com> Date: Tue, 23 Sep 2025 07:53:34 -0300 Subject: [PATCH 30/30] User Story 37654: Create Abstractions package - Fixed duplicate parameters from git merge. --- .../common/templates/stages/ci-run-tests-stage.yml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/eng/pipelines/common/templates/stages/ci-run-tests-stage.yml b/eng/pipelines/common/templates/stages/ci-run-tests-stage.yml index a44f01837a..46318f8e06 100644 --- a/eng/pipelines/common/templates/stages/ci-run-tests-stage.yml +++ b/eng/pipelines/common/templates/stages/ci-run-tests-stage.yml @@ -42,13 +42,6 @@ parameters: - name: testConfigurations type: object - - name: prebuildSteps - type: stepList - default: [] - - - name: testConfigurations - type: object - # The timeout, in minutes, for each test job. - name: testsTimeout type: string