From 542fe640a710358ced6696c18b12eb381d16ef79 Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Thu, 28 May 2026 13:23:56 -0500 Subject: [PATCH 01/55] Move install-dotnet to common/steps, first bits of pipeline # Conflicts: # eng/pipelines/common/steps/restore-dotnet-tools.yml --- .../steps/install-dotnet-arm64.ps1 | 0 .../{ => common}/steps/install-dotnet.yml | 0 .../steps/restore-dotnet-tools.yml | 0 .../templates/jobs/ci-build-nugets-job.yml | 4 +-- .../templates/jobs/ci-code-coverage-job.yml | 2 +- .../templates/jobs/ci-run-tests-job.yml | 6 ++--- .../common/templates/steps/pre-build-step.yml | 2 +- .../steps/verify-nuget-package-step.yml | 2 +- .../jobs/pack-abstractions-package-ci-job.yml | 2 +- .../jobs/pack-azure-package-ci-job.yml | 2 +- .../jobs/pack-logging-package-ci-job.yml | 2 +- .../jobs/pack-sqlserver-package-ci-job.yml | 2 +- .../jobs/test-abstractions-package-ci-job.yml | 2 +- .../jobs/test-azure-package-ci-job.yml | 2 +- eng/pipelines/kerberos/sqlclient-kerberos.yml | 4 +-- .../onebranch/jobs/build-buildproj-job.yml | 4 +-- eng/pipelines/prci/prci-pipeline.yml | 11 ++++++++ eng/pipelines/prci/stages/buid-stage.yml | 27 +++++++++++++++++++ eng/pipelines/stress/stress-tests-job.yml | 2 +- 19 files changed, 57 insertions(+), 19 deletions(-) rename eng/pipelines/{ => common}/steps/install-dotnet-arm64.ps1 (100%) rename eng/pipelines/{ => common}/steps/install-dotnet.yml (100%) rename eng/pipelines/{ => common}/steps/restore-dotnet-tools.yml (100%) create mode 100644 eng/pipelines/prci/prci-pipeline.yml create mode 100644 eng/pipelines/prci/stages/buid-stage.yml diff --git a/eng/pipelines/steps/install-dotnet-arm64.ps1 b/eng/pipelines/common/steps/install-dotnet-arm64.ps1 similarity index 100% rename from eng/pipelines/steps/install-dotnet-arm64.ps1 rename to eng/pipelines/common/steps/install-dotnet-arm64.ps1 diff --git a/eng/pipelines/steps/install-dotnet.yml b/eng/pipelines/common/steps/install-dotnet.yml similarity index 100% rename from eng/pipelines/steps/install-dotnet.yml rename to eng/pipelines/common/steps/install-dotnet.yml diff --git a/eng/pipelines/steps/restore-dotnet-tools.yml b/eng/pipelines/common/steps/restore-dotnet-tools.yml similarity index 100% rename from eng/pipelines/steps/restore-dotnet-tools.yml rename to eng/pipelines/common/steps/restore-dotnet-tools.yml 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 de9b4d284f..aa6a1c50c5 100644 --- a/eng/pipelines/common/templates/jobs/ci-build-nugets-job.yml +++ b/eng/pipelines/common/templates/jobs/ci-build-nugets-job.yml @@ -132,10 +132,10 @@ jobs: targetPath: $(localFeedPath) # Install the .NET SDK. - - template: /eng/pipelines/steps/install-dotnet.yml@self + - template: /eng/pipelines/common/steps/install-dotnet.yml@self # Restore dotnet CLI tools (e.g. pwsh, apicompat) before building. - - template: /eng/pipelines/steps/restore-dotnet-tools.yml@self + - template: /eng/pipelines/common/steps/restore-dotnet-tools.yml@self # When we're performing a Debug build, we still want to try _compiling_ the # code in Release mode to ensure downstream pipelines don't encounter diff --git a/eng/pipelines/common/templates/jobs/ci-code-coverage-job.yml b/eng/pipelines/common/templates/jobs/ci-code-coverage-job.yml index 09c72e9719..95c0ac0f3c 100644 --- a/eng/pipelines/common/templates/jobs/ci-code-coverage-job.yml +++ b/eng/pipelines/common/templates/jobs/ci-code-coverage-job.yml @@ -44,7 +44,7 @@ jobs: displayName: '[Debug] List Environment Variables' # Install the .NET SDK. - - template: /eng/pipelines/steps/install-dotnet.yml@self + - template: /eng/pipelines/common/steps/install-dotnet.yml@self parameters: debug: ${{ parameters.debug }} 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 4c42af8dc1..737ac0fa23 100644 --- a/eng/pipelines/common/templates/jobs/ci-run-tests-job.yml +++ b/eng/pipelines/common/templates/jobs/ci-run-tests-job.yml @@ -211,7 +211,7 @@ jobs: targetPath: $(Build.SourcesDirectory)/packages # Install the .NET SDK and Runtimes. - - template: /eng/pipelines/steps/install-dotnet.yml@self + - template: /eng/pipelines/common/steps/install-dotnet.yml@self parameters: debug: ${{ parameters.debug }} ${{ if parameters.isArm64 }}: @@ -223,7 +223,7 @@ jobs: runtimes: [8.x, 9.x] # Restore dotnet CLI tools (e.g. pwsh, apicompat) before building. - - template: /eng/pipelines/steps/restore-dotnet-tools.yml@self + - template: /eng/pipelines/common/steps/restore-dotnet-tools.yml@self - ${{ if ne(parameters.prebuildSteps, '') }}: - ${{ parameters.prebuildSteps }} # extra steps to run before the build like downloading sni and the required configuration @@ -352,7 +352,7 @@ jobs: - ${{ if and(eq(parameters.enableX86Test, true), eq(parameters.operatingSystem, 'Windows')) }}: - ${{ if ne(variables['dotnetx86RootPath'], '') }}: # Install the .NET SDK and Runtimes for x86. - - template: /eng/pipelines/steps/install-dotnet.yml@self + - template: /eng/pipelines/common/steps/install-dotnet.yml@self parameters: architecture: x86 debug: ${{ parameters.debug }} diff --git a/eng/pipelines/common/templates/steps/pre-build-step.yml b/eng/pipelines/common/templates/steps/pre-build-step.yml index 068223af70..1d57d18296 100644 --- a/eng/pipelines/common/templates/steps/pre-build-step.yml +++ b/eng/pipelines/common/templates/steps/pre-build-step.yml @@ -5,7 +5,7 @@ ################################################################################# steps: # Install the .NET SDK and Runtimes. - - template: /eng/pipelines/steps/install-dotnet.yml@self + - template: /eng/pipelines/common/steps/install-dotnet.yml@self parameters: runtimes: [8.x, 9.x] diff --git a/eng/pipelines/common/templates/steps/verify-nuget-package-step.yml b/eng/pipelines/common/templates/steps/verify-nuget-package-step.yml index 6c74c01988..604f1b7894 100644 --- a/eng/pipelines/common/templates/steps/verify-nuget-package-step.yml +++ b/eng/pipelines/common/templates/steps/verify-nuget-package-step.yml @@ -34,7 +34,7 @@ parameters: steps: # Install the .NET SDK, required by the PowerShell script. - - template: /eng/pipelines/steps/install-dotnet.yml@self + - template: /eng/pipelines/common/steps/install-dotnet.yml@self # Invoke the script with the path to the packages to verify. - task: PowerShell@2 diff --git a/eng/pipelines/jobs/pack-abstractions-package-ci-job.yml b/eng/pipelines/jobs/pack-abstractions-package-ci-job.yml index aed7672618..a9cb5b1043 100644 --- a/eng/pipelines/jobs/pack-abstractions-package-ci-job.yml +++ b/eng/pipelines/jobs/pack-abstractions-package-ci-job.yml @@ -103,7 +103,7 @@ jobs: displayName: '[Debug] Print Environment Variables' # Install the .NET SDK. - - template: /eng/pipelines/steps/install-dotnet.yml@self + - template: /eng/pipelines/common/steps/install-dotnet.yml@self parameters: debug: ${{ parameters.debug }} diff --git a/eng/pipelines/jobs/pack-azure-package-ci-job.yml b/eng/pipelines/jobs/pack-azure-package-ci-job.yml index 3b03dc0adc..eaf0e3c66f 100644 --- a/eng/pipelines/jobs/pack-azure-package-ci-job.yml +++ b/eng/pipelines/jobs/pack-azure-package-ci-job.yml @@ -146,7 +146,7 @@ jobs: targetPath: $(Build.SourcesDirectory)/packages # Install the .NET SDK. - - template: /eng/pipelines/steps/install-dotnet.yml@self + - template: /eng/pipelines/common/steps/install-dotnet.yml@self parameters: debug: ${{ parameters.debug }} diff --git a/eng/pipelines/jobs/pack-logging-package-ci-job.yml b/eng/pipelines/jobs/pack-logging-package-ci-job.yml index dd748cb4b2..f2a42699e0 100644 --- a/eng/pipelines/jobs/pack-logging-package-ci-job.yml +++ b/eng/pipelines/jobs/pack-logging-package-ci-job.yml @@ -94,7 +94,7 @@ jobs: displayName: '[Debug] Print Environment Variables' # Install the .NET SDK. - - template: /eng/pipelines/steps/install-dotnet.yml@self + - template: /eng/pipelines/common/steps/install-dotnet.yml@self parameters: debug: ${{ parameters.debug }} diff --git a/eng/pipelines/jobs/pack-sqlserver-package-ci-job.yml b/eng/pipelines/jobs/pack-sqlserver-package-ci-job.yml index 915bf1e9bd..6b19e8c154 100644 --- a/eng/pipelines/jobs/pack-sqlserver-package-ci-job.yml +++ b/eng/pipelines/jobs/pack-sqlserver-package-ci-job.yml @@ -90,7 +90,7 @@ jobs: displayName: '[Debug] Print Environment Variables' # Install the .NET SDK. - - template: /eng/pipelines/steps/install-dotnet.yml@self + - template: /eng/pipelines/common/steps/install-dotnet.yml@self parameters: debug: ${{ parameters.debug }} diff --git a/eng/pipelines/jobs/test-abstractions-package-ci-job.yml b/eng/pipelines/jobs/test-abstractions-package-ci-job.yml index 226dc1ae2a..83366b52a9 100644 --- a/eng/pipelines/jobs/test-abstractions-package-ci-job.yml +++ b/eng/pipelines/jobs/test-abstractions-package-ci-job.yml @@ -122,7 +122,7 @@ jobs: displayName: '[Debug] Print Environment Variables' # Install the .NET SDK and Runtimes. - - template: /eng/pipelines/steps/install-dotnet.yml@self + - template: /eng/pipelines/common/steps/install-dotnet.yml@self parameters: debug: ${{ parameters.debug }} runtimes: [8.x, 9.x] diff --git a/eng/pipelines/jobs/test-azure-package-ci-job.yml b/eng/pipelines/jobs/test-azure-package-ci-job.yml index 9c70433e33..42097daa42 100644 --- a/eng/pipelines/jobs/test-azure-package-ci-job.yml +++ b/eng/pipelines/jobs/test-azure-package-ci-job.yml @@ -243,7 +243,7 @@ jobs: targetPath: $(Build.SourcesDirectory)/packages # Install the .NET SDK and Runtimes. - - template: /eng/pipelines/steps/install-dotnet.yml@self + - template: /eng/pipelines/common/steps/install-dotnet.yml@self parameters: debug: ${{ parameters.debug }} runtimes: [8.x, 9.x] diff --git a/eng/pipelines/kerberos/sqlclient-kerberos.yml b/eng/pipelines/kerberos/sqlclient-kerberos.yml index af1b04266f..57325dc3a7 100644 --- a/eng/pipelines/kerberos/sqlclient-kerberos.yml +++ b/eng/pipelines/kerberos/sqlclient-kerberos.yml @@ -133,7 +133,7 @@ stages: # Restore dotnet local tools (pwsh, apicompat, etc.). Required by build.proj targets # such as _CheckPwshToolRestored that run during the SqlClient ref project build. - - template: /eng/pipelines/steps/restore-dotnet-tools.yml@self + - template: /eng/pipelines/common/steps/restore-dotnet-tools.yml@self # --- Update test configuration --- # Uses runtime variables from the matrix ($(managedSNI)) so we use @@ -230,7 +230,7 @@ stages: # Restore dotnet local tools (pwsh, apicompat, etc.). Required by build.proj targets # such as _CheckPwshToolRestored that run during the SqlClient ref project build. - - template: /eng/pipelines/steps/restore-dotnet-tools.yml@self + - template: /eng/pipelines/common/steps/restore-dotnet-tools.yml@self # --- Update test configuration (with Kerberos credentials) --- - pwsh: | diff --git a/eng/pipelines/onebranch/jobs/build-buildproj-job.yml b/eng/pipelines/onebranch/jobs/build-buildproj-job.yml index 34c775ad5c..51c70e8c64 100644 --- a/eng/pipelines/onebranch/jobs/build-buildproj-job.yml +++ b/eng/pipelines/onebranch/jobs/build-buildproj-job.yml @@ -128,11 +128,11 @@ jobs: targetPath: $(REPO_ROOT)/packages # Install the .NET SDK. - - template: /eng/pipelines/steps/install-dotnet.yml@self + - template: /eng/pipelines/common/steps/install-dotnet.yml@self # Restore dotnet local tools (pwsh, apicompat, etc.). Required by build.proj targets # such as _CheckPwshToolRestored that run during RoslynAnalyzers and Build. - - template: /eng/pipelines/steps/restore-dotnet-tools.yml@self + - template: /eng/pipelines/common/steps/restore-dotnet-tools.yml@self # Perform Roslyn analysis before building, since this step will clobber build output. - template: /eng/pipelines/onebranch/steps/roslyn-analyzers-buildproj-step.yml@self diff --git a/eng/pipelines/prci/prci-pipeline.yml b/eng/pipelines/prci/prci-pipeline.yml new file mode 100644 index 0000000000..338c6753ea --- /dev/null +++ b/eng/pipelines/prci/prci-pipeline.yml @@ -0,0 +1,11 @@ +################################################################################# +# 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. # +################################################################################# + +parameters: + +variables: + +stages: diff --git a/eng/pipelines/prci/stages/buid-stage.yml b/eng/pipelines/prci/stages/buid-stage.yml new file mode 100644 index 0000000000..070500b06b --- /dev/null +++ b/eng/pipelines/prci/stages/buid-stage.yml @@ -0,0 +1,27 @@ +################################################################################# +# 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 is meant to perform a sanity check of the source code at the current point in time. +# Although the test targets will implicitly build the projects they depend on, this stage allows +# for fast failure of the build if the source code is not in a state that can be built. +# +# This stage will also be used to generate nuget packages based on the current source code. These +# will be uploaded, along with the build output as the artifacts of the build. + +stages: + - stage: build_projects + displayName: Build Projects + + jobs: + - job: build_projects + displayName: Build Projects + + pool: + vmImage: 'ubuntu-latest' + + steps: + + diff --git a/eng/pipelines/stress/stress-tests-job.yml b/eng/pipelines/stress/stress-tests-job.yml index a216c23864..ac82002ece 100644 --- a/eng/pipelines/stress/stress-tests-job.yml +++ b/eng/pipelines/stress/stress-tests-job.yml @@ -144,7 +144,7 @@ jobs: steps: # Install the .NET SDK and Runtimes. - - template: /eng/pipelines/steps/install-dotnet.yml@self + - template: /eng/pipelines/common/steps/install-dotnet.yml@self parameters: runtimes: [8.x, 9.x] From d96840ba62c126e67be885aea10ff767637090b7 Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Fri, 1 May 2026 14:17:27 -0500 Subject: [PATCH 02/55] Adding build and pack steps and writing up the build/pack stage. Leaving the unused build step for now just in case we need it later --- .../onebranch/steps/build-buildproj-step.yml | 4 + eng/pipelines/prci/prci-pipeline.yml | 8 ++ .../prci/stages/buid-and-pack-stage.yml | 104 ++++++++++++++++++ eng/pipelines/prci/stages/buid-stage.yml | 27 ----- .../prci/steps/build-buildproj-step.yml | 45 ++++++++ .../prci/steps/pack-buildproj-step.yml | 48 ++++++++ 6 files changed, 209 insertions(+), 27 deletions(-) create mode 100644 eng/pipelines/prci/stages/buid-and-pack-stage.yml delete mode 100644 eng/pipelines/prci/stages/buid-stage.yml create mode 100644 eng/pipelines/prci/steps/build-buildproj-step.yml create mode 100644 eng/pipelines/prci/steps/pack-buildproj-step.yml diff --git a/eng/pipelines/onebranch/steps/build-buildproj-step.yml b/eng/pipelines/onebranch/steps/build-buildproj-step.yml index 080896ee10..2a5730c848 100644 --- a/eng/pipelines/onebranch/steps/build-buildproj-step.yml +++ b/eng/pipelines/onebranch/steps/build-buildproj-step.yml @@ -6,6 +6,10 @@ # This collection of steps to build a project via the build.proj. This will execute the "Build*" # target in build.proj, where * is the packageShortName provided in the parameters. +# +# Note: This differs from the pr/ci build-buildproj-step.yml in that it always strong-name signs +# the assemblies, it only builds in package reference mode, and as such allows for version +# parameters to be provided. parameters: # Build configuration - Release or Debug. diff --git a/eng/pipelines/prci/prci-pipeline.yml b/eng/pipelines/prci/prci-pipeline.yml index 338c6753ea..bedd8438c9 100644 --- a/eng/pipelines/prci/prci-pipeline.yml +++ b/eng/pipelines/prci/prci-pipeline.yml @@ -4,8 +4,16 @@ # See the LICENSE file in the project root for more information. # ################################################################################# +name: $(DayOfYear)$(Rev:rr) + parameters: variables: + - template: /eng/pipelines/common/variables/common-variables.yml@self stages: + # Stage 1: Build and pack all projects in the repository + - template: /eng/pipelines/prci/stages/build-and-pack-stage.yml + parameters: + buildConfiguration: Debug + buildSuffix: pr diff --git a/eng/pipelines/prci/stages/buid-and-pack-stage.yml b/eng/pipelines/prci/stages/buid-and-pack-stage.yml new file mode 100644 index 0000000000..8d68359907 --- /dev/null +++ b/eng/pipelines/prci/stages/buid-and-pack-stage.yml @@ -0,0 +1,104 @@ +################################################################################# +# 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 is meant to perform a sanity check of the source code at the current point in time. +# Although the test targets will implicitly build the projects they depend on, this stage allows +# for fast failure of the build if the source code is not in a state that can be built. +# +# This stage will also be used to generate nuget packages based on the current source code. These +# will be uploaded, along with the build output as the artifacts of the build. +# +# Developer notes --- +# * Because we want a single artifact for build output, and we want to minimize overhead for build, +# we build all packages as a single job rather than one job per package. +# * Although theoretically in package build we could arrange build steps to minimize re-building, +# build.proj isn't properly aware of how to do this. So, instead, arranging the build steps +# alphabetically is the best way to arrange for now. + +stages: + - stage: build_and_pack_projects + displayName: Build and Pack Projects + + parameters: + - name: buildConfiguration + type: string + values: + - Debug + - Release + + - name: buildSuffix + type: string + + jobs: + - job: build_and_pack_projects + displayName: Build and Pack Projects + + pool: + vmImage: 'ubuntu-latest' + + steps: + # Install dotnet SDK + - template: /eng/pipelines/common/steps/install-dotnet.yml@self + + # ################################################################ + # Build/Pack Microsoft.Data.SqlClient + - template: /eng/pipelines/prci/steps/pack-buildproj-step.yml + parameters: + buildConfiguration: ${{ parameters.buildConfiguration }} + buildSuffix: ${{ parameters.buildSuffix }} + packageShortName: SqlClient + + # ################################################################ + # Build/Pack Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider + - template: /eng/pipelines/prci/steps/pack-buildproj-step.yml + parameters: + buildConfiguration: ${{ parameters.buildConfiguration }} + buildSuffix: ${{ parameters.buildSuffix }} + packageShortName: AkvProvider + + # ################################################################ + # Build/Pack Microsoft.Data.SqlClient.Extensions.Abstractions + - template: /eng/pipelines/prci/steps/pack-buildproj-step.yml + parameters: + buildConfiguration: ${{ parameters.buildConfiguration }} + buildSuffix: ${{ parameters.buildSuffix }} + packageShortName: Abstractions + + # ################################################################ + # Build/Pack Microsoft.Data.SqlClient.Extensions.Azure + - template: /eng/pipelines/prci/steps/pack-buildproj-step.yml + parameters: + buildConfiguration: ${{ parameters.buildConfiguration }} + buildSuffix: ${{ parameters.buildSuffix }} + packageShortName: Azure + + # ################################################################ + # Build/Pack Microsoft.Data.SqlClient.Internal.Logging + - template: /eng/pipelines/prci/steps/pack-buildproj-step.yml + parameters: + buildConfiguration: ${{ parameters.buildConfiguration }} + buildSuffix: ${{ parameters.buildSuffix }} + packageShortName: Logging + + # ################################################################ + # Build/Pack Microsoft.SqlServer.Server + - template: /eng/pipelines/prci/steps/pack-buildproj-step.yml + parameters: + buildConfiguration: ${{ parameters.buildConfiguration }} + buildSuffix: ${{ parameters.buildSuffix }} + packageShortName: SqlServer + + # Emit the build output + - script: tree /a /f $(BUILD_OUTPUT) + displayName: Output Build Output Tree + + # Upload the build output as the artifact of the job + - publish: $(BUILD_OUTPUT) + artifact: build_and_pack_projects + + + + diff --git a/eng/pipelines/prci/stages/buid-stage.yml b/eng/pipelines/prci/stages/buid-stage.yml deleted file mode 100644 index 070500b06b..0000000000 --- a/eng/pipelines/prci/stages/buid-stage.yml +++ /dev/null @@ -1,27 +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. # -################################################################################# - -# This stage is meant to perform a sanity check of the source code at the current point in time. -# Although the test targets will implicitly build the projects they depend on, this stage allows -# for fast failure of the build if the source code is not in a state that can be built. -# -# This stage will also be used to generate nuget packages based on the current source code. These -# will be uploaded, along with the build output as the artifacts of the build. - -stages: - - stage: build_projects - displayName: Build Projects - - jobs: - - job: build_projects - displayName: Build Projects - - pool: - vmImage: 'ubuntu-latest' - - steps: - - diff --git a/eng/pipelines/prci/steps/build-buildproj-step.yml b/eng/pipelines/prci/steps/build-buildproj-step.yml new file mode 100644 index 0000000000..fee994a0b4 --- /dev/null +++ b/eng/pipelines/prci/steps/build-buildproj-step.yml @@ -0,0 +1,45 @@ +################################################################################# +# 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 collection of steps to build a project via the build.proj. This will execute the "Build*" +# target in build.proj, where * is the packageShortName provided in the parameters. +# +# Note: This differs from the onebranch build-buildproj-step.yml in that it does *not* strong-name +# sign the assemblies, it only builds in project reference mode, and as such it does not allow +# version parameters or dependencies to be provided. + +parameters: + - name: buildConfiguration + type: string + values: + - Debug + - Release + + - name: buildSuffix + type: string + + - name: packageShortName + type: string + values: + - Azure + - AkvProvider + - Abstractions + - Logging + - SqlClient + - SqlServer + +steps: + - task: DotNetCoreCLI@2 + displayName: 'build.proj - Build${{ parameters.packageShortName }}' + inputs: + command: build + projects: build.proj + arguments: >- + -t:Build${{ parameters.packageShortName }} + -p:BuildNumber='$(Build.BuildNumber)' + -p:BuildSuffix='${{ parameters.buildSuffix }}' + + diff --git a/eng/pipelines/prci/steps/pack-buildproj-step.yml b/eng/pipelines/prci/steps/pack-buildproj-step.yml new file mode 100644 index 0000000000..59b9c55527 --- /dev/null +++ b/eng/pipelines/prci/steps/pack-buildproj-step.yml @@ -0,0 +1,48 @@ +################################################################################# +# 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 is a step to build a project via the build.proj. This will execute the "Pack*" target in +# build.proj, where * is the packageShortName provided in the parameters. Because the "no build" +# parameter is not provided, the target will implicitly build the projects required to create the +# NuGet package. + +parameters: + # Configuration to use to build the project. + - name: buildConfiguration + type: string + values: + - Debug + - Release + + # Suffix to apply to the generated packages such that the package will be considered a prerelease + # version. The resulting package version will look like: `1.2.3-suffix888.1` where 1.2.3 is the + # default version specified in Versions.props, suffix is this parameter, and 888.1 is the build + # number for the currently executing build. + - name: buildSuffix + type: string + + # Package/project to build and pack. + - name: packageShortName + type: string + values: + - Azure + - AkvProvider + - Abstractions + - Logging + - SqlClient + - SqlServer + +steps: + - task: DotNetCoreCLI@2 + displayName: 'build.proj - Build${{ parameters.packageShortName }}' + inputs: + command: build + projects: build.proj + verbosity: detailed + arguments: >- + -t:Pack{{ parameters.packageShortName }} + -p:BuildNumber='$(Build.BuildNumber)' + -p:BuildSuffix='${{ parameters.buildSuffix }}' From 50c02c80aad9034ebc0d36c70afc28d29cdd5f55 Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Fri, 1 May 2026 14:21:56 -0500 Subject: [PATCH 03/55] Move common variables to common folder. Move OneBranch specific variables to OneBranch variables file --- .../variables/common-variables.yml | 16 +--------------- .../onebranch/sqlclient-non-official.yml | 2 +- .../onebranch/sqlclient-official.yml | 2 +- .../variables/onebranch-variables.yml | 19 ++++++++++++++++++- 4 files changed, 21 insertions(+), 18 deletions(-) rename eng/pipelines/{onebranch => common}/variables/common-variables.yml (54%) diff --git a/eng/pipelines/onebranch/variables/common-variables.yml b/eng/pipelines/common/variables/common-variables.yml similarity index 54% rename from eng/pipelines/onebranch/variables/common-variables.yml rename to eng/pipelines/common/variables/common-variables.yml index 5b6209d59d..5f4532778d 100644 --- a/eng/pipelines/onebranch/variables/common-variables.yml +++ b/eng/pipelines/common/variables/common-variables.yml @@ -4,11 +4,9 @@ # See the LICENSE file in the project root for more information. # ################################################################################# -# Common variables shared across all OneBranch Official pipelines. +# Common variables shared across all pipelines. variables: - - name: CommitHead - value: '' # the value will be extracted from the repo's head ########################################################################## # "Well-Known" Variables that are ok to use directly, anywhere in the pipeline. @@ -21,15 +19,3 @@ variables: # ). - name: BUILD_OUTPUT value: $(REPO_ROOT)/artifacts - - # Directory where downloaded pipeline artifacts (NuGet packages from earlier - # stages) are placed. Build jobs use this as a local NuGet package source so - # that downstream packages can resolve dependencies on packages built by - # upstream stages. - - name: JOB_INPUT - value: $(REPO_ROOT)/packages - - # Root directory for all job output artifacts (NuGet packages, symbols, etc.). OneBranch auto - # publishes everything under this directory as the artifact for the job. - - name: JOB_OUTPUT - value: $(REPO_ROOT)/output diff --git a/eng/pipelines/onebranch/sqlclient-non-official.yml b/eng/pipelines/onebranch/sqlclient-non-official.yml index 584bd050f9..abf9b6dcbe 100644 --- a/eng/pipelines/onebranch/sqlclient-non-official.yml +++ b/eng/pipelines/onebranch/sqlclient-non-official.yml @@ -90,7 +90,7 @@ parameters: default: false variables: - - template: /eng/pipelines/onebranch/variables/common-variables.yml@self + - template: /eng/pipelines/common/variables/common-variables.yml@self - template: /eng/pipelines/onebranch/variables/onebranch-variables.yml@self - template: /eng/pipelines/onebranch/variables/package-variables.yml@self parameters: diff --git a/eng/pipelines/onebranch/sqlclient-official.yml b/eng/pipelines/onebranch/sqlclient-official.yml index 07b8da1b17..8ea429bb00 100644 --- a/eng/pipelines/onebranch/sqlclient-official.yml +++ b/eng/pipelines/onebranch/sqlclient-official.yml @@ -112,7 +112,7 @@ parameters: default: false variables: - - template: /eng/pipelines/onebranch/variables/common-variables.yml@self + - template: /eng/pipelines/common/variables/common-variables.yml@self - template: /eng/pipelines/onebranch/variables/onebranch-variables.yml@self - template: /eng/pipelines/onebranch/variables/package-variables.yml@self parameters: diff --git a/eng/pipelines/onebranch/variables/onebranch-variables.yml b/eng/pipelines/onebranch/variables/onebranch-variables.yml index 5a36dbbe75..7d940c1cb7 100644 --- a/eng/pipelines/onebranch/variables/onebranch-variables.yml +++ b/eng/pipelines/onebranch/variables/onebranch-variables.yml @@ -32,8 +32,25 @@ variables: # SymbolsUploadAccount - group: 'symbols-variables-v3' + # Well-Known Variables ################################################### + + # Directory where downloaded pipeline artifacts (NuGet packages from earlier + # stages) are placed. Build jobs use this as a local NuGet package source so + # that downstream packages can resolve dependencies on packages built by + # upstream stages. + - name: JOB_INPUT + value: $(REPO_ROOT)/packages + + # Root directory for all job output artifacts (NuGet packages, symbols, etc.). OneBranch auto + # publishes everything under this directory as the artifact for the job. + - name: JOB_OUTPUT + value: $(REPO_ROOT)/output + # OneBranch Template Variables ########################################### + - name: CommitHead + value: '' # the value will be extracted from the repo's head + # https://aka.ms/obpipelines/sdl - name: ob_sdl_binskim_break value: true @@ -42,7 +59,7 @@ variables: value: true # OneBranch supplies a variety of container images we must use for our jobs. - # + # Windows jobs use this image. - name: WindowsContainerImage value: onebranch.azurecr.io/windows/ltsc2022/vse2022:latest From 2ee5492436fa3b71afced14673fa29403929ceed Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Fri, 1 May 2026 18:15:00 -0500 Subject: [PATCH 04/55] Rename prci-pipeline to pr-pipeline --- eng/pipelines/prci/{prci-pipeline.yml => pr-pipeline.yml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename eng/pipelines/prci/{prci-pipeline.yml => pr-pipeline.yml} (100%) diff --git a/eng/pipelines/prci/prci-pipeline.yml b/eng/pipelines/prci/pr-pipeline.yml similarity index 100% rename from eng/pipelines/prci/prci-pipeline.yml rename to eng/pipelines/prci/pr-pipeline.yml From cca94d8a28f506e20bd5711219dcec22ef60884a Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Fri, 1 May 2026 18:33:16 -0500 Subject: [PATCH 05/55] First round of tests --- eng/pipelines/prci/pr-pipeline.yml | 2 +- ...ack-stage.yml => build-and-pack-stage.yml} | 20 +++++++++---------- .../prci/steps/pack-buildproj-step.yml | 2 +- 3 files changed, 12 insertions(+), 12 deletions(-) rename eng/pipelines/prci/stages/{buid-and-pack-stage.yml => build-and-pack-stage.yml} (96%) diff --git a/eng/pipelines/prci/pr-pipeline.yml b/eng/pipelines/prci/pr-pipeline.yml index bedd8438c9..e97608ccc8 100644 --- a/eng/pipelines/prci/pr-pipeline.yml +++ b/eng/pipelines/prci/pr-pipeline.yml @@ -6,7 +6,7 @@ name: $(DayOfYear)$(Rev:rr) -parameters: +#parameters: variables: - template: /eng/pipelines/common/variables/common-variables.yml@self diff --git a/eng/pipelines/prci/stages/buid-and-pack-stage.yml b/eng/pipelines/prci/stages/build-and-pack-stage.yml similarity index 96% rename from eng/pipelines/prci/stages/buid-and-pack-stage.yml rename to eng/pipelines/prci/stages/build-and-pack-stage.yml index 8d68359907..819a1bd736 100644 --- a/eng/pipelines/prci/stages/buid-and-pack-stage.yml +++ b/eng/pipelines/prci/stages/build-and-pack-stage.yml @@ -18,20 +18,20 @@ # build.proj isn't properly aware of how to do this. So, instead, arranging the build steps # alphabetically is the best way to arrange for now. +parameters: + - name: buildConfiguration + type: string + values: + - Debug + - Release + + - name: buildSuffix + type: string + stages: - stage: build_and_pack_projects displayName: Build and Pack Projects - parameters: - - name: buildConfiguration - type: string - values: - - Debug - - Release - - - name: buildSuffix - type: string - jobs: - job: build_and_pack_projects displayName: Build and Pack Projects diff --git a/eng/pipelines/prci/steps/pack-buildproj-step.yml b/eng/pipelines/prci/steps/pack-buildproj-step.yml index 59b9c55527..4379b7bb42 100644 --- a/eng/pipelines/prci/steps/pack-buildproj-step.yml +++ b/eng/pipelines/prci/steps/pack-buildproj-step.yml @@ -43,6 +43,6 @@ steps: projects: build.proj verbosity: detailed arguments: >- - -t:Pack{{ parameters.packageShortName }} + -t:Pack${{ parameters.packageShortName }} -p:BuildNumber='$(Build.BuildNumber)' -p:BuildSuffix='${{ parameters.buildSuffix }}' From d57e1f4b2093777a2d4501f38bd48b45674763d9 Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Fri, 1 May 2026 18:42:46 -0500 Subject: [PATCH 06/55] Run build/pack regardless of previous package. --- eng/pipelines/prci/stages/build-and-pack-stage.yml | 12 ++++++++++++ eng/pipelines/prci/steps/pack-buildproj-step.yml | 10 ++++++++++ 2 files changed, 22 insertions(+) diff --git a/eng/pipelines/prci/stages/build-and-pack-stage.yml b/eng/pipelines/prci/stages/build-and-pack-stage.yml index 819a1bd736..f5b67c172e 100644 --- a/eng/pipelines/prci/stages/build-and-pack-stage.yml +++ b/eng/pipelines/prci/stages/build-and-pack-stage.yml @@ -47,6 +47,8 @@ stages: # Build/Pack Microsoft.Data.SqlClient - template: /eng/pipelines/prci/steps/pack-buildproj-step.yml parameters: + condition: succeeded() # Only run if dotnet was installed successfully + buildConfiguration: ${{ parameters.buildConfiguration }} buildSuffix: ${{ parameters.buildSuffix }} packageShortName: SqlClient @@ -55,6 +57,8 @@ stages: # Build/Pack Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider - template: /eng/pipelines/prci/steps/pack-buildproj-step.yml parameters: + condition: succeededOrFailed() + buildConfiguration: ${{ parameters.buildConfiguration }} buildSuffix: ${{ parameters.buildSuffix }} packageShortName: AkvProvider @@ -63,6 +67,8 @@ stages: # Build/Pack Microsoft.Data.SqlClient.Extensions.Abstractions - template: /eng/pipelines/prci/steps/pack-buildproj-step.yml parameters: + condition: succeededOrFailed() + buildConfiguration: ${{ parameters.buildConfiguration }} buildSuffix: ${{ parameters.buildSuffix }} packageShortName: Abstractions @@ -71,6 +77,8 @@ stages: # Build/Pack Microsoft.Data.SqlClient.Extensions.Azure - template: /eng/pipelines/prci/steps/pack-buildproj-step.yml parameters: + condition: succeededOrFailed() + buildConfiguration: ${{ parameters.buildConfiguration }} buildSuffix: ${{ parameters.buildSuffix }} packageShortName: Azure @@ -79,6 +87,8 @@ stages: # Build/Pack Microsoft.Data.SqlClient.Internal.Logging - template: /eng/pipelines/prci/steps/pack-buildproj-step.yml parameters: + condition: succeededOrFailed() + buildConfiguration: ${{ parameters.buildConfiguration }} buildSuffix: ${{ parameters.buildSuffix }} packageShortName: Logging @@ -87,6 +97,8 @@ stages: # Build/Pack Microsoft.SqlServer.Server - template: /eng/pipelines/prci/steps/pack-buildproj-step.yml parameters: + condition: succeededOrFailed() + buildConfiguration: ${{ parameters.buildConfiguration }} buildSuffix: ${{ parameters.buildSuffix }} packageShortName: SqlServer diff --git a/eng/pipelines/prci/steps/pack-buildproj-step.yml b/eng/pipelines/prci/steps/pack-buildproj-step.yml index 4379b7bb42..d3c9fd73e7 100644 --- a/eng/pipelines/prci/steps/pack-buildproj-step.yml +++ b/eng/pipelines/prci/steps/pack-buildproj-step.yml @@ -10,6 +10,15 @@ # NuGet package. parameters: + # General Parameters ===================================================== + + # Condition parameter to forward onto the DotNetCoreCLI task. + - name: condition + type: string + default: succeeded() + + # Build Parameters ======================================================= + # Configuration to use to build the project. - name: buildConfiguration type: string @@ -38,6 +47,7 @@ parameters: steps: - task: DotNetCoreCLI@2 displayName: 'build.proj - Build${{ parameters.packageShortName }}' + condition: ${{ parameters.condition }} inputs: command: build projects: build.proj From 9ed385268460fd13130c89c443988c4179e2da21 Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Fri, 1 May 2026 18:59:37 -0500 Subject: [PATCH 07/55] Run tree and publish artifact regardless of previous success --- eng/pipelines/Pipelines.csproj | 4 ++++ eng/pipelines/prci/stages/build-and-pack-stage.yml | 2 ++ 2 files changed, 6 insertions(+) diff --git a/eng/pipelines/Pipelines.csproj b/eng/pipelines/Pipelines.csproj index f599c80053..fda1b4778b 100644 --- a/eng/pipelines/Pipelines.csproj +++ b/eng/pipelines/Pipelines.csproj @@ -25,4 +25,8 @@ + + + + diff --git a/eng/pipelines/prci/stages/build-and-pack-stage.yml b/eng/pipelines/prci/stages/build-and-pack-stage.yml index f5b67c172e..c391f3fc3c 100644 --- a/eng/pipelines/prci/stages/build-and-pack-stage.yml +++ b/eng/pipelines/prci/stages/build-and-pack-stage.yml @@ -106,10 +106,12 @@ stages: # Emit the build output - script: tree /a /f $(BUILD_OUTPUT) displayName: Output Build Output Tree + condition: succeededOrFailed() # Upload the build output as the artifact of the job - publish: $(BUILD_OUTPUT) artifact: build_and_pack_projects + condition: succeededOrFailed() From 60782cf2267b817496151a29a9d7e1cf1e87a847 Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Thu, 7 May 2026 19:59:28 -0500 Subject: [PATCH 08/55] Completely untested, let's see what it does. --- eng/pipelines/Pipelines.csproj | 2 +- eng/pipelines/pr/jobs/test-buildproj-job.yml | 71 ++++++++++++ eng/pipelines/pr/pr-pipeline.yml | 52 +++++++++ .../stages/build-and-pack-stage.yml | 12 +-- eng/pipelines/pr/stages/test-stages.yml | 102 ++++++++++++++++++ .../steps/build-buildproj-step.yml | 0 .../steps/pack-buildproj-step.yml | 0 .../pr/steps/test-buildproj-step.yml | 58 ++++++++++ eng/pipelines/prci/pr-pipeline.yml | 19 ---- 9 files changed, 290 insertions(+), 26 deletions(-) create mode 100644 eng/pipelines/pr/jobs/test-buildproj-job.yml create mode 100644 eng/pipelines/pr/pr-pipeline.yml rename eng/pipelines/{prci => pr}/stages/build-and-pack-stage.yml (91%) create mode 100644 eng/pipelines/pr/stages/test-stages.yml rename eng/pipelines/{prci => pr}/steps/build-buildproj-step.yml (100%) rename eng/pipelines/{prci => pr}/steps/pack-buildproj-step.yml (100%) create mode 100644 eng/pipelines/pr/steps/test-buildproj-step.yml delete mode 100644 eng/pipelines/prci/pr-pipeline.yml diff --git a/eng/pipelines/Pipelines.csproj b/eng/pipelines/Pipelines.csproj index fda1b4778b..e4e3bceecb 100644 --- a/eng/pipelines/Pipelines.csproj +++ b/eng/pipelines/Pipelines.csproj @@ -27,6 +27,6 @@ - + diff --git a/eng/pipelines/pr/jobs/test-buildproj-job.yml b/eng/pipelines/pr/jobs/test-buildproj-job.yml new file mode 100644 index 0000000000..57fb3de4fc --- /dev/null +++ b/eng/pipelines/pr/jobs/test-buildproj-job.yml @@ -0,0 +1,71 @@ +################################################################################# +# 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. # +################################################################################# + +parameters: + # General Parameters ===================================================== + + - name: buildConfiguration + type: string + values: + - Debug + - Release + + - name: buildSuffix + type: string + + # Platform Parameters ==================================================== + + - name: platformDisplayName + type: string + + - name: platformDotnet + type: string + + - name: platformImage + type: string + + # Test Parameters ======================================================== + + - name: packageShortName + type: string + values: + - Azure + - AkvProvider + - Abstractions + - Logging + - SqlClient + - SqlServer + + - name: testDisplayName + type: string + + - name: testProject + type: string + default: '' + +jobs: + - job: "test_${{ parameters.platformDisplayName }}_${{ parameters.testDisplayName }}" + displayName: "${{ parameters.testDisplayName}}_${{ parameters.platformDisplayName }}" + + pool: + vmImage: ${{ parameters.platformImage }} + + steps: + # @TODO: Include retry + - template: /eng/pipelines/common/steps/install-dotnet.yml@self + parameters: + ${{ if not(contains(parameters.platformDotnet, 'net4')) }}: + runtimes: + - "${{ replace(parameters.platformDotnet, 'net', '') }}.x" + + - template: /eng/pipelines/pr/steps/test-buildproj-step.yml + parameters: + buildConfiguration: ${{ parameters.buildConfiguration }} + buildSuffix: ${{ parameters.buildSuffix }} + + packageShortName: ${{ parameters.packageShortName }} + targetFramework: ${{ parameters.platformDotnet }} + testProject: ${{ parameters.testProject }} diff --git a/eng/pipelines/pr/pr-pipeline.yml b/eng/pipelines/pr/pr-pipeline.yml new file mode 100644 index 0000000000..2d9d10b73e --- /dev/null +++ b/eng/pipelines/pr/pr-pipeline.yml @@ -0,0 +1,52 @@ +################################################################################# +# 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. # +################################################################################# + +name: $(DayOfYear)$(Rev:rr) + +#parameters: + +variables: + - template: /eng/pipelines/common/variables/common-variables.yml@self + +stages: + # Stage 1: Build and pack all projects in the repository + - template: /eng/pipelines/pr/stages/build-and-pack-stage.yml + parameters: + buildConfiguration: Debug + buildSuffix: pr + + # Stage 2: Execute tests + - template: /eng/pipelines/pr/stages/test-stages.yml + parameters: + buildConfiguration: Debug + buildSuffix: pr + platforms: + # @TODO: Expand to cover different SQL Server targets + - displayName: "windows_net462" + image: "windows-latest" + dotnet: "net462" + - displayName: "windows_net8" + image: "windows-latest" + dotnet: "net8.0" + - displayName: "windows_net9" + image: "windows-latest" + dotnet: "net9.0" + - displayName: "windows_net10" + image: "windows-latest" + dotnet: "net10.0" + + - displayName: "linux_net8" + image: "ubuntu-latest" + dotnet: "net8.0" + - displayName: "linux_net9" + image: "ubuntu-latest" + dotnet: "net9.0" + - displayName: "linux_net10" + image: "ubuntu-latest" + dotnet: "net10.0" + + # Stage 3: Collect and report code coverage + # @TODO: ^^^ diff --git a/eng/pipelines/prci/stages/build-and-pack-stage.yml b/eng/pipelines/pr/stages/build-and-pack-stage.yml similarity index 91% rename from eng/pipelines/prci/stages/build-and-pack-stage.yml rename to eng/pipelines/pr/stages/build-and-pack-stage.yml index c391f3fc3c..963c47cef6 100644 --- a/eng/pipelines/prci/stages/build-and-pack-stage.yml +++ b/eng/pipelines/pr/stages/build-and-pack-stage.yml @@ -45,7 +45,7 @@ stages: # ################################################################ # Build/Pack Microsoft.Data.SqlClient - - template: /eng/pipelines/prci/steps/pack-buildproj-step.yml + - template: /eng/pipelines/pr/steps/pack-buildproj-step.yml parameters: condition: succeeded() # Only run if dotnet was installed successfully @@ -55,7 +55,7 @@ stages: # ################################################################ # Build/Pack Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider - - template: /eng/pipelines/prci/steps/pack-buildproj-step.yml + - template: /eng/pipelines/pr/steps/pack-buildproj-step.yml parameters: condition: succeededOrFailed() @@ -65,7 +65,7 @@ stages: # ################################################################ # Build/Pack Microsoft.Data.SqlClient.Extensions.Abstractions - - template: /eng/pipelines/prci/steps/pack-buildproj-step.yml + - template: /eng/pipelines/pr/steps/pack-buildproj-step.yml parameters: condition: succeededOrFailed() @@ -75,7 +75,7 @@ stages: # ################################################################ # Build/Pack Microsoft.Data.SqlClient.Extensions.Azure - - template: /eng/pipelines/prci/steps/pack-buildproj-step.yml + - template: /eng/pipelines/pr/steps/pack-buildproj-step.yml parameters: condition: succeededOrFailed() @@ -85,7 +85,7 @@ stages: # ################################################################ # Build/Pack Microsoft.Data.SqlClient.Internal.Logging - - template: /eng/pipelines/prci/steps/pack-buildproj-step.yml + - template: /eng/pipelines/pr/steps/pack-buildproj-step.yml parameters: condition: succeededOrFailed() @@ -95,7 +95,7 @@ stages: # ################################################################ # Build/Pack Microsoft.SqlServer.Server - - template: /eng/pipelines/prci/steps/pack-buildproj-step.yml + - template: /eng/pipelines/pr/steps/pack-buildproj-step.yml parameters: condition: succeededOrFailed() diff --git a/eng/pipelines/pr/stages/test-stages.yml b/eng/pipelines/pr/stages/test-stages.yml new file mode 100644 index 0000000000..a6debe4d86 --- /dev/null +++ b/eng/pipelines/pr/stages/test-stages.yml @@ -0,0 +1,102 @@ +################################################################################# +# 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. # +################################################################################# + +# These stages are meant to validate a PR against a battery of tests to ensure confidence in the +# changes the PR presents. There is, however, a balance to be struck between completeness of +# confidence and expedience of validation. + +parameters: + - name: buildConfiguration + type: string + values: + - Debug + - Release + + - name: buildSuffix + type: string + + # This is an array of objects with the following fields: + # - displayName - Friendly name to use when displaying the stage name and job names. This must + # only contain alphanumeric characters and '_'. It will be used for both display + # name fields and stage/job names. + # - dotnet - Version of dotnet runtime to use to execute the tests + # - image - Image to use to execute the test jobs in the pipeline + # + # Each one of the objects in this parameter will become a stage that executes all test projects + # available. + - name: platforms + type: object + default: [] + +stages: + - ${{ each platform in parameters.platforms }}: + - stage: "test_${{ platform.displayName }}" + displayName: "Test: ${{ platform.displayName }}" + dependsOn: "build_and_pack_projects" + + jobs: + # TestAbstractions + - template: /eng/pipelines/pr/jobs/test-buildproj-job.yml@self + parameters: + buildConfiguration: ${{ parameters.buildConfiguration }} + buildSuffix: ${{ parameters.buildSuffix }} + platformDisplayName: ${{ platform.displayName }} + platformDotnet: ${{ platform.dotnet }} + platformImage: ${{ platform.image }} + + packageShortName: "Abstractions" + testDisplayName: "abstractions" + + # TestAzure + - template: /eng/pipelines/pr/jobs/test-buildproj-job.yml@self + parameters: + buildConfiguration: ${{ parameters.buildConfiguration }} + buildSuffix: ${{ parameters.buildSuffix }} + platformDisplayName: ${{ platform.displayName }} + platformDotnet: ${{ platform.dotnet }} + platformImage: ${{ platform.image }} + + packageShortName: "Azure" + testDisplayName: "azure" + + # TestSqlClientFunctional + - template: /eng/pipelines/pr/jobs/test-buildproj-job.yml@self + parameters: + buildConfiguration: ${{ parameters.buildConfiguration }} + buildSuffix: ${{ parameters.buildSuffix }} + platformDisplayName: ${{ platform.displayName }} + platformDotnet: ${{ platform.dotnet }} + platformImage: ${{ platform.image }} + + packageShortName: "SqlClient" + testDisplayName: "sqlclient_functional" + testProject: "Functional" + + # TestSqlClientManual - PR subset + - template: /eng/pipelines/pr/jobs/test-buildproj-job.yml@self + parameters: + buildConfiguration: ${{ parameters.buildConfiguration }} + buildSuffix: ${{ parameters.buildSuffix }} + platformDisplayName: ${{ platform.displayName }} + platformDotnet: ${{ platform.dotnet }} + platformImage: ${{ platform.image }} + + packageShortName: "SqlClient" + testDisplayName: "sqlclient_manual" + testProject: "Manual" + + # TestSqlClientUnit + - template: /eng/pipelines/pr/jobs/test-buildproj-job.yml@self + parameters: + buildConfiguration: ${{ parameters.buildConfiguration }} + buildSuffix: ${{ parameters.buildSuffix }} + platformDisplayName: ${{ platform.displayName }} + platformDotnet: ${{ platform.dotnet }} + platformImage: ${{ platform.image }} + + packageShortName: "SqlClient" + testDisplayName: "sqlclient_unit" + testProject: "Unit" diff --git a/eng/pipelines/prci/steps/build-buildproj-step.yml b/eng/pipelines/pr/steps/build-buildproj-step.yml similarity index 100% rename from eng/pipelines/prci/steps/build-buildproj-step.yml rename to eng/pipelines/pr/steps/build-buildproj-step.yml diff --git a/eng/pipelines/prci/steps/pack-buildproj-step.yml b/eng/pipelines/pr/steps/pack-buildproj-step.yml similarity index 100% rename from eng/pipelines/prci/steps/pack-buildproj-step.yml rename to eng/pipelines/pr/steps/pack-buildproj-step.yml diff --git a/eng/pipelines/pr/steps/test-buildproj-step.yml b/eng/pipelines/pr/steps/test-buildproj-step.yml new file mode 100644 index 0000000000..5c43536feb --- /dev/null +++ b/eng/pipelines/pr/steps/test-buildproj-step.yml @@ -0,0 +1,58 @@ +################################################################################# +# 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. # +################################################################################# + +parameters: + # General Parameters ======================================================= + + # Configuration to use to build the project. + - name: buildConfiguration + type: string + values: + - Debug + - Release + + # Suffix to apply to the generated packages such that the package will be considered a prerelease + # version. The resulting package version will look like: `1.2.3-suffix888.1` where 1.2.3 is the + # default version specified in Versions.props, suffix is this parameter, and 888.1 is the build + # number for the currently executing build. + - name: buildSuffix + type: string + + # Test Parameters ======================================================== + + # Package/project to test. + - name: packageShortName + type: string + values: + - Azure + - AkvProvider + - Abstractions + - Logging + - SqlClient + - SqlServer + + - name: targetFramework + type: string + + # If the project to test has multiple projects supported by build.proj, use this optional + # parameter to specify the project to execute. This will be appended to Test{PackageShortName} to + # generate the target to execute. See build.proj for supported targets. + - name: testProject + type: string + default: '' + +steps: + - task: DotNetCoreCLI@2 + displayName: 'build.proj - Test${{ parameters.packageShortName }}${{ parameters.testProject }}' + inputs: + command: build + projects: build.proj + verbosity: detailed + arguments: >- + -t:Test${{ parameters.packageShortName }}${{ parameters.testProject }} + -p:BuildNumber='$(Build.BuildNumber)' + -p:BuildSuffix='${{ parameters.buildSuffix }}' + -p:TargetFramework='${{ parameters.targetFramework }}' diff --git a/eng/pipelines/prci/pr-pipeline.yml b/eng/pipelines/prci/pr-pipeline.yml deleted file mode 100644 index e97608ccc8..0000000000 --- a/eng/pipelines/prci/pr-pipeline.yml +++ /dev/null @@ -1,19 +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. # -################################################################################# - -name: $(DayOfYear)$(Rev:rr) - -#parameters: - -variables: - - template: /eng/pipelines/common/variables/common-variables.yml@self - -stages: - # Stage 1: Build and pack all projects in the repository - - template: /eng/pipelines/prci/stages/build-and-pack-stage.yml - parameters: - buildConfiguration: Debug - buildSuffix: pr From 3c85479770328810705e0e127ede4caa33fbb942 Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Fri, 8 May 2026 13:30:34 -0500 Subject: [PATCH 09/55] Rename build-and-pack-stage.yml --- eng/pipelines/pr/pr-pipeline.yml | 2 +- .../pr/stages/{build-and-pack-stage.yml => pack-stage.yml} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename eng/pipelines/pr/stages/{build-and-pack-stage.yml => pack-stage.yml} (100%) diff --git a/eng/pipelines/pr/pr-pipeline.yml b/eng/pipelines/pr/pr-pipeline.yml index 2d9d10b73e..5ec6e4b18e 100644 --- a/eng/pipelines/pr/pr-pipeline.yml +++ b/eng/pipelines/pr/pr-pipeline.yml @@ -13,7 +13,7 @@ variables: stages: # Stage 1: Build and pack all projects in the repository - - template: /eng/pipelines/pr/stages/build-and-pack-stage.yml + - template: /eng/pipelines/pr/stages/pack-stage.yml parameters: buildConfiguration: Debug buildSuffix: pr diff --git a/eng/pipelines/pr/stages/build-and-pack-stage.yml b/eng/pipelines/pr/stages/pack-stage.yml similarity index 100% rename from eng/pipelines/pr/stages/build-and-pack-stage.yml rename to eng/pipelines/pr/stages/pack-stage.yml From 578ba0f87bbbfbc79e7f9a5b8fa1f6965a7acaf7 Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Fri, 8 May 2026 13:45:54 -0500 Subject: [PATCH 10/55] tree on linux --- eng/pipelines/pr/stages/pack-stage.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eng/pipelines/pr/stages/pack-stage.yml b/eng/pipelines/pr/stages/pack-stage.yml index 963c47cef6..466dd0cffc 100644 --- a/eng/pipelines/pr/stages/pack-stage.yml +++ b/eng/pipelines/pr/stages/pack-stage.yml @@ -104,7 +104,7 @@ stages: packageShortName: SqlServer # Emit the build output - - script: tree /a /f $(BUILD_OUTPUT) + - script: tree -a $(BUILD_OUTPUT) displayName: Output Build Output Tree condition: succeededOrFailed() From adfabcfd8e4a23c29093ec5794f2818a4b8fd2a5 Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Fri, 8 May 2026 13:55:14 -0500 Subject: [PATCH 11/55] Fix test framework --- eng/pipelines/pr/jobs/test-buildproj-job.yml | 2 +- eng/pipelines/pr/steps/test-buildproj-step.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/pipelines/pr/jobs/test-buildproj-job.yml b/eng/pipelines/pr/jobs/test-buildproj-job.yml index 57fb3de4fc..cea48d3179 100644 --- a/eng/pipelines/pr/jobs/test-buildproj-job.yml +++ b/eng/pipelines/pr/jobs/test-buildproj-job.yml @@ -67,5 +67,5 @@ jobs: buildSuffix: ${{ parameters.buildSuffix }} packageShortName: ${{ parameters.packageShortName }} - targetFramework: ${{ parameters.platformDotnet }} + testFramework: ${{ parameters.platformDotnet }} testProject: ${{ parameters.testProject }} diff --git a/eng/pipelines/pr/steps/test-buildproj-step.yml b/eng/pipelines/pr/steps/test-buildproj-step.yml index 5c43536feb..4082af30a2 100644 --- a/eng/pipelines/pr/steps/test-buildproj-step.yml +++ b/eng/pipelines/pr/steps/test-buildproj-step.yml @@ -34,7 +34,7 @@ parameters: - SqlClient - SqlServer - - name: targetFramework + - name: testFramework type: string # If the project to test has multiple projects supported by build.proj, use this optional @@ -55,4 +55,4 @@ steps: -t:Test${{ parameters.packageShortName }}${{ parameters.testProject }} -p:BuildNumber='$(Build.BuildNumber)' -p:BuildSuffix='${{ parameters.buildSuffix }}' - -p:TargetFramework='${{ parameters.targetFramework }}' + -p:TestFramework=${{ parameters.testFramework }} From dc8d733817782e26347692577e8d2ad046a651f9 Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Mon, 11 May 2026 13:59:08 -0500 Subject: [PATCH 12/55] Switch images to ones that have sql server on it Move a couple things around WIP for manual test configuration generation --- eng/pipelines/Pipelines.csproj | 4 - eng/pipelines/pr/jobs/test-buildproj-job.yml | 9 +-- .../pr/jobs/test-sqlclientmanual-job.yml | 64 ++++++++++++++++ eng/pipelines/pr/pr-pipeline.yml | 14 ++-- eng/pipelines/pr/steps/install-dotnet.yml | 22 ++++++ eng/pipelines/pr/variables/pr-variables.yml | 73 +++++++++++++++++++ 6 files changed, 169 insertions(+), 17 deletions(-) create mode 100644 eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml create mode 100644 eng/pipelines/pr/steps/install-dotnet.yml create mode 100644 eng/pipelines/pr/variables/pr-variables.yml diff --git a/eng/pipelines/Pipelines.csproj b/eng/pipelines/Pipelines.csproj index e4e3bceecb..f599c80053 100644 --- a/eng/pipelines/Pipelines.csproj +++ b/eng/pipelines/Pipelines.csproj @@ -25,8 +25,4 @@ - - - - diff --git a/eng/pipelines/pr/jobs/test-buildproj-job.yml b/eng/pipelines/pr/jobs/test-buildproj-job.yml index cea48d3179..14a1ea2186 100644 --- a/eng/pipelines/pr/jobs/test-buildproj-job.yml +++ b/eng/pipelines/pr/jobs/test-buildproj-job.yml @@ -48,18 +48,15 @@ parameters: jobs: - job: "test_${{ parameters.platformDisplayName }}_${{ parameters.testDisplayName }}" - displayName: "${{ parameters.testDisplayName}}_${{ parameters.platformDisplayName }}" + displayName: "${{ parameters.testDisplayName }}_${{ parameters.platformDisplayName }}" pool: vmImage: ${{ parameters.platformImage }} steps: - # @TODO: Include retry - - template: /eng/pipelines/common/steps/install-dotnet.yml@self + - template: /eng/pipelines/pr/steps/install-dotnet.yml@self parameters: - ${{ if not(contains(parameters.platformDotnet, 'net4')) }}: - runtimes: - - "${{ replace(parameters.platformDotnet, 'net', '') }}.x" + runtimeVersion: ${{ parameters.platformDotnet }} - template: /eng/pipelines/pr/steps/test-buildproj-step.yml parameters: diff --git a/eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml b/eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml new file mode 100644 index 0000000000..14beb19708 --- /dev/null +++ b/eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml @@ -0,0 +1,64 @@ +################################################################################# +# 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. # +################################################################################# + +parameters: + - name: buildConfiguration + type: string + values: + - Debug + - Release + + - name: buildSuffix + type: string + + # Platform Parameters ==================================================== + + - name: platformDisplayName + type: string + + - name: platformDotnet + type: string + + - name: platformImage + type: string + + # Test Configuration Parameters ========================================== + + - name: azureKeyVaultTenantId + type: string + + - name: azureKeyVaultUrl + type: string + + - name: connectionStringNp + type: string + + - name: connectionStringTcp + type: string + +jobs: + - job: "test_${{ parameters.platformDisplayName }}_sqlclient_manual" + displayName: "sqlclient_manual_${{ parameters.platformDisplayName }}" + + pool: + vmImage: ${{ parameters.platformImage }} + + steps: + - template: /eng/pipelines/pr/steps/install-dotnet.yml@self + parameters: + runtimeVersion: ${{ parameters.platformDotnet }} + + - # @TODO: Config genration step will go here. + + - template: /eng/pipelines/pr/steps/test-buildproj-step.yml + parameters: + buildConfiguration: ${{ parameters.buildConfiguration }} + buildSuffix: ${{ parameters.buildSuffix }} + + packageShortName: ${{ parameters.packageShortName }} + testFramework: ${{ parameters.platformDotnet }} + testProject: ${{ parameters.testProject }} + diff --git a/eng/pipelines/pr/pr-pipeline.yml b/eng/pipelines/pr/pr-pipeline.yml index 5ec6e4b18e..25e86ea0b5 100644 --- a/eng/pipelines/pr/pr-pipeline.yml +++ b/eng/pipelines/pr/pr-pipeline.yml @@ -26,26 +26,26 @@ stages: platforms: # @TODO: Expand to cover different SQL Server targets - displayName: "windows_net462" - image: "windows-latest" + image: "ADO-MMS22-SQL22" dotnet: "net462" - displayName: "windows_net8" - image: "windows-latest" + image: "ADO-MMS22-SQL22" dotnet: "net8.0" - displayName: "windows_net9" - image: "windows-latest" + image: "ADO-MMS22-SQL22" dotnet: "net9.0" - displayName: "windows_net10" - image: "windows-latest" + image: "ADO-MMS22-SQL22" dotnet: "net10.0" - displayName: "linux_net8" - image: "ubuntu-latest" + image: "ADO-UB22-SQL22" dotnet: "net8.0" - displayName: "linux_net9" - image: "ubuntu-latest" + image: "ADO-UB22-SQL22" dotnet: "net9.0" - displayName: "linux_net10" - image: "ubuntu-latest" + image: "ADO-UB22-SQL22" dotnet: "net10.0" # Stage 3: Collect and report code coverage diff --git a/eng/pipelines/pr/steps/install-dotnet.yml b/eng/pipelines/pr/steps/install-dotnet.yml new file mode 100644 index 0000000000..d6e808e65e --- /dev/null +++ b/eng/pipelines/pr/steps/install-dotnet.yml @@ -0,0 +1,22 @@ +################################################################################# +# 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 is a step to wrap the install-dotnet step for use in the PR pipeline. It will always install +# the SDK version specified in the global.json file, and if the runtime version specified does not +# begin with "net4" (ie, indicating netfx runtime is being used), the version will be passed in as +# part of the runtime parameters. + +parameters: + - name: runtimeVersion + type: string + +steps: + # @TODO: Include retry + - template: /eng/pipelines/common/steps/install-dotnet.yml@self + parameters: + ${{ if not(contains(parameters.runtimeVersion, 'net4')) }}: + runtimes: + - "${{ replace(parameters.runtimeVersion, 'net', '') }}.x" diff --git a/eng/pipelines/pr/variables/pr-variables.yml b/eng/pipelines/pr/variables/pr-variables.yml new file mode 100644 index 0000000000..9fa143cb61 --- /dev/null +++ b/eng/pipelines/pr/variables/pr-variables.yml @@ -0,0 +1,73 @@ +################################################################################# +# 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 file contains variables used for running PR pipelines. + +variables: + # Libraries ============================================================== + + # These variables are used to construct the config file for manual tests. + # + # AAD_PASSWORD_CONN_STR + # AAD_PASSWORD_CONN_STR_eastus + # AADAuthorityURL + # AADServicePrincipalId + # AADServicePrincipalSecret + # AZURE_DB_NP_CONN_STRING + # AZURE_DB_NP_CONN_STRING_eastus + # AZURE_DB_TCP_CONN_STRING + # AZURE_DB_TCP_CONN_STRING_eastus + # AZURE_DW_NP_CONN_STRING + # AZURE_DW_TCP_CONN_STRING + # Azure_Password + # Azure_SQL_Server_eastus + # Azure_SQL_Server_westus2 + # AZURE_USERNAME + # AzureKeyVaultTenantId + # AzureKeyVaultUrl + # AzureKeyVaultUrl_EastUS + # Database + # Enclave_Password + # EnclaveEnabled + # Encrypt + # EncryptOptions + # FileStreamDirectory + # LocalDbAppName + # LocalDbSharedInstanceName + # MI_Password + # MI_User + # NamedInstance + # Password + # saUser + # SQL_MI_NP_CONN_STRING + # SQL_MI_TCP_CONN_STRING + # SQL_NP_CONN_STRING + # SQL_NP_CONN_STRING_ENCRYPTED + # SQL_TCP_CONN_STRING + # SQL_TCP_CONN_STRING_AASSGX + # SQL_TCP_CONN_STRING_AASVBS + # SQL_TCP_CONN_STRING_ENCRYPTED + # SQL_TCP_CONN_STRING_ENCRYPTED_UNIX + # SQL_TCP_CONN_STRING_HGSVBS + # SQL_TCP_CONN_STRING_NoneVBS + # SQL_TCP_CONN_STRING_TDS8_Strict_HNIC + # SQL_TCP_INSTANCE_CONN_STRING + # SQL16RootPath + # SQL17RootPath + # SQL19-SGX + # SQL19-VBS + # SQL19RootPath + # SQL22RootPath + # SupportsIntegratedSecurity + # UseManagedSNIOnWindows + # user + # UserManagedIdentityClientId + # UserManagedIdentityClientId_eastus + # UserManagedIdentityObjectId + # UsermanagedIdentityObjectId_eastus + # WorkloadIdentityFederationServiceConnectionId + - group: ADO Test Configuration Properties + From 43d36fcb9715d3aba88fb9a3fc524c27e3bf2bc2 Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Mon, 11 May 2026 14:37:57 -0500 Subject: [PATCH 13/55] :robot: Implement config file generation for manual test --- .../pr/jobs/test-sqlclientmanual-job.yml | 68 ++++++++++++++++++- eng/pipelines/pr/pr-pipeline.yml | 18 ++++- eng/pipelines/pr/stages/test-stages.yml | 59 ++++++++++++++-- 3 files changed, 135 insertions(+), 10 deletions(-) diff --git a/eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml b/eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml index 14beb19708..16c6a9d783 100644 --- a/eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml +++ b/eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml @@ -27,18 +27,46 @@ parameters: # Test Configuration Parameters ========================================== + # The SA password to set when expanding local SQL Server connection strings. + - name: saPassword + type: string + - name: azureKeyVaultTenantId type: string - name: azureKeyVaultUrl type: string + - name: aliasName + type: string + - name: connectionStringNp type: string - name: connectionStringTcp type: string + - name: fileStreamDirectory + type: string + + - name: localDbAppName + type: string + + - name: localDbSharedInstanceName + type: string + + - name: managedIdentitySupported + type: string + + - name: supportsFileStream + type: string + + - name: supportsIntegratedSecurity + type: string + + - name: useManagedSNIOnWindows + type: string + jobs: - job: "test_${{ parameters.platformDisplayName }}_sqlclient_manual" displayName: "sqlclient_manual_${{ parameters.platformDisplayName }}" @@ -51,14 +79,48 @@ jobs: parameters: runtimeVersion: ${{ parameters.platformDotnet }} - - # @TODO: Config genration step will go here. + # @TODO: Document these thingies + + - pwsh: | + $password = "${{ parameters.saPassword }}" + Write-Host "##vso[task.setvariable variable=Password;isSecret=true]$password" + displayName: Set Connection String Password + + - pwsh: | + $defaultConfigPath = "$(REPO_ROOT)/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/config.default.json" + $configDirectory = "$(Agent.TempDirectory)/mds-config" + $configPath = Join-Path $configDirectory "config.json" + + New-Item -ItemType Directory -Force -Path $configDirectory | Out-Null + + $config = Get-Content -Raw $defaultConfigPath | ConvertFrom-Json + + $config.TCPConnectionString = "${{ parameters.connectionStringTcp }}" + $config.NPConnectionString = "${{ parameters.connectionStringNp }}" + $config.AzureKeyVaultURL = "${{ parameters.azureKeyVaultUrl }}" + $config.AzureKeyVaultTenantId = "${{ parameters.azureKeyVaultTenantId }}" + $config.FileStreamDirectory = "${{ parameters.fileStreamDirectory }}" + $config.LocalDbAppName = "${{ parameters.localDbAppName }}" + $config.LocalDbSharedInstanceName = "${{ parameters.localDbSharedInstanceName }}" + $config.AliasName = "${{ parameters.aliasName }}" + + $config.SupportsIntegratedSecurity = [System.Convert]::ToBoolean("${{ parameters.supportsIntegratedSecurity }}") + $config.SupportsFileStream = [System.Convert]::ToBoolean("${{ parameters.supportsFileStream }}") + $config.UseManagedSNIOnWindows = [System.Convert]::ToBoolean("${{ parameters.useManagedSNIOnWindows }}") + $config.ManagedIdentitySupported = [System.Convert]::ToBoolean("${{ parameters.managedIdentitySupported }}") + + $config | ConvertTo-Json | Set-Content $configPath + + #Write-Host "##vso[task.setvariable variable=MDS_CONFIG_FILE]$configPath" + Write-Host "##vso[task.setvariable variable=TEST_MDS_CONFIG]$configPath" + displayName: 'Generate manual test config' - template: /eng/pipelines/pr/steps/test-buildproj-step.yml parameters: buildConfiguration: ${{ parameters.buildConfiguration }} buildSuffix: ${{ parameters.buildSuffix }} - packageShortName: ${{ parameters.packageShortName }} + packageShortName: "SqlClient" testFramework: ${{ parameters.platformDotnet }} - testProject: ${{ parameters.testProject }} + testProject: "Manual" diff --git a/eng/pipelines/pr/pr-pipeline.yml b/eng/pipelines/pr/pr-pipeline.yml index 25e86ea0b5..76fb8290d7 100644 --- a/eng/pipelines/pr/pr-pipeline.yml +++ b/eng/pipelines/pr/pr-pipeline.yml @@ -4,12 +4,11 @@ # See the LICENSE file in the project root for more information. # ################################################################################# -name: $(DayOfYear)$(Rev:rr) - -#parameters: +name: $(DayOfYear).$(Rev:rr) variables: - template: /eng/pipelines/common/variables/common-variables.yml@self + - template: /eng/pipelines/pr/variables/pr-variables.yml@self stages: # Stage 1: Build and pack all projects in the repository @@ -23,6 +22,19 @@ stages: parameters: buildConfiguration: Debug buildSuffix: pr + manualTestConnectionStringTcp: $(SQL_TCP_CONN_STRING) + manualTestConnectionStringNp: $(SQL_NP_CONN_STRING) + manualTestAzureKeyVaultUrl: $(AzureKeyVaultUrl) + manualTestAzureKeyVaultTenantId: $(AzureKeyVaultTenantId) + manualTestFileStreamDirectory: $(FileStreamDirectory) + manualTestLocalDbAppName: $(LocalDbAppName) + manualTestLocalDbSharedInstanceName: $(LocalDbSharedInstanceName) + manualTestAliasName: '' + manualTestSupportsIntegratedSecurity: $(SupportsIntegratedSecurity) + manualTestSupportsFileStream: 'false' + manualTestUseManagedSNIOnWindows: $(UseManagedSNIOnWindows) + manualTestManagedIdentitySupported: 'true' + manualTestSaPassword: $(Password) platforms: # @TODO: Expand to cover different SQL Server targets - displayName: "windows_net462" diff --git a/eng/pipelines/pr/stages/test-stages.yml b/eng/pipelines/pr/stages/test-stages.yml index a6debe4d86..cfb9454b83 100644 --- a/eng/pipelines/pr/stages/test-stages.yml +++ b/eng/pipelines/pr/stages/test-stages.yml @@ -18,6 +18,47 @@ parameters: - name: buildSuffix type: string + # Manual Test Configuration Parameters ================================== + + - name: manualTestConnectionStringTcp + type: string + + - name: manualTestConnectionStringNp + type: string + + - name: manualTestAzureKeyVaultUrl + type: string + + - name: manualTestAzureKeyVaultTenantId + type: string + + - name: manualTestFileStreamDirectory + type: string + + - name: manualTestLocalDbAppName + type: string + + - name: manualTestLocalDbSharedInstanceName + type: string + + - name: manualTestAliasName + type: string + + - name: manualTestSupportsIntegratedSecurity + type: string + + - name: manualTestSupportsFileStream + type: string + + - name: manualTestUseManagedSNIOnWindows + type: string + + - name: manualTestManagedIdentitySupported + type: string + + - name: manualTestSaPassword + type: string + # This is an array of objects with the following fields: # - displayName - Friendly name to use when displaying the stage name and job names. This must # only contain alphanumeric characters and '_'. It will be used for both display @@ -76,7 +117,7 @@ stages: testProject: "Functional" # TestSqlClientManual - PR subset - - template: /eng/pipelines/pr/jobs/test-buildproj-job.yml@self + - template: /eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml@self parameters: buildConfiguration: ${{ parameters.buildConfiguration }} buildSuffix: ${{ parameters.buildSuffix }} @@ -84,9 +125,19 @@ stages: platformDotnet: ${{ platform.dotnet }} platformImage: ${{ platform.image }} - packageShortName: "SqlClient" - testDisplayName: "sqlclient_manual" - testProject: "Manual" + azureKeyVaultTenantId: ${{ parameters.manualTestAzureKeyVaultTenantId }} + azureKeyVaultUrl: ${{ parameters.manualTestAzureKeyVaultUrl }} + connectionStringNp: ${{ parameters.manualTestConnectionStringNp }} + connectionStringTcp: ${{ parameters.manualTestConnectionStringTcp }} + fileStreamDirectory: ${{ parameters.manualTestFileStreamDirectory }} + localDbAppName: ${{ parameters.manualTestLocalDbAppName }} + localDbSharedInstanceName: ${{ parameters.manualTestLocalDbSharedInstanceName }} + aliasName: ${{ parameters.manualTestAliasName }} + supportsIntegratedSecurity: ${{ parameters.manualTestSupportsIntegratedSecurity }} + supportsFileStream: ${{ parameters.manualTestSupportsFileStream }} + useManagedSNIOnWindows: ${{ parameters.manualTestUseManagedSNIOnWindows }} + managedIdentitySupported: ${{ parameters.manualTestManagedIdentitySupported }} + saPassword: ${{ parameters.manualTestSaPassword }} # TestSqlClientUnit - template: /eng/pipelines/pr/jobs/test-buildproj-job.yml@self From eccbeaff22a1b14331c9ca0c2260f087fa28f556 Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Mon, 11 May 2026 17:58:58 -0500 Subject: [PATCH 14/55] Fix build name --- eng/pipelines/pr/pr-pipeline.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eng/pipelines/pr/pr-pipeline.yml b/eng/pipelines/pr/pr-pipeline.yml index 76fb8290d7..faa24d0b44 100644 --- a/eng/pipelines/pr/pr-pipeline.yml +++ b/eng/pipelines/pr/pr-pipeline.yml @@ -4,7 +4,7 @@ # See the LICENSE file in the project root for more information. # ################################################################################# -name: $(DayOfYear).$(Rev:rr) +name: $(DayOfYear)$(Rev:rr) variables: - template: /eng/pipelines/common/variables/common-variables.yml@self From a4915880dddcf1296fe96919a38961dd5e8c1fa7 Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Tue, 12 May 2026 12:30:37 -0500 Subject: [PATCH 15/55] WIP --- eng/pipelines/pr/jobs/test-buildproj-job.yml | 2 ++ eng/pipelines/pr/pr-pipeline.yml | 5 ++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/eng/pipelines/pr/jobs/test-buildproj-job.yml b/eng/pipelines/pr/jobs/test-buildproj-job.yml index 14a1ea2186..05345b388c 100644 --- a/eng/pipelines/pr/jobs/test-buildproj-job.yml +++ b/eng/pipelines/pr/jobs/test-buildproj-job.yml @@ -51,6 +51,8 @@ jobs: displayName: "${{ parameters.testDisplayName }}_${{ parameters.platformDisplayName }}" pool: + # TEST + name: ADO-1ES-Pool vmImage: ${{ parameters.platformImage }} steps: diff --git a/eng/pipelines/pr/pr-pipeline.yml b/eng/pipelines/pr/pr-pipeline.yml index faa24d0b44..3b9aa9f356 100644 --- a/eng/pipelines/pr/pr-pipeline.yml +++ b/eng/pipelines/pr/pr-pipeline.yml @@ -17,7 +17,7 @@ stages: buildConfiguration: Debug buildSuffix: pr - # Stage 2: Execute tests + # Stage 2: Execute tests and collect code coverage - template: /eng/pipelines/pr/stages/test-stages.yml parameters: buildConfiguration: Debug @@ -60,5 +60,4 @@ stages: image: "ADO-UB22-SQL22" dotnet: "net10.0" - # Stage 3: Collect and report code coverage - # @TODO: ^^^ + From 9491067cf704493e753bd7e5c2dc2237bbd8686c Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Tue, 12 May 2026 14:23:45 -0500 Subject: [PATCH 16/55] WIP --- eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml b/eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml index 16c6a9d783..4713a0be85 100644 --- a/eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml +++ b/eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml @@ -72,6 +72,8 @@ jobs: displayName: "sqlclient_manual_${{ parameters.platformDisplayName }}" pool: + # TEST + name: ADO-1ES-Pool vmImage: ${{ parameters.platformImage }} steps: From 5fba197dc530fb65de77fb0a291dc06c75435369 Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Fri, 15 May 2026 12:13:10 -0500 Subject: [PATCH 17/55] Add secret generation stage --- eng/pipelines/pr/pr-pipeline.yml | 14 +++- .../pr/stages/generate-secrets-stage.yml | 67 +++++++++++++++++++ eng/pipelines/pr/stages/pack-stage.yml | 7 +- eng/pipelines/pr/stages/test-stages.yml | 10 ++- eng/pipelines/pr/variables/pr-variables.yml | 6 ++ 5 files changed, 99 insertions(+), 5 deletions(-) create mode 100644 eng/pipelines/pr/stages/generate-secrets-stage.yml diff --git a/eng/pipelines/pr/pr-pipeline.yml b/eng/pipelines/pr/pr-pipeline.yml index 3b9aa9f356..32dd027b79 100644 --- a/eng/pipelines/pr/pr-pipeline.yml +++ b/eng/pipelines/pr/pr-pipeline.yml @@ -11,17 +11,26 @@ variables: - template: /eng/pipelines/pr/variables/pr-variables.yml@self stages: - # Stage 1: Build and pack all projects in the repository + # Stage 1a: Build and pack all projects in the repository - template: /eng/pipelines/pr/stages/pack-stage.yml parameters: buildConfiguration: Debug buildSuffix: pr + stageName: ${{ variables.stageNamePack }} + + # Stage 1b: Generate secrets + - template: /eng/pipelines/pr/stages/generate-secrets-stage.yml + parameters: + stageName: ${{ variables.stageNameSecrets }} # Stage 2: Execute tests and collect code coverage - template: /eng/pipelines/pr/stages/test-stages.yml parameters: buildConfiguration: Debug buildSuffix: pr + stageNamePack: ${{ variables.stageNamePack }} + stageNameSecrets: ${{ variables.stageNameSecrets }} + manualTestConnectionStringTcp: $(SQL_TCP_CONN_STRING) manualTestConnectionStringNp: $(SQL_NP_CONN_STRING) manualTestAzureKeyVaultUrl: $(AzureKeyVaultUrl) @@ -60,4 +69,5 @@ stages: image: "ADO-UB22-SQL22" dotnet: "net10.0" - + # Stage 3: Collect code coverage + # @TODO: diff --git a/eng/pipelines/pr/stages/generate-secrets-stage.yml b/eng/pipelines/pr/stages/generate-secrets-stage.yml new file mode 100644 index 0000000000..5c19270085 --- /dev/null +++ b/eng/pipelines/pr/stages/generate-secrets-stage.yml @@ -0,0 +1,67 @@ +#################################################################################################### +# 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 generates the following random secrets for use throughout the PR and CI pipelines: +# SaPassword - A random GUID suitable for use as the SA password of local SQL Server instances. +# +# Subsequent stages may reference these variables as: +# $[stageDependencies.secrets_stage.secrets_job.outputs['SaPassword.Value']] +# +# For further details on the stage-dependency syntax, see: +# https://learn.microsoft.com/en-us/azure/devops/pipelines/process/set-variables-scripts?view=azure-devops&tabs=bash#set-an-output-variable-for-use-in-future-stages +# +# Any stages that use these secrets must depend on this stage: +# secrets_stage +# +# None of the values produced here are actual secrets - they are just random values that are +# suitable for testing purposes, and do not need to be protected. For simplicity, they are emitted +# as regular output variables of script steps, are not formally marked as secrets, and not stored in +# the Azure DevOps Library or Key Vault. + +parameters: + + # True to emit debug information and steps. + - name: debug + type: boolean + default: false + + - name: stageName + type: string + +stages: + + # The stage downstream stages must depend on to ensure the secrets are generated before they are + # used. + - stage: ${{ parameters.stageName }} + displayName: Generate Secrets + jobs: + + # The job that generates the secrets. Each secret is emitted as an output variable of a + # script step and can be referenced by downstream stages via the stage-dependencies syntax. + - job: secrets_job + displayName: Generate Secrets + pool: + # We don't need anything special, so use the standard Microsoft-hosted Ubuntu image, which + # is typically very fast to spin up. + vmImage: ubuntu-latest + + steps: + + # We don't need the repo checked out. + - checkout: none + + # Generate a password suitable for the SA user of local SQL Server instances. + # This creates the SaPassword.Value variable. + - bash: | + guid=$(cat /proc/sys/kernel/random/uuid) + echo "##vso[task.setvariable variable=Value;isOutput=true]$guid" + name: SaPassword + displayName: Generate SA password + + # Emit the SA password, if desired. + - ${{ if eq(parameters.debug, true) }}: + - bash: | + echo "SA password: $(SaPassword.Value)" + displayName: '[Debug] Emit SA password' diff --git a/eng/pipelines/pr/stages/pack-stage.yml b/eng/pipelines/pr/stages/pack-stage.yml index 466dd0cffc..3576927c7d 100644 --- a/eng/pipelines/pr/stages/pack-stage.yml +++ b/eng/pipelines/pr/stages/pack-stage.yml @@ -28,12 +28,15 @@ parameters: - name: buildSuffix type: string + - name: stageName + type: string + stages: - - stage: build_and_pack_projects + - stage: ${{ parameters.stageName }} displayName: Build and Pack Projects jobs: - - job: build_and_pack_projects + - job: pack_job displayName: Build and Pack Projects pool: diff --git a/eng/pipelines/pr/stages/test-stages.yml b/eng/pipelines/pr/stages/test-stages.yml index cfb9454b83..91b83526d9 100644 --- a/eng/pipelines/pr/stages/test-stages.yml +++ b/eng/pipelines/pr/stages/test-stages.yml @@ -18,6 +18,12 @@ parameters: - name: buildSuffix type: string + - name: stageNamePack + type: string + + - name: stageNameSecrets + type: string + # Manual Test Configuration Parameters ================================== - name: manualTestConnectionStringTcp @@ -76,7 +82,9 @@ stages: - ${{ each platform in parameters.platforms }}: - stage: "test_${{ platform.displayName }}" displayName: "Test: ${{ platform.displayName }}" - dependsOn: "build_and_pack_projects" + dependsOn: + - ${{ parameters.stageNamePack }} + - ${{ parameters.stageNameSecrets }} jobs: # TestAbstractions diff --git a/eng/pipelines/pr/variables/pr-variables.yml b/eng/pipelines/pr/variables/pr-variables.yml index 9fa143cb61..81541ed123 100644 --- a/eng/pipelines/pr/variables/pr-variables.yml +++ b/eng/pipelines/pr/variables/pr-variables.yml @@ -71,3 +71,9 @@ variables: # WorkloadIdentityFederationServiceConnectionId - group: ADO Test Configuration Properties + # Well-known Variables =================================================== + - name: stageNamePack + value: "pack_stage" + + - name: stageNameSecrets + value: "secrets_stage" From 9c32547310a2ff3b6d27ab93e56433a7c15d9172 Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Fri, 15 May 2026 12:25:26 -0500 Subject: [PATCH 18/55] Run pack-stage and generate-secrets-stage in parallel --- eng/pipelines/pr/stages/generate-secrets-stage.yml | 2 ++ eng/pipelines/pr/stages/pack-stage.yml | 1 + 2 files changed, 3 insertions(+) diff --git a/eng/pipelines/pr/stages/generate-secrets-stage.yml b/eng/pipelines/pr/stages/generate-secrets-stage.yml index 5c19270085..5fef8e9165 100644 --- a/eng/pipelines/pr/stages/generate-secrets-stage.yml +++ b/eng/pipelines/pr/stages/generate-secrets-stage.yml @@ -36,6 +36,8 @@ stages: # used. - stage: ${{ parameters.stageName }} displayName: Generate Secrets + dependsOn: [] + jobs: # The job that generates the secrets. Each secret is emitted as an output variable of a diff --git a/eng/pipelines/pr/stages/pack-stage.yml b/eng/pipelines/pr/stages/pack-stage.yml index 3576927c7d..aaf8852e42 100644 --- a/eng/pipelines/pr/stages/pack-stage.yml +++ b/eng/pipelines/pr/stages/pack-stage.yml @@ -34,6 +34,7 @@ parameters: stages: - stage: ${{ parameters.stageName }} displayName: Build and Pack Projects + dependsOn: [] jobs: - job: pack_job From 379b384cc73ee906a875fd23279f61ecaf819cc8 Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Fri, 15 May 2026 20:09:49 -0500 Subject: [PATCH 19/55] More WIP to wire up manual test config --- .../pr/jobs/test-sqlclientmanual-job.yml | 42 +++----- eng/pipelines/pr/pr-pipeline.yml | 23 ++--- eng/pipelines/pr/stages/test-stages.yml | 54 +++++----- .../pr/steps/configure-sqlserver-step.yml | 45 +++++++++ .../configure-sqlserver-windows-step.yml | 99 +++++++++++++++++++ eng/pipelines/pr/variables/pr-variables.yml | 12 +++ 6 files changed, 204 insertions(+), 71 deletions(-) create mode 100644 eng/pipelines/pr/steps/configure-sqlserver-step.yml create mode 100644 eng/pipelines/pr/steps/configure-sqlserver-windows-step.yml diff --git a/eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml b/eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml index 4713a0be85..a54fa9b596 100644 --- a/eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml +++ b/eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml @@ -27,19 +27,12 @@ parameters: # Test Configuration Parameters ========================================== - # The SA password to set when expanding local SQL Server connection strings. - - name: saPassword - type: string - - name: azureKeyVaultTenantId type: string - name: azureKeyVaultUrl type: string - - name: aliasName - type: string - - name: connectionStringNp type: string @@ -49,22 +42,7 @@ parameters: - name: fileStreamDirectory type: string - - name: localDbAppName - type: string - - - name: localDbSharedInstanceName - type: string - - - name: managedIdentitySupported - type: string - - - name: supportsFileStream - type: string - - - name: supportsIntegratedSecurity - type: string - - - name: useManagedSNIOnWindows + - name: saPassword type: string jobs: @@ -81,6 +59,12 @@ jobs: parameters: runtimeVersion: ${{ parameters.platformDotnet }} + - template: /eng/pipelines/pr/steps/configure-sqlserver-step.yml@self + parameters: + dotnetVersion: ${{ parameters.platformDotnet }} + fileStreamDirectory: ${{ parameters.fileStreamDirectory }} + saPassword: ${{ parameters.saPassword }} + # @TODO: Document these thingies - pwsh: | @@ -102,18 +86,14 @@ jobs: $config.AzureKeyVaultURL = "${{ parameters.azureKeyVaultUrl }}" $config.AzureKeyVaultTenantId = "${{ parameters.azureKeyVaultTenantId }}" $config.FileStreamDirectory = "${{ parameters.fileStreamDirectory }}" - $config.LocalDbAppName = "${{ parameters.localDbAppName }}" - $config.LocalDbSharedInstanceName = "${{ parameters.localDbSharedInstanceName }}" - $config.AliasName = "${{ parameters.aliasName }}" - $config.SupportsIntegratedSecurity = [System.Convert]::ToBoolean("${{ parameters.supportsIntegratedSecurity }}") - $config.SupportsFileStream = [System.Convert]::ToBoolean("${{ parameters.supportsFileStream }}") - $config.UseManagedSNIOnWindows = [System.Convert]::ToBoolean("${{ parameters.useManagedSNIOnWindows }}") - $config.ManagedIdentitySupported = [System.Convert]::ToBoolean("${{ parameters.managedIdentitySupported }}") + $config.SupportsIntegratedSecurity = false + $config.SupportsFileStream = true + $config.UseManagedSNIOnWindows = true + $config.ManagedIdentitySupported = true $config | ConvertTo-Json | Set-Content $configPath - #Write-Host "##vso[task.setvariable variable=MDS_CONFIG_FILE]$configPath" Write-Host "##vso[task.setvariable variable=TEST_MDS_CONFIG]$configPath" displayName: 'Generate manual test config' diff --git a/eng/pipelines/pr/pr-pipeline.yml b/eng/pipelines/pr/pr-pipeline.yml index 32dd027b79..b652d98a9d 100644 --- a/eng/pipelines/pr/pr-pipeline.yml +++ b/eng/pipelines/pr/pr-pipeline.yml @@ -31,19 +31,6 @@ stages: stageNamePack: ${{ variables.stageNamePack }} stageNameSecrets: ${{ variables.stageNameSecrets }} - manualTestConnectionStringTcp: $(SQL_TCP_CONN_STRING) - manualTestConnectionStringNp: $(SQL_NP_CONN_STRING) - manualTestAzureKeyVaultUrl: $(AzureKeyVaultUrl) - manualTestAzureKeyVaultTenantId: $(AzureKeyVaultTenantId) - manualTestFileStreamDirectory: $(FileStreamDirectory) - manualTestLocalDbAppName: $(LocalDbAppName) - manualTestLocalDbSharedInstanceName: $(LocalDbSharedInstanceName) - manualTestAliasName: '' - manualTestSupportsIntegratedSecurity: $(SupportsIntegratedSecurity) - manualTestSupportsFileStream: 'false' - manualTestUseManagedSNIOnWindows: $(UseManagedSNIOnWindows) - manualTestManagedIdentitySupported: 'true' - manualTestSaPassword: $(Password) platforms: # @TODO: Expand to cover different SQL Server targets - displayName: "windows_net462" @@ -69,5 +56,15 @@ stages: image: "ADO-UB22-SQL22" dotnet: "net10.0" + manualTestAzureKeyVaultUrl: $(AzureKeyVaultUrl) + manualTestAzureKeyVaultTenantId: $(AzureKeyVaultTenantId) + manualTestConnectionStringLocalNp: $(ConnectionStringNp_LocalhostDefault_UsernamePassword) + manualTestConnectionStringLocalTcp: $(ConnectionStringTcp_LocalhostDefault_UsernamePassword) + manualTestConnectionStringAzureNp: $(ConnectionStringNp_Azure_ManagedIdentity) + manualTestConnectionStringAzureTcp: $(ConnectionStringTcp_Azure_ManagedIdentity) + manualTestFileStreamDirectory: "$(Pipeline.Workspace)/filestream" + manualTestLocalDbAppName: $(LocalDbAppName) + manualTestLocalDbSharedInstanceName: $(LocalDbSharedInstanceName) + # Stage 3: Collect code coverage # @TODO: diff --git a/eng/pipelines/pr/stages/test-stages.yml b/eng/pipelines/pr/stages/test-stages.yml index 91b83526d9..548ac566bf 100644 --- a/eng/pipelines/pr/stages/test-stages.yml +++ b/eng/pipelines/pr/stages/test-stages.yml @@ -26,40 +26,31 @@ parameters: # Manual Test Configuration Parameters ================================== - - name: manualTestConnectionStringTcp - type: string - - - name: manualTestConnectionStringNp - type: string - - - name: manualTestAzureKeyVaultUrl - type: string - - name: manualTestAzureKeyVaultTenantId type: string - - name: manualTestFileStreamDirectory + - name: manualTestAzureKeyVaultUrl type: string - - name: manualTestLocalDbAppName + - name: manualTestConnectionStringNpAzure type: string - - name: manualTestLocalDbSharedInstanceName + - name: manualTestConnectionStringNpLocalhost type: string - - name: manualTestAliasName + - name: manualTestConnectionStringTcpAzure type: string - - name: manualTestSupportsIntegratedSecurity + - name: manualTestConnectionStringTcpLocalhost type: string - - name: manualTestSupportsFileStream + - name: manualTestFileStreamDirectory type: string - - name: manualTestUseManagedSNIOnWindows + - name: manualTestLocalDbAppName type: string - - name: manualTestManagedIdentitySupported + - name: manualTestLocalDbSharedInstanceName type: string - name: manualTestSaPassword @@ -124,7 +115,7 @@ stages: testDisplayName: "sqlclient_functional" testProject: "Functional" - # TestSqlClientManual - PR subset + # TestSqlClientManual - Localhost - template: /eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml@self parameters: buildConfiguration: ${{ parameters.buildConfiguration }} @@ -135,18 +126,27 @@ stages: azureKeyVaultTenantId: ${{ parameters.manualTestAzureKeyVaultTenantId }} azureKeyVaultUrl: ${{ parameters.manualTestAzureKeyVaultUrl }} - connectionStringNp: ${{ parameters.manualTestConnectionStringNp }} - connectionStringTcp: ${{ parameters.manualTestConnectionStringTcp }} + connectionStringNp: ${{ parameters.manualTestConnectionStringNpLocalhost }} + connectionStringTcp: ${{ parameters.manualTestConnectionStringTcpLocalhost }} fileStreamDirectory: ${{ parameters.manualTestFileStreamDirectory }} - localDbAppName: ${{ parameters.manualTestLocalDbAppName }} - localDbSharedInstanceName: ${{ parameters.manualTestLocalDbSharedInstanceName }} - aliasName: ${{ parameters.manualTestAliasName }} - supportsIntegratedSecurity: ${{ parameters.manualTestSupportsIntegratedSecurity }} - supportsFileStream: ${{ parameters.manualTestSupportsFileStream }} - useManagedSNIOnWindows: ${{ parameters.manualTestUseManagedSNIOnWindows }} - managedIdentitySupported: ${{ parameters.manualTestManagedIdentitySupported }} saPassword: ${{ parameters.manualTestSaPassword }} +# # TestSqlClientManual - Azure +# - template: /eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml@self +# parameters: +# buildConfiguration: ${{ parameters.buildConfiguration }} +# buildSuffix: ${{ parameters.buildSuffix }} +# platformDisplayName: ${{ platform.displayName }} +# platformDotnet: ${{ platform.dotnet }} +# platformImage: ${{ platform.image }} +# +# azureKeyVaultTenantId: ${{ parameters.manualTestAzureKeyVaultTenantId }} +# azureKeyVaultUrl: ${{ parameters.manualTestAzureKeyVaultUrl }} +# connectionStringNp: ${{ parameters.manualTestConnectionStringNpAzure }} +# connectionStringTcp: ${{ parameters.manualTestConnectionStringTcpAzure }} +# fileStreamDirectory: ${{ parameters.manualTestFileStreamDirectory }} +# saPassword: ${{ parameters.manualTestSaPassword }} + # TestSqlClientUnit - template: /eng/pipelines/pr/jobs/test-buildproj-job.yml@self parameters: diff --git a/eng/pipelines/pr/steps/configure-sqlserver-step.yml b/eng/pipelines/pr/steps/configure-sqlserver-step.yml new file mode 100644 index 0000000000..bd52a1b26c --- /dev/null +++ b/eng/pipelines/pr/steps/configure-sqlserver-step.yml @@ -0,0 +1,45 @@ +################################################################################# +# 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. # +################################################################################# + +parameters: + # Version of .NET to use to build and run the Ext Utilities that will install the test database. + - name: dotnetVersion + type: string + + # Path to use for file stream tests. This only applies to Windows test runs. + - name: fileStreamDirectory + type: string + + # Password to use for the SA account. This should be generated from the generate-secrets-stage. + - name: saPassword + type: string + +steps: + - ${{ if eq(Agent.OS, 'Windows_NT') }}: + - template: /eng/pipelines/pr/steps/configure-sqlserver-windows-step.yml@self + parameters: + fileStreamDirectory: ${{ parameters.fileStreamDirectory }} + saPassword: ${{ parameters.saPassword }} + + - ${{ elseif eq(Agent.OS, 'Linux') }}: + - template: /eng/pipelines/common/templates/steps/configure-sqlserver-linux-step.yml@self + parameters: + saPassword: ${{ parameters.saPassword }} + + - task: DotNetCoreCLI@2 + displayName: 'Build Ext Utilities' + inputs: + command: build + arguments: '-f ${{ parameters.dotnetVersion }}' + workingDirectory: 'src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.ExtUtilities' + retryCountOnTaskFailure: 1 + + - task: DotNetCoreCLI@2 + displayName: 'Create Northwind Database' + inputs: + command: run + arguments: '-f ${{ parameters.dotnetVersion }} -- "CreateDatabase" Northwind' + workingDirectory: 'src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.ExtUtilities' diff --git a/eng/pipelines/pr/steps/configure-sqlserver-windows-step.yml b/eng/pipelines/pr/steps/configure-sqlserver-windows-step.yml new file mode 100644 index 0000000000..cda0fa8d7e --- /dev/null +++ b/eng/pipelines/pr/steps/configure-sqlserver-windows-step.yml @@ -0,0 +1,99 @@ +################################################################################# +# 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 step configures an existing SQL Server running on the local Windows host. For example, our +# 1ES Hosted Pool has images like ADO-MMS22-SQL22 that come with SQL Server 2022 pre-installed and +# running. + +parameters: + # Path to use for file stream tests. + - name: fileStreamDirectory + type: string + + # Password to use for the SA account. This should be generated from the generate-secrets-stage. + - name: saPassword + type: string + +steps: + # GOTCHA: We must use the Windows-only powershell task here instead of the cross-platform pwsh + # task because we call some Windows-specific cmdlets. + + + # Enable TCP and NP protocols on the default SQL Server instance + - powershell: | + try + { + echo "> 1. Aquire WMI handle" + Import-Module "sqlps" + $smo = 'Microsoft.SqlServer.Management.Smo.' + $wmi = new-object ($smo + 'Wmi.ManagedComputer') + + + Write-Host "WMI Information:" + $wmi + + echo "> 2. Enable TCP on the default instance" + $Tcp = $wmi.GetSmoObject("ManagedComputer[@Name='$env:COMPUTERNAME']/ ServerInstance[@Name='MSSQLSERVER']/ServerProtocol[@Name='Tcp']") + $Tcp.IsEnabled = $true + $Tcp.Alter() + + Write-Host "TCP Information:" + $Tcp + + echo "> 3. Enable named pipes on the default instance" + $Np = $wmi.GetSmoObject("ManagedComputer[@Name='$env:COMPUTERNAME']/ ServerInstance[@Name='MSSQLSERVER']/ServerProtocol[@Name='Np']") + $Np.IsEnabled = $true + $Np.Alter() + + Write-Host "NP Information:" + $Np + } + catch + { + $error[0] | format-list -force + throw + } + + New-NetFirewallRule -DisplayName "SQL TCP Ports" -Direction Inbound -Protocol TCP -LocalPort 1433 -Action allow + $sqlSrvPath = (Get-WmiObject win32_service | ?{$_.DisplayName -eq 'SQL Server (MSSQLSERVER)'} | select @{Name="Path"; Expression={$_.PathName.split('"')[1]}}).Path + New-NetFirewallRule -DisplayName "sqlservr.exe" -Program "$sqlSrvPath" + displayName: 'Enable TCP, NP & Firewall [Win]' + retryCountOnTaskFailure: 2 + + # Set the SA password on the default instance + - powershell: | + # Propagate parameters to PS variables ############################### + $password = "${{ parameters.saPassword }}" + + $machineName = $env:COMPUTERNAME + Write-Host $machineName + + # Connect to database and update SA account ########################## + try + { + Import-Module "sqlps" + + Invoke-Sqlcmd -ServerInstance "$machineName" @" + ALTER LOGIN [sa] ENABLE; + ALTER LOGIN [sa] WITH PASSWORD = '$password'; + "@ + } + catch + { + $error[0] | format-list -force + throw + } + displayName: 'Set SA Password [Win]' + retryCountOnTaskFailure: 5 + + # Create folder for file stream tests + - powershell: | + New-Item -Path ${{ parameters.fileStreamDirectory }} -ItemType Directory + displayName: 'Create FileStreamFolder' + retryCountOnTaskFailure: 1 + continueOnError: true + + diff --git a/eng/pipelines/pr/variables/pr-variables.yml b/eng/pipelines/pr/variables/pr-variables.yml index 81541ed123..af77ece7c1 100644 --- a/eng/pipelines/pr/variables/pr-variables.yml +++ b/eng/pipelines/pr/variables/pr-variables.yml @@ -71,6 +71,18 @@ variables: # WorkloadIdentityFederationServiceConnectionId - group: ADO Test Configuration Properties + # These variables are used to construct the config file for manual tests. + # + # AzureKeyVaultTenantId + # AzureKeyVaultUrl + # ConnectionStringNp_Azure_ManagedIdentity + # ConnectionStringNp_LocalhostDefault_UsernamePassword + # ConnectionStringTcp_Azure_ManagedIdentity + # ConnectionStringTcp_LocalhostDefault_UsernamePassword + # LocalDbAppName + # LocalDbSharedInstanceName + - group: sqlclient-testconfig-v1 + # Well-known Variables =================================================== - name: stageNamePack value: "pack_stage" From b788c71c163eb60ab398b3996833f8d0de05fcc3 Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Mon, 18 May 2026 17:00:04 -0500 Subject: [PATCH 20/55] :robot: Finish wiring up what exists today. Time to try it out and see what's broken. --- .../pr/jobs/test-sqlclientmanual-job.yml | 18 +++++++++++++----- eng/pipelines/pr/pr-pipeline.yml | 15 +++++++++++---- eng/pipelines/pr/stages/test-stages.yml | 16 +++++++++++----- 3 files changed, 35 insertions(+), 14 deletions(-) diff --git a/eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml b/eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml index a54fa9b596..d17a57a362 100644 --- a/eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml +++ b/eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml @@ -42,6 +42,12 @@ parameters: - name: fileStreamDirectory type: string + - name: localDbAppName + type: string + + - name: localDbSharedInstanceName + type: string + - name: saPassword type: string @@ -85,13 +91,15 @@ jobs: $config.NPConnectionString = "${{ parameters.connectionStringNp }}" $config.AzureKeyVaultURL = "${{ parameters.azureKeyVaultUrl }}" $config.AzureKeyVaultTenantId = "${{ parameters.azureKeyVaultTenantId }}" - $config.FileStreamDirectory = "${{ parameters.fileStreamDirectory }}" - - $config.SupportsIntegratedSecurity = false - $config.SupportsFileStream = true - $config.UseManagedSNIOnWindows = true + $config.LocalDbAppName = "${{ parameters.localDbAppName }}" + $config.LocalDbSharedInstanceName = "${{ parameters.localDbSharedInstanceName }}" $config.ManagedIdentitySupported = true + $enableWindowsLocalFeatures = "$(Agent.OS)" -eq "Windows_NT" + $config.SupportsFileStream = $enableWindowsLocalFeatures + $config.FileStreamDirectory = if ($enableWindowsLocalFeatures) { "${{ parameters.fileStreamDirectory }}" } else { "" } + $config.SupportsIntegratedSecurity = $enableWindowsLocalFeatures + $config | ConvertTo-Json | Set-Content $configPath Write-Host "##vso[task.setvariable variable=TEST_MDS_CONFIG]$configPath" diff --git a/eng/pipelines/pr/pr-pipeline.yml b/eng/pipelines/pr/pr-pipeline.yml index b652d98a9d..372b94ec21 100644 --- a/eng/pipelines/pr/pr-pipeline.yml +++ b/eng/pipelines/pr/pr-pipeline.yml @@ -36,32 +36,39 @@ stages: - displayName: "windows_net462" image: "ADO-MMS22-SQL22" dotnet: "net462" + operatingSystem: "Windows" - displayName: "windows_net8" image: "ADO-MMS22-SQL22" dotnet: "net8.0" + operatingSystem: "Windows" - displayName: "windows_net9" image: "ADO-MMS22-SQL22" dotnet: "net9.0" + operatingSystem: "Windows" - displayName: "windows_net10" image: "ADO-MMS22-SQL22" dotnet: "net10.0" + operatingSystem: "Windows" - displayName: "linux_net8" image: "ADO-UB22-SQL22" dotnet: "net8.0" + operatingSystem: "Linux" - displayName: "linux_net9" image: "ADO-UB22-SQL22" dotnet: "net9.0" + operatingSystem: "Linux" - displayName: "linux_net10" image: "ADO-UB22-SQL22" dotnet: "net10.0" + operatingSystem: "Linux" manualTestAzureKeyVaultUrl: $(AzureKeyVaultUrl) manualTestAzureKeyVaultTenantId: $(AzureKeyVaultTenantId) - manualTestConnectionStringLocalNp: $(ConnectionStringNp_LocalhostDefault_UsernamePassword) - manualTestConnectionStringLocalTcp: $(ConnectionStringTcp_LocalhostDefault_UsernamePassword) - manualTestConnectionStringAzureNp: $(ConnectionStringNp_Azure_ManagedIdentity) - manualTestConnectionStringAzureTcp: $(ConnectionStringTcp_Azure_ManagedIdentity) + manualTestConnectionStringNpLocalhost: $(ConnectionStringNp_LocalhostDefault_UsernamePassword) + manualTestConnectionStringTcpLocalhost: $(ConnectionStringTcp_LocalhostDefault_UsernamePassword) + manualTestConnectionStringNpAzure: $(ConnectionStringNp_Azure_ManagedIdentity) + manualTestConnectionStringTcpAzure: $(ConnectionStringTcp_Azure_ManagedIdentity) manualTestFileStreamDirectory: "$(Pipeline.Workspace)/filestream" manualTestLocalDbAppName: $(LocalDbAppName) manualTestLocalDbSharedInstanceName: $(LocalDbSharedInstanceName) diff --git a/eng/pipelines/pr/stages/test-stages.yml b/eng/pipelines/pr/stages/test-stages.yml index 548ac566bf..4d3ea245cf 100644 --- a/eng/pipelines/pr/stages/test-stages.yml +++ b/eng/pipelines/pr/stages/test-stages.yml @@ -53,9 +53,6 @@ parameters: - name: manualTestLocalDbSharedInstanceName type: string - - name: manualTestSaPassword - type: string - # This is an array of objects with the following fields: # - displayName - Friendly name to use when displaying the stage name and job names. This must # only contain alphanumeric characters and '_'. It will be used for both display @@ -77,6 +74,11 @@ stages: - ${{ parameters.stageNamePack }} - ${{ parameters.stageNameSecrets }} + variables: + # Bring the generated SA password from the secrets stage into scope for this test stage. + - name: manualTestSaPassword + value: $[stageDependencies.${{ parameters.stageNameSecrets }}.secrets_job.outputs['SaPassword.Value']] + jobs: # TestAbstractions - template: /eng/pipelines/pr/jobs/test-buildproj-job.yml@self @@ -129,7 +131,9 @@ stages: connectionStringNp: ${{ parameters.manualTestConnectionStringNpLocalhost }} connectionStringTcp: ${{ parameters.manualTestConnectionStringTcpLocalhost }} fileStreamDirectory: ${{ parameters.manualTestFileStreamDirectory }} - saPassword: ${{ parameters.manualTestSaPassword }} + localDbAppName: ${{ parameters.manualTestLocalDbAppName }} + localDbSharedInstanceName: ${{ parameters.manualTestLocalDbSharedInstanceName }} + saPassword: $(manualTestSaPassword) # # TestSqlClientManual - Azure # - template: /eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml@self @@ -145,7 +149,9 @@ stages: # connectionStringNp: ${{ parameters.manualTestConnectionStringNpAzure }} # connectionStringTcp: ${{ parameters.manualTestConnectionStringTcpAzure }} # fileStreamDirectory: ${{ parameters.manualTestFileStreamDirectory }} -# saPassword: ${{ parameters.manualTestSaPassword }} +# localDbAppName: ${{ parameters.manualTestLocalDbAppName }} +# localDbSharedInstanceName: ${{ parameters.manualTestLocalDbSharedInstanceName }} +# saPassword: $(manualTestSaPassword) # TestSqlClientUnit - template: /eng/pipelines/pr/jobs/test-buildproj-job.yml@self From 7b64e1cff6b449392bcafc4bf3e30e0209ecd69e Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Mon, 18 May 2026 17:11:45 -0500 Subject: [PATCH 21/55] Fine, :robot:, you were right. Adding back the operating system parameters --- eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml | 6 +++++- eng/pipelines/pr/pr-pipeline.yml | 14 +++++++------- eng/pipelines/pr/stages/test-stages.yml | 1 + .../pr/steps/configure-sqlserver-step.yml | 7 +++++-- 4 files changed, 18 insertions(+), 10 deletions(-) diff --git a/eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml b/eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml index d17a57a362..5f5b46d5c1 100644 --- a/eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml +++ b/eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml @@ -25,6 +25,9 @@ parameters: - name: platformImage type: string + - name: platformOperatingSystem + type: string + # Test Configuration Parameters ========================================== - name: azureKeyVaultTenantId @@ -69,6 +72,7 @@ jobs: parameters: dotnetVersion: ${{ parameters.platformDotnet }} fileStreamDirectory: ${{ parameters.fileStreamDirectory }} + operatingSystem: ${{ parameters.platformOperatingSystem }} saPassword: ${{ parameters.saPassword }} # @TODO: Document these thingies @@ -95,7 +99,7 @@ jobs: $config.LocalDbSharedInstanceName = "${{ parameters.localDbSharedInstanceName }}" $config.ManagedIdentitySupported = true - $enableWindowsLocalFeatures = "$(Agent.OS)" -eq "Windows_NT" + $enableWindowsLocalFeatures = "${{ parameters.platformOperatingSystem }}" -eq "Windows" $config.SupportsFileStream = $enableWindowsLocalFeatures $config.FileStreamDirectory = if ($enableWindowsLocalFeatures) { "${{ parameters.fileStreamDirectory }}" } else { "" } $config.SupportsIntegratedSecurity = $enableWindowsLocalFeatures diff --git a/eng/pipelines/pr/pr-pipeline.yml b/eng/pipelines/pr/pr-pipeline.yml index 372b94ec21..423653f65c 100644 --- a/eng/pipelines/pr/pr-pipeline.yml +++ b/eng/pipelines/pr/pr-pipeline.yml @@ -34,33 +34,33 @@ stages: platforms: # @TODO: Expand to cover different SQL Server targets - displayName: "windows_net462" - image: "ADO-MMS22-SQL22" dotnet: "net462" + image: "ADO-MMS22-SQL22" operatingSystem: "Windows" - displayName: "windows_net8" - image: "ADO-MMS22-SQL22" dotnet: "net8.0" + image: "ADO-MMS22-SQL22" operatingSystem: "Windows" - displayName: "windows_net9" - image: "ADO-MMS22-SQL22" dotnet: "net9.0" + image: "ADO-MMS22-SQL22" operatingSystem: "Windows" - displayName: "windows_net10" - image: "ADO-MMS22-SQL22" dotnet: "net10.0" + image: "ADO-MMS22-SQL22" operatingSystem: "Windows" - displayName: "linux_net8" - image: "ADO-UB22-SQL22" dotnet: "net8.0" + image: "ADO-UB22-SQL22" operatingSystem: "Linux" - displayName: "linux_net9" - image: "ADO-UB22-SQL22" dotnet: "net9.0" + image: "ADO-UB22-SQL22" operatingSystem: "Linux" - displayName: "linux_net10" - image: "ADO-UB22-SQL22" dotnet: "net10.0" + image: "ADO-UB22-SQL22" operatingSystem: "Linux" manualTestAzureKeyVaultUrl: $(AzureKeyVaultUrl) diff --git a/eng/pipelines/pr/stages/test-stages.yml b/eng/pipelines/pr/stages/test-stages.yml index 4d3ea245cf..b54e7f669a 100644 --- a/eng/pipelines/pr/stages/test-stages.yml +++ b/eng/pipelines/pr/stages/test-stages.yml @@ -125,6 +125,7 @@ stages: platformDisplayName: ${{ platform.displayName }} platformDotnet: ${{ platform.dotnet }} platformImage: ${{ platform.image }} + platformOperatingSystem: ${{ platform.operatingSystem }} azureKeyVaultTenantId: ${{ parameters.manualTestAzureKeyVaultTenantId }} azureKeyVaultUrl: ${{ parameters.manualTestAzureKeyVaultUrl }} diff --git a/eng/pipelines/pr/steps/configure-sqlserver-step.yml b/eng/pipelines/pr/steps/configure-sqlserver-step.yml index bd52a1b26c..ff7d2a4b7a 100644 --- a/eng/pipelines/pr/steps/configure-sqlserver-step.yml +++ b/eng/pipelines/pr/steps/configure-sqlserver-step.yml @@ -13,18 +13,21 @@ parameters: - name: fileStreamDirectory type: string + - name: operatingSystem + type: string + # Password to use for the SA account. This should be generated from the generate-secrets-stage. - name: saPassword type: string steps: - - ${{ if eq(Agent.OS, 'Windows_NT') }}: + - ${{ if eq(parameters.operatingSystem, 'Windows') }}: - template: /eng/pipelines/pr/steps/configure-sqlserver-windows-step.yml@self parameters: fileStreamDirectory: ${{ parameters.fileStreamDirectory }} saPassword: ${{ parameters.saPassword }} - - ${{ elseif eq(Agent.OS, 'Linux') }}: + - ${{ elseif eq(parameters.operatingSystem, 'Linux') }}: - template: /eng/pipelines/common/templates/steps/configure-sqlserver-linux-step.yml@self parameters: saPassword: ${{ parameters.saPassword }} From 6e783fb918a6f82f599c09edb3ac8a26680883e4 Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Mon, 18 May 2026 17:26:26 -0500 Subject: [PATCH 22/55] Fix link to linux config step --- eng/pipelines/pr/steps/configure-sqlserver-step.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eng/pipelines/pr/steps/configure-sqlserver-step.yml b/eng/pipelines/pr/steps/configure-sqlserver-step.yml index ff7d2a4b7a..abd34c32fd 100644 --- a/eng/pipelines/pr/steps/configure-sqlserver-step.yml +++ b/eng/pipelines/pr/steps/configure-sqlserver-step.yml @@ -28,7 +28,7 @@ steps: saPassword: ${{ parameters.saPassword }} - ${{ elseif eq(parameters.operatingSystem, 'Linux') }}: - - template: /eng/pipelines/common/templates/steps/configure-sqlserver-linux-step.yml@self + - template: /eng/pipelines/common/templates/steps/configure-sql-server-linux-step.yml@self parameters: saPassword: ${{ parameters.saPassword }} From cdd461ffdec20dd511b35fdbe8c18121687e7e77 Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Mon, 18 May 2026 18:55:51 -0500 Subject: [PATCH 23/55] :robot: remove dependency on extutilities --- .../pr/jobs/test-sqlclientmanual-job.yml | 1 - .../steps/configure-sqlserver-linux-step.yml | 77 +++++++++++++++++++ .../pr/steps/configure-sqlserver-step.yml | 21 +---- .../configure-sqlserver-windows-step.yml | 14 ++++ 4 files changed, 92 insertions(+), 21 deletions(-) create mode 100644 eng/pipelines/pr/steps/configure-sqlserver-linux-step.yml diff --git a/eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml b/eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml index 5f5b46d5c1..e1ddd43606 100644 --- a/eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml +++ b/eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml @@ -70,7 +70,6 @@ jobs: - template: /eng/pipelines/pr/steps/configure-sqlserver-step.yml@self parameters: - dotnetVersion: ${{ parameters.platformDotnet }} fileStreamDirectory: ${{ parameters.fileStreamDirectory }} operatingSystem: ${{ parameters.platformOperatingSystem }} saPassword: ${{ parameters.saPassword }} diff --git a/eng/pipelines/pr/steps/configure-sqlserver-linux-step.yml b/eng/pipelines/pr/steps/configure-sqlserver-linux-step.yml new file mode 100644 index 0000000000..c11a1fa139 --- /dev/null +++ b/eng/pipelines/pr/steps/configure-sqlserver-linux-step.yml @@ -0,0 +1,77 @@ +################################################################################# +# 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 step configures an existing SQL Server running on the local Linux host. For example, our 1ES +# Hosted Pool has images like ADO-UB20-SQL22 that come with SQL Server 2022 pre-installed and +# running. + +parameters: + + # The SA password to set when configuring SQL Server. + - name: saPassword + type: string + +steps: + + # Configure SQL Server. + - bash: | + sudo systemctl stop mssql-server + + # Password for the SA user (required) + MSSQL_SA_PW="${{ parameters.saPassword }}" + + # Product ID of the version of SQL server you're installing + # Must be evaluation, developer, express, web, standard, enterprise, or your 25 digit product key + MSSQL_PID="enterprise" + + echo Running mssql-conf setup... + sudo MSSQL_SA_PASSWORD="$MSSQL_SA_PW" \ + MSSQL_PID="$MSSQL_PID" \ + /opt/mssql/bin/mssql-conf -n setup accept-eula + + # Connect to server and get the version: + counter=1 + errstatus=1 + while [ $counter -le 5 ] && [ $errstatus = 1 ] + do + echo Waiting for SQL Server to start... + sleep 3s + /opt/mssql-tools/bin/sqlcmd \ + -S localhost \ + -U SA \ + -P "$MSSQL_SA_PW" \ + -Q "SELECT @@VERSION" 2>/dev/null + errstatus=$? + ((counter++)) + done + + # Display error if connection failed: + if [ $errstatus = 1 ] + then + echo Cannot connect to SQL Server, installation aborted + exit $errstatus + fi + displayName: 'Configure SQL Server [Linux]' + + - bash: | + SCRIPT_PATH="$(Build.SourcesDirectory)/tools/testsql/createNorthwindDb.sql" + MSSQL_SA_PW="${{ parameters.saPassword }}" + + /opt/mssql-tools/bin/sqlcmd \ + -S localhost \ + -U SA \ + -P "$MSSQL_SA_PW" \ + -Q "IF DB_ID(N'Northwind') IS NOT NULL BEGIN ALTER DATABASE [Northwind] SET SINGLE_USER WITH ROLLBACK IMMEDIATE; DROP DATABASE [Northwind]; END" \ + -b + + /opt/mssql-tools/bin/sqlcmd \ + -S localhost \ + -U SA \ + -P "$MSSQL_SA_PW" \ + -i "$SCRIPT_PATH" \ + -b + displayName: 'Create Northwind Database [Linux]' + retryCountOnTaskFailure: 1 diff --git a/eng/pipelines/pr/steps/configure-sqlserver-step.yml b/eng/pipelines/pr/steps/configure-sqlserver-step.yml index abd34c32fd..8a386ffe65 100644 --- a/eng/pipelines/pr/steps/configure-sqlserver-step.yml +++ b/eng/pipelines/pr/steps/configure-sqlserver-step.yml @@ -5,10 +5,6 @@ ################################################################################# parameters: - # Version of .NET to use to build and run the Ext Utilities that will install the test database. - - name: dotnetVersion - type: string - # Path to use for file stream tests. This only applies to Windows test runs. - name: fileStreamDirectory type: string @@ -28,21 +24,6 @@ steps: saPassword: ${{ parameters.saPassword }} - ${{ elseif eq(parameters.operatingSystem, 'Linux') }}: - - template: /eng/pipelines/common/templates/steps/configure-sql-server-linux-step.yml@self + - template: /eng/pipelines/pr/steps/configure-sqlserver-linux-step.yml@self parameters: saPassword: ${{ parameters.saPassword }} - - - task: DotNetCoreCLI@2 - displayName: 'Build Ext Utilities' - inputs: - command: build - arguments: '-f ${{ parameters.dotnetVersion }}' - workingDirectory: 'src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.ExtUtilities' - retryCountOnTaskFailure: 1 - - - task: DotNetCoreCLI@2 - displayName: 'Create Northwind Database' - inputs: - command: run - arguments: '-f ${{ parameters.dotnetVersion }} -- "CreateDatabase" Northwind' - workingDirectory: 'src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.ExtUtilities' diff --git a/eng/pipelines/pr/steps/configure-sqlserver-windows-step.yml b/eng/pipelines/pr/steps/configure-sqlserver-windows-step.yml index cda0fa8d7e..c200ae34fe 100644 --- a/eng/pipelines/pr/steps/configure-sqlserver-windows-step.yml +++ b/eng/pipelines/pr/steps/configure-sqlserver-windows-step.yml @@ -96,4 +96,18 @@ steps: retryCountOnTaskFailure: 1 continueOnError: true + - powershell: | + $machineName = $env:COMPUTERNAME + $scriptPath = "$(Build.SourcesDirectory)\tools\testsql\createNorthwindDb.sql" + + Invoke-Sqlcmd -ServerInstance "$machineName" -Query " + IF DB_ID(N'Northwind') IS NOT NULL + BEGIN + ALTER DATABASE [Northwind] SET SINGLE_USER WITH ROLLBACK IMMEDIATE; + DROP DATABASE [Northwind]; + END" + + Invoke-Sqlcmd -ServerInstance "$machineName" -InputFile $scriptPath + displayName: 'Create Northwind Database [Win]' + retryCountOnTaskFailure: 1 From 7b51688702c203a5dba3d7eaa26cbdeef6013696 Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Tue, 19 May 2026 13:49:33 -0500 Subject: [PATCH 24/55] :robot: Get connection string for setting up northwind from config --- .../pr/jobs/test-sqlclientmanual-job.yml | 1 + .../pr/steps/configure-sqlserver-step.yml | 4 +++ .../configure-sqlserver-windows-step.yml | 31 ++++++++++++++++--- 3 files changed, 32 insertions(+), 4 deletions(-) diff --git a/eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml b/eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml index e1ddd43606..a3b30b3817 100644 --- a/eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml +++ b/eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml @@ -70,6 +70,7 @@ jobs: - template: /eng/pipelines/pr/steps/configure-sqlserver-step.yml@self parameters: + connectionStringTcp: ${{ parameters.connectionStringTcp }} fileStreamDirectory: ${{ parameters.fileStreamDirectory }} operatingSystem: ${{ parameters.platformOperatingSystem }} saPassword: ${{ parameters.saPassword }} diff --git a/eng/pipelines/pr/steps/configure-sqlserver-step.yml b/eng/pipelines/pr/steps/configure-sqlserver-step.yml index 8a386ffe65..9508759b72 100644 --- a/eng/pipelines/pr/steps/configure-sqlserver-step.yml +++ b/eng/pipelines/pr/steps/configure-sqlserver-step.yml @@ -5,6 +5,9 @@ ################################################################################# parameters: + - name: connectionStringTcp + type: string + # Path to use for file stream tests. This only applies to Windows test runs. - name: fileStreamDirectory type: string @@ -20,6 +23,7 @@ steps: - ${{ if eq(parameters.operatingSystem, 'Windows') }}: - template: /eng/pipelines/pr/steps/configure-sqlserver-windows-step.yml@self parameters: + connectionStringTcp: ${{ parameters.connectionStringTcp }} fileStreamDirectory: ${{ parameters.fileStreamDirectory }} saPassword: ${{ parameters.saPassword }} diff --git a/eng/pipelines/pr/steps/configure-sqlserver-windows-step.yml b/eng/pipelines/pr/steps/configure-sqlserver-windows-step.yml index c200ae34fe..30c871e31a 100644 --- a/eng/pipelines/pr/steps/configure-sqlserver-windows-step.yml +++ b/eng/pipelines/pr/steps/configure-sqlserver-windows-step.yml @@ -9,6 +9,10 @@ # running. parameters: + # TCP connection string for the local SQL Server instance used by manual tests. + - name: connectionStringTcp + type: string + # Path to use for file stream tests. - name: fileStreamDirectory type: string @@ -97,17 +101,36 @@ steps: continueOnError: true - powershell: | - $machineName = $env:COMPUTERNAME + $password = "${{ parameters.saPassword }}" $scriptPath = "$(Build.SourcesDirectory)\tools\testsql\createNorthwindDb.sql" + $connectionString = "${{ parameters.connectionStringTcp }}" + + Import-Module "sqlps" + Add-Type -AssemblyName System.Data + + $builder = New-Object System.Data.SqlClient.SqlConnectionStringBuilder($connectionString) + $builder['Initial Catalog'] = 'master' + $builder['Password'] = $password + + if (-not $builder.ContainsKey('User ID')) + { + $builder['User ID'] = 'sa' + } - Invoke-Sqlcmd -ServerInstance "$machineName" -Query " + if (-not $builder.ContainsKey('TrustServerCertificate')) + { + $builder['TrustServerCertificate'] = $true + } + + $connectionString = $builder.ConnectionString + + Invoke-Sqlcmd -ConnectionString $connectionString -Query " IF DB_ID(N'Northwind') IS NOT NULL BEGIN ALTER DATABASE [Northwind] SET SINGLE_USER WITH ROLLBACK IMMEDIATE; DROP DATABASE [Northwind]; END" - Invoke-Sqlcmd -ServerInstance "$machineName" -InputFile $scriptPath + Invoke-Sqlcmd -ConnectionString $connectionString -InputFile $scriptPath displayName: 'Create Northwind Database [Win]' retryCountOnTaskFailure: 1 - From 3992b3c0ae4edb8752d777657778f5eb01322886 Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Tue, 19 May 2026 14:12:41 -0500 Subject: [PATCH 25/55] :robot: Only swap out the initial catalog field. --- .../configure-sqlserver-windows-step.yml | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/eng/pipelines/pr/steps/configure-sqlserver-windows-step.yml b/eng/pipelines/pr/steps/configure-sqlserver-windows-step.yml index 30c871e31a..67b94008a9 100644 --- a/eng/pipelines/pr/steps/configure-sqlserver-windows-step.yml +++ b/eng/pipelines/pr/steps/configure-sqlserver-windows-step.yml @@ -101,28 +101,11 @@ steps: continueOnError: true - powershell: | - $password = "${{ parameters.saPassword }}" $scriptPath = "$(Build.SourcesDirectory)\tools\testsql\createNorthwindDb.sql" $connectionString = "${{ parameters.connectionStringTcp }}" Import-Module "sqlps" - Add-Type -AssemblyName System.Data - - $builder = New-Object System.Data.SqlClient.SqlConnectionStringBuilder($connectionString) - $builder['Initial Catalog'] = 'master' - $builder['Password'] = $password - - if (-not $builder.ContainsKey('User ID')) - { - $builder['User ID'] = 'sa' - } - - if (-not $builder.ContainsKey('TrustServerCertificate')) - { - $builder['TrustServerCertificate'] = $true - } - - $connectionString = $builder.ConnectionString + $connectionString = $connectionString -replace '(?i)(Initial Catalog\s*=\s*)[^;]*', '$1master' Invoke-Sqlcmd -ConnectionString $connectionString -Query " IF DB_ID(N'Northwind') IS NOT NULL From 96c193eed043ca5bd904929566d56d9c7a5a182b Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Tue, 19 May 2026 17:52:46 -0500 Subject: [PATCH 26/55] :robot: vs :robot: :fight: --- eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml | 1 - eng/pipelines/pr/steps/configure-sqlserver-step.yml | 3 --- .../pr/steps/configure-sqlserver-windows-step.yml | 12 ++++-------- 3 files changed, 4 insertions(+), 12 deletions(-) diff --git a/eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml b/eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml index a3b30b3817..e1ddd43606 100644 --- a/eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml +++ b/eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml @@ -70,7 +70,6 @@ jobs: - template: /eng/pipelines/pr/steps/configure-sqlserver-step.yml@self parameters: - connectionStringTcp: ${{ parameters.connectionStringTcp }} fileStreamDirectory: ${{ parameters.fileStreamDirectory }} operatingSystem: ${{ parameters.platformOperatingSystem }} saPassword: ${{ parameters.saPassword }} diff --git a/eng/pipelines/pr/steps/configure-sqlserver-step.yml b/eng/pipelines/pr/steps/configure-sqlserver-step.yml index 9508759b72..ebae5390e4 100644 --- a/eng/pipelines/pr/steps/configure-sqlserver-step.yml +++ b/eng/pipelines/pr/steps/configure-sqlserver-step.yml @@ -5,8 +5,6 @@ ################################################################################# parameters: - - name: connectionStringTcp - type: string # Path to use for file stream tests. This only applies to Windows test runs. - name: fileStreamDirectory @@ -23,7 +21,6 @@ steps: - ${{ if eq(parameters.operatingSystem, 'Windows') }}: - template: /eng/pipelines/pr/steps/configure-sqlserver-windows-step.yml@self parameters: - connectionStringTcp: ${{ parameters.connectionStringTcp }} fileStreamDirectory: ${{ parameters.fileStreamDirectory }} saPassword: ${{ parameters.saPassword }} diff --git a/eng/pipelines/pr/steps/configure-sqlserver-windows-step.yml b/eng/pipelines/pr/steps/configure-sqlserver-windows-step.yml index 67b94008a9..7e0059c6c9 100644 --- a/eng/pipelines/pr/steps/configure-sqlserver-windows-step.yml +++ b/eng/pipelines/pr/steps/configure-sqlserver-windows-step.yml @@ -9,9 +9,6 @@ # running. parameters: - # TCP connection string for the local SQL Server instance used by manual tests. - - name: connectionStringTcp - type: string # Path to use for file stream tests. - name: fileStreamDirectory @@ -30,7 +27,7 @@ steps: - powershell: | try { - echo "> 1. Aquire WMI handle" + echo "> 1. Acquire WMI handle" Import-Module "sqlps" $smo = 'Microsoft.SqlServer.Management.Smo.' $wmi = new-object ($smo + 'Wmi.ManagedComputer') @@ -102,18 +99,17 @@ steps: - powershell: | $scriptPath = "$(Build.SourcesDirectory)\tools\testsql\createNorthwindDb.sql" - $connectionString = "${{ parameters.connectionStringTcp }}" + $machineName = $env:COMPUTERNAME Import-Module "sqlps" - $connectionString = $connectionString -replace '(?i)(Initial Catalog\s*=\s*)[^;]*', '$1master' - Invoke-Sqlcmd -ConnectionString $connectionString -Query " + Invoke-Sqlcmd -ServerInstance "$machineName" -Database "master" -Query " IF DB_ID(N'Northwind') IS NOT NULL BEGIN ALTER DATABASE [Northwind] SET SINGLE_USER WITH ROLLBACK IMMEDIATE; DROP DATABASE [Northwind]; END" - Invoke-Sqlcmd -ConnectionString $connectionString -InputFile $scriptPath + Invoke-Sqlcmd -ServerInstance "$machineName" -Database "master" -InputFile $scriptPath displayName: 'Create Northwind Database [Win]' retryCountOnTaskFailure: 1 From bdddb06e33d3bf9b0cd17e8d74341fc29b2b53cb Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Tue, 19 May 2026 18:26:34 -0500 Subject: [PATCH 27/55] Sync config.cs and config.json --- .../Microsoft.Data.SqlClient.TestUtilities/Config.cs | 11 +++++------ .../config.default.json | 7 ++++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/Config.cs b/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/Config.cs index 6e82dc5076..24c9c4f884 100644 --- a/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/Config.cs +++ b/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/Config.cs @@ -15,33 +15,32 @@ public class Config public string TCPConnectionStringHGSVBS = null; public string TCPConnectionStringNoneVBS = null; public string TCPConnectionStringAASSGX = null; + public bool EnclaveEnabled = false; + public bool TracingEnabled = false; public string AADAuthorityURL = null; public string AADPasswordConnectionString = null; public string AADServicePrincipalId = null; public string AADServicePrincipalSecret = null; public string AzureKeyVaultURL = null; public string AzureKeyVaultTenantId = null; + public bool SupportsIntegratedSecurity = false; public string LocalDbAppName = null; public string LocalDbSharedInstanceName = null; - public bool EnclaveEnabled = false; - public bool TracingEnabled = false; - public bool SupportsIntegratedSecurity = false; - public bool ManagedIdentitySupported = true; public string FileStreamDirectory = null; public bool UseManagedSNIOnWindows = false; public string DNSCachingConnString = null; public string DNSCachingServerCR = null; // this is for the control ring public string DNSCachingServerTR = null; // this is for the tenant ring - public bool IsAzureSynapse = false; // True for Azure Data Warehouse/Synapse public bool IsDNSCachingSupportedCR = false; // this is for the control ring public bool IsDNSCachingSupportedTR = false; // this is for the tenant ring public string EnclaveAzureDatabaseConnString = null; + public bool ManagedIdentitySupported = true; public string UserManagedIdentityClientId = null; public string PowerShellPath = null; + public string AliasName = null; public string KerberosDomainPassword = null; public string KerberosDomainUser = null; public bool IsManagedInstance = false; - public string AliasName = null; public static Config Load(string configPath = @"config.json") { diff --git a/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/config.default.json b/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/config.default.json index 4362d07c75..df602f11bf 100644 --- a/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/config.default.json +++ b/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/config.default.json @@ -22,7 +22,6 @@ "SupportsIntegratedSecurity": true, "LocalDbAppName": "", "LocalDbSharedInstanceName": "", - "SupportsFileStream": false, "FileStreamDirectory": "", "UseManagedSNIOnWindows": false, "DNSCachingConnString": "", @@ -30,11 +29,13 @@ "DNSCachingServerTR": "", "IsDNSCachingSupportedCR": false, "IsDNSCachingSupportedTR": false, - "IsAzureSynapse": false, "EnclaveAzureDatabaseConnString": "", "ManagedIdentitySupported": true, "UserManagedIdentityClientId": "", "PowerShellPath": "", "AliasName": "", - "WorkloadIdentityFederationServiceConnectionId": "" + "WorkloadIdentityFederationServiceConnectionId": "", + "KerberosDomainPassword": "", + "KerberosDomainuser": "", + "IsManagedInstance": false } From 61283a09614bbe7e068785a8a7bb4a3a700e2afe Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Tue, 19 May 2026 18:27:23 -0500 Subject: [PATCH 28/55] Cleanup powershells --- .../pr/jobs/test-sqlclientmanual-job.yml | 2 + .../configure-sqlserver-windows-step.yml | 48 +++++++++---------- 2 files changed, 26 insertions(+), 24 deletions(-) diff --git a/eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml b/eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml index e1ddd43606..f2722d3dc6 100644 --- a/eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml +++ b/eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml @@ -82,6 +82,8 @@ jobs: displayName: Set Connection String Password - pwsh: | + # Read existing default configuration from file + $defaultConfigPath = "$(REPO_ROOT)/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/config.default.json" $configDirectory = "$(Agent.TempDirectory)/mds-config" $configPath = Join-Path $configDirectory "config.json" diff --git a/eng/pipelines/pr/steps/configure-sqlserver-windows-step.yml b/eng/pipelines/pr/steps/configure-sqlserver-windows-step.yml index 7e0059c6c9..1675a1b6b4 100644 --- a/eng/pipelines/pr/steps/configure-sqlserver-windows-step.yml +++ b/eng/pipelines/pr/steps/configure-sqlserver-windows-step.yml @@ -22,7 +22,6 @@ steps: # GOTCHA: We must use the Windows-only powershell task here instead of the cross-platform pwsh # task because we call some Windows-specific cmdlets. - # Enable TCP and NP protocols on the default SQL Server instance - powershell: | try @@ -69,24 +68,14 @@ steps: # Propagate parameters to PS variables ############################### $password = "${{ parameters.saPassword }}" - $machineName = $env:COMPUTERNAME - Write-Host $machineName - # Connect to database and update SA account ########################## - try - { - Import-Module "sqlps" + Import-Module "sqlps" + $machineName = $env:COMPUTERNAME - Invoke-Sqlcmd -ServerInstance "$machineName" @" - ALTER LOGIN [sa] ENABLE; - ALTER LOGIN [sa] WITH PASSWORD = '$password'; + Invoke-Sqlcmd -ServerInstance "$machineName" @" + ALTER LOGIN [sa] ENABLE; + ALTER LOGIN [sa] WITH PASSWORD = '$password'; "@ - } - catch - { - $error[0] | format-list -force - throw - } displayName: 'Set SA Password [Win]' retryCountOnTaskFailure: 5 @@ -97,19 +86,30 @@ steps: retryCountOnTaskFailure: 1 continueOnError: true + # Install northwind database - powershell: | - $scriptPath = "$(Build.SourcesDirectory)\tools\testsql\createNorthwindDb.sql" - $machineName = $env:COMPUTERNAME + # Propagate parameters to PS variables ############################### + $repoRoot = $(REPO_ROOT) + echo "repoRoot= $repoRoot" + # Install Northwind Database ######################################### Import-Module "sqlps" + $machineName = $env:COMPUTERNAME - Invoke-Sqlcmd -ServerInstance "$machineName" -Database "master" -Query " - IF DB_ID(N'Northwind') IS NOT NULL - BEGIN - ALTER DATABASE [Northwind] SET SINGLE_USER WITH ROLLBACK IMMEDIATE; - DROP DATABASE [Northwind]; - END" + # Delete any existing northwind database + Invoke-Sqlcmd ` + -ServerInstance "$machineName" ` + -Database "master" ` + -Query @" + IF DB_ID(N'Northwind') IS NOT NULL + BEGIN + ALTER DATABASE [Northwind] SET SINGLE_USER WITH ROLLBACK IMMEDIATE; + DROP DATABASE [Northwind]; + END + "@ + # Install northwind database via script + $scriptPath = "$repoRoot\tools\testsql\createNorthwindDb.sql" Invoke-Sqlcmd -ServerInstance "$machineName" -Database "master" -InputFile $scriptPath displayName: 'Create Northwind Database [Win]' retryCountOnTaskFailure: 1 From 349d7ec91bbb5d07bc202a361216ab97099a9001 Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Wed, 20 May 2026 19:03:57 -0500 Subject: [PATCH 29/55] Config steps --- .../pr/jobs/test-sqlclientmanual-job.yml | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml b/eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml index f2722d3dc6..045209103b 100644 --- a/eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml +++ b/eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml @@ -83,15 +83,12 @@ jobs: - pwsh: | # Read existing default configuration from file - $defaultConfigPath = "$(REPO_ROOT)/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/config.default.json" $configDirectory = "$(Agent.TempDirectory)/mds-config" $configPath = Join-Path $configDirectory "config.json" - - New-Item -ItemType Directory -Force -Path $configDirectory | Out-Null - $config = Get-Content -Raw $defaultConfigPath | ConvertFrom-Json + # Update the config values $config.TCPConnectionString = "${{ parameters.connectionStringTcp }}" $config.NPConnectionString = "${{ parameters.connectionStringNp }}" $config.AzureKeyVaultURL = "${{ parameters.azureKeyVaultUrl }}" @@ -99,14 +96,19 @@ jobs: $config.LocalDbAppName = "${{ parameters.localDbAppName }}" $config.LocalDbSharedInstanceName = "${{ parameters.localDbSharedInstanceName }}" $config.ManagedIdentitySupported = true + $config.SupportsIntegratedSecurity = false - $enableWindowsLocalFeatures = "${{ parameters.platformOperatingSystem }}" -eq "Windows" - $config.SupportsFileStream = $enableWindowsLocalFeatures - $config.FileStreamDirectory = if ($enableWindowsLocalFeatures) { "${{ parameters.fileStreamDirectory }}" } else { "" } - $config.SupportsIntegratedSecurity = $enableWindowsLocalFeatures + if ("${{ parameters.platformOperatingSystem }}" -eq "Windows") { + $config.FileStreamDirectory = "${{ parameters.fileStreamDirectory }}" + } else { + $config.FileStreamDirectory = "" + } + # Write config object to config file + New-Item -ItemType Directory -Force -Path $configDirectory | Out-Null $config | ConvertTo-Json | Set-Content $configPath + # Set generated config file path to environment variable Write-Host "##vso[task.setvariable variable=TEST_MDS_CONFIG]$configPath" displayName: 'Generate manual test config' From 0bda15172eff4b47e5b58c333ca0ced4759d8910 Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Thu, 21 May 2026 10:44:22 -0500 Subject: [PATCH 30/55] :hammer: --- eng/pipelines/pr/steps/configure-sqlserver-windows-step.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eng/pipelines/pr/steps/configure-sqlserver-windows-step.yml b/eng/pipelines/pr/steps/configure-sqlserver-windows-step.yml index 1675a1b6b4..d1567beaee 100644 --- a/eng/pipelines/pr/steps/configure-sqlserver-windows-step.yml +++ b/eng/pipelines/pr/steps/configure-sqlserver-windows-step.yml @@ -89,7 +89,7 @@ steps: # Install northwind database - powershell: | # Propagate parameters to PS variables ############################### - $repoRoot = $(REPO_ROOT) + $repoRoot = "$(REPO_ROOT)" echo "repoRoot= $repoRoot" # Install Northwind Database ######################################### From c2e0ca96452f3b9a1f1dc7f4b584edf8159f6062 Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Thu, 21 May 2026 12:04:24 -0500 Subject: [PATCH 31/55] Diagnostic --- .../pr/jobs/test-sqlclientmanual-job.yml | 70 ++++++++++++------- 1 file changed, 43 insertions(+), 27 deletions(-) diff --git a/eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml b/eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml index 045209103b..68111fb72a 100644 --- a/eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml +++ b/eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml @@ -82,34 +82,50 @@ jobs: displayName: Set Connection String Password - pwsh: | - # Read existing default configuration from file - $defaultConfigPath = "$(REPO_ROOT)/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/config.default.json" - $configDirectory = "$(Agent.TempDirectory)/mds-config" - $configPath = Join-Path $configDirectory "config.json" - $config = Get-Content -Raw $defaultConfigPath | ConvertFrom-Json - - # Update the config values - $config.TCPConnectionString = "${{ parameters.connectionStringTcp }}" - $config.NPConnectionString = "${{ parameters.connectionStringNp }}" - $config.AzureKeyVaultURL = "${{ parameters.azureKeyVaultUrl }}" - $config.AzureKeyVaultTenantId = "${{ parameters.azureKeyVaultTenantId }}" - $config.LocalDbAppName = "${{ parameters.localDbAppName }}" - $config.LocalDbSharedInstanceName = "${{ parameters.localDbSharedInstanceName }}" - $config.ManagedIdentitySupported = true - $config.SupportsIntegratedSecurity = false - - if ("${{ parameters.platformOperatingSystem }}" -eq "Windows") { - $config.FileStreamDirectory = "${{ parameters.fileStreamDirectory }}" - } else { - $config.FileStreamDirectory = "" + try { + # Read existing default configuration from file + $defaultConfigPath = "$(REPO_ROOT)/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/config.default.json" + $configDirectory = "$(Agent.TempDirectory)/mds-config" + $configPath = Join-Path $configDirectory "config.json" + $config = Get-Content -Raw $defaultConfigPath | ConvertFrom-Json + + # Update the config values + $config.TCPConnectionString = "${{ parameters.connectionStringTcp }}" + $config.NPConnectionString = "${{ parameters.connectionStringNp }}" + $config.AzureKeyVaultURL = "${{ parameters.azureKeyVaultUrl }}" + $config.AzureKeyVaultTenantId = "${{ parameters.azureKeyVaultTenantId }}" + $config.LocalDbAppName = "${{ parameters.localDbAppName }}" + $config.LocalDbSharedInstanceName = "${{ parameters.localDbSharedInstanceName }}" + $config.ManagedIdentitySupported = true + $config.SupportsIntegratedSecurity = false + + if ("${{ parameters.platformOperatingSystem }}" -eq "Windows") { + $config.FileStreamDirectory = "${{ parameters.fileStreamDirectory }}" + } else { + $config.FileStreamDirectory = "" + } + + # Write config object to config file + New-Item -ItemType Directory -Force -Path $configDirectory | Out-Null + $config | ConvertTo-Json | Set-Content $configPath + + # Set generated config file path to environment variable + Write-Host "##vso[task.setvariable variable=TEST_MDS_CONFIG]$configPath" + } catch { + Write-Host "Generate manual test config failed." + Write-Host "defaultConfigPath: $defaultConfigPath" + Write-Host "configDirectory: $configDirectory" + Write-Host "configPath: $configPath" + Write-Host "ExceptionType: $($_.Exception.GetType().FullName)" + Write-Host "ExceptionMessage: $($_.Exception.Message)" + Write-Host "InvocationInfo:" + Write-Host $_.InvocationInfo.PositionMessage + Write-Host "ScriptStackTrace:" + Write-Host $_.ScriptStackTrace + Write-Host "ErrorRecord:" + $_ | Format-List * -Force + throw } - - # Write config object to config file - New-Item -ItemType Directory -Force -Path $configDirectory | Out-Null - $config | ConvertTo-Json | Set-Content $configPath - - # Set generated config file path to environment variable - Write-Host "##vso[task.setvariable variable=TEST_MDS_CONFIG]$configPath" displayName: 'Generate manual test config' - template: /eng/pipelines/pr/steps/test-buildproj-step.yml From eb115195e2011838b4a674d9464400a9df58d988 Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Thu, 21 May 2026 13:50:32 -0500 Subject: [PATCH 32/55] Stupid powershell. --- .../pr/jobs/test-sqlclientmanual-job.yml | 70 +++++++------------ 1 file changed, 27 insertions(+), 43 deletions(-) diff --git a/eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml b/eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml index 68111fb72a..6972a45c03 100644 --- a/eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml +++ b/eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml @@ -82,50 +82,34 @@ jobs: displayName: Set Connection String Password - pwsh: | - try { - # Read existing default configuration from file - $defaultConfigPath = "$(REPO_ROOT)/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/config.default.json" - $configDirectory = "$(Agent.TempDirectory)/mds-config" - $configPath = Join-Path $configDirectory "config.json" - $config = Get-Content -Raw $defaultConfigPath | ConvertFrom-Json - - # Update the config values - $config.TCPConnectionString = "${{ parameters.connectionStringTcp }}" - $config.NPConnectionString = "${{ parameters.connectionStringNp }}" - $config.AzureKeyVaultURL = "${{ parameters.azureKeyVaultUrl }}" - $config.AzureKeyVaultTenantId = "${{ parameters.azureKeyVaultTenantId }}" - $config.LocalDbAppName = "${{ parameters.localDbAppName }}" - $config.LocalDbSharedInstanceName = "${{ parameters.localDbSharedInstanceName }}" - $config.ManagedIdentitySupported = true - $config.SupportsIntegratedSecurity = false - - if ("${{ parameters.platformOperatingSystem }}" -eq "Windows") { - $config.FileStreamDirectory = "${{ parameters.fileStreamDirectory }}" - } else { - $config.FileStreamDirectory = "" - } - - # Write config object to config file - New-Item -ItemType Directory -Force -Path $configDirectory | Out-Null - $config | ConvertTo-Json | Set-Content $configPath - - # Set generated config file path to environment variable - Write-Host "##vso[task.setvariable variable=TEST_MDS_CONFIG]$configPath" - } catch { - Write-Host "Generate manual test config failed." - Write-Host "defaultConfigPath: $defaultConfigPath" - Write-Host "configDirectory: $configDirectory" - Write-Host "configPath: $configPath" - Write-Host "ExceptionType: $($_.Exception.GetType().FullName)" - Write-Host "ExceptionMessage: $($_.Exception.Message)" - Write-Host "InvocationInfo:" - Write-Host $_.InvocationInfo.PositionMessage - Write-Host "ScriptStackTrace:" - Write-Host $_.ScriptStackTrace - Write-Host "ErrorRecord:" - $_ | Format-List * -Force - throw + # Read existing default configuration from file + $defaultConfigPath = "$(REPO_ROOT)/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/config.default.json" + $configDirectory = "$(Agent.TempDirectory)/mds-config" + $configPath = Join-Path $configDirectory "config.json" + $config = Get-Content -Raw $defaultConfigPath | ConvertFrom-Json + + # Update the config values + $config.TCPConnectionString = "${{ parameters.connectionStringTcp }}" + $config.NPConnectionString = "${{ parameters.connectionStringNp }}" + $config.AzureKeyVaultURL = "${{ parameters.azureKeyVaultUrl }}" + $config.AzureKeyVaultTenantId = "${{ parameters.azureKeyVaultTenantId }}" + $config.LocalDbAppName = "${{ parameters.localDbAppName }}" + $config.LocalDbSharedInstanceName = "${{ parameters.localDbSharedInstanceName }}" + $config.ManagedIdentitySupported = $true + $config.SupportsIntegratedSecurity = $false + + if ("${{ parameters.platformOperatingSystem }}" -eq "Windows") { + $config.FileStreamDirectory = "${{ parameters.fileStreamDirectory }}" + } else { + $config.FileStreamDirectory = "" } + + # Write config object to config file + New-Item -ItemType Directory -Force -Path $configDirectory | Out-Null + $config | ConvertTo-Json | Set-Content $configPath + + # Set generated config file path to environment variable + Write-Host "##vso[task.setvariable variable=TEST_MDS_CONFIG]$configPath" displayName: 'Generate manual test config' - template: /eng/pipelines/pr/steps/test-buildproj-step.yml From dbd7d95b6f6b303e4c43b112f85c0e103063ed92 Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Thu, 21 May 2026 16:06:07 -0500 Subject: [PATCH 33/55] Making demands. --- eng/pipelines/pr/jobs/test-buildproj-job.yml | 4 +- .../pr/jobs/test-sqlclientmanual-job.yml | 3 +- .../steps/configure-sqlserver-linux-step.yml | 60 +++++++++++++++++-- 3 files changed, 59 insertions(+), 8 deletions(-) diff --git a/eng/pipelines/pr/jobs/test-buildproj-job.yml b/eng/pipelines/pr/jobs/test-buildproj-job.yml index 05345b388c..579c86b0a0 100644 --- a/eng/pipelines/pr/jobs/test-buildproj-job.yml +++ b/eng/pipelines/pr/jobs/test-buildproj-job.yml @@ -51,9 +51,9 @@ jobs: displayName: "${{ parameters.testDisplayName }}_${{ parameters.platformDisplayName }}" pool: - # TEST name: ADO-1ES-Pool - vmImage: ${{ parameters.platformImage }} + demands: + - imageOverride -equals ${{ parameters.platformImage }} steps: - template: /eng/pipelines/pr/steps/install-dotnet.yml@self diff --git a/eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml b/eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml index 6972a45c03..986949855a 100644 --- a/eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml +++ b/eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml @@ -61,7 +61,8 @@ jobs: pool: # TEST name: ADO-1ES-Pool - vmImage: ${{ parameters.platformImage }} + demands: + - imageOverride -equals ${{ parameters.platformImage }} steps: - template: /eng/pipelines/pr/steps/install-dotnet.yml@self diff --git a/eng/pipelines/pr/steps/configure-sqlserver-linux-step.yml b/eng/pipelines/pr/steps/configure-sqlserver-linux-step.yml index c11a1fa139..8eb8cc40d6 100644 --- a/eng/pipelines/pr/steps/configure-sqlserver-linux-step.yml +++ b/eng/pipelines/pr/steps/configure-sqlserver-linux-step.yml @@ -18,7 +18,37 @@ steps: # Configure SQL Server. - bash: | + set -u + + if ! command -v sudo >/dev/null 2>&1; then + echo "ERROR: 'sudo' is required to configure SQL Server on Linux." + exit 1 + fi + + if [ ! -x /opt/mssql/bin/mssql-conf ]; then + echo "ERROR: '/opt/mssql/bin/mssql-conf' was not found." + exit 1 + fi + + SQLCMD_BIN="" + if command -v sqlcmd >/dev/null 2>&1; then + SQLCMD_BIN="$(command -v sqlcmd)" + elif [ -x /opt/mssql-tools18/bin/sqlcmd ]; then + SQLCMD_BIN="/opt/mssql-tools18/bin/sqlcmd" + elif [ -x /opt/mssql-tools/bin/sqlcmd ]; then + SQLCMD_BIN="/opt/mssql-tools/bin/sqlcmd" + else + echo "ERROR: 'sqlcmd' was not found on PATH or in the standard mssql-tools locations." + exit 1 + fi + sudo systemctl stop mssql-server + errstatus=$? + if [ $errstatus -ne 0 ] + then + echo "ERROR: stopping mssql-server failed with exit code $errstatus." + exit $errstatus + fi # Password for the SA user (required) MSSQL_SA_PW="${{ parameters.saPassword }}" @@ -31,15 +61,21 @@ steps: sudo MSSQL_SA_PASSWORD="$MSSQL_SA_PW" \ MSSQL_PID="$MSSQL_PID" \ /opt/mssql/bin/mssql-conf -n setup accept-eula + errstatus=$? + if [ $errstatus -ne 0 ] + then + echo "ERROR: mssql-conf setup failed with exit code $errstatus." + exit $errstatus + fi # Connect to server and get the version: counter=1 errstatus=1 - while [ $counter -le 5 ] && [ $errstatus = 1 ] + while [ $counter -le 5 ] && [ $errstatus -ne 0 ] do echo Waiting for SQL Server to start... sleep 3s - /opt/mssql-tools/bin/sqlcmd \ + "$SQLCMD_BIN" \ -S localhost \ -U SA \ -P "$MSSQL_SA_PW" \ @@ -49,7 +85,7 @@ steps: done # Display error if connection failed: - if [ $errstatus = 1 ] + if [ $errstatus -ne 0 ] then echo Cannot connect to SQL Server, installation aborted exit $errstatus @@ -57,17 +93,31 @@ steps: displayName: 'Configure SQL Server [Linux]' - bash: | + set -u + SCRIPT_PATH="$(Build.SourcesDirectory)/tools/testsql/createNorthwindDb.sql" MSSQL_SA_PW="${{ parameters.saPassword }}" - /opt/mssql-tools/bin/sqlcmd \ + SQLCMD_BIN="" + if command -v sqlcmd >/dev/null 2>&1; then + SQLCMD_BIN="$(command -v sqlcmd)" + elif [ -x /opt/mssql-tools18/bin/sqlcmd ]; then + SQLCMD_BIN="/opt/mssql-tools18/bin/sqlcmd" + elif [ -x /opt/mssql-tools/bin/sqlcmd ]; then + SQLCMD_BIN="/opt/mssql-tools/bin/sqlcmd" + else + echo "ERROR: 'sqlcmd' was not found on PATH or in the standard mssql-tools locations." + exit 1 + fi + + "$SQLCMD_BIN" \ -S localhost \ -U SA \ -P "$MSSQL_SA_PW" \ -Q "IF DB_ID(N'Northwind') IS NOT NULL BEGIN ALTER DATABASE [Northwind] SET SINGLE_USER WITH ROLLBACK IMMEDIATE; DROP DATABASE [Northwind]; END" \ -b - /opt/mssql-tools/bin/sqlcmd \ + "$SQLCMD_BIN" \ -S localhost \ -U SA \ -P "$MSSQL_SA_PW" \ From 462253a8ab7aaf6aad5579e39f48030a538fa15f Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Thu, 21 May 2026 20:56:43 -0500 Subject: [PATCH 34/55] Fixing the first round of manual tests. --- .../SQL/InstanceNameTest/InstanceNameTest.cs | 12 +++--------- .../SQL/SqlCommand/SqlCommandCancelTest.cs | 2 ++ 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/InstanceNameTest/InstanceNameTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/InstanceNameTest/InstanceNameTest.cs index 42a2331be6..cba6712065 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/InstanceNameTest/InstanceNameTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/InstanceNameTest/InstanceNameTest.cs @@ -22,16 +22,10 @@ public static class InstanceNameTest public static void ConnectToSQLWithInstanceNameTest() { SqlConnectionStringBuilder builder = new(DataTestUtility.TCPConnectionString); + DataTestUtility.ParseDataSource(builder.DataSource, out string hostname, out _, out _); - bool proceed = true; - string dataSourceStr = builder.DataSource.Replace("tcp:", ""); - string[] serverNamePartsByBackSlash = dataSourceStr.Split('\\'); - string hostname = serverNamePartsByBackSlash[0]; - if (!dataSourceStr.Contains(",") && serverNamePartsByBackSlash.Length == 2) - { - proceed = !string.IsNullOrWhiteSpace(hostname) && IsBrowserAlive(hostname); - } - + // @TODO: This test as it is written will report success even if it doesn't test anything. + bool proceed = !string.IsNullOrWhiteSpace(hostname) && IsBrowserAlive(hostname); if (proceed) { using SqlConnection connection = new(builder.ConnectionString); diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlCommand/SqlCommandCancelTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlCommand/SqlCommandCancelTest.cs index 552fd4cea5..04b0de8072 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlCommand/SqlCommandCancelTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlCommand/SqlCommandCancelTest.cs @@ -150,6 +150,8 @@ public static void CancelAndDisposePreparedCommand_NamedPipe() => public static void TimeOutDuringRead_Tcp() => TimeOutDuringRead(tcp_connStr); + // @TODO: This test does not test NP behavior as the proxy server converts the named pipe connection string to a TCP connection string. + [ActiveIssue("https://dev.azure.com/SqlClientDrivers/ADO.Net/_workitems/edit/40840/")] [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup), nameof(DataTestUtility.IsNotAzureServer), nameof(DataTestUtility.IsNotNamedInstance))] [PlatformSpecific(TestPlatforms.Windows)] public static void TimeOutDuringRead_NamedPipe() => From 8e1556469592cae6f269c0ebcbab390524e23b06 Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Fri, 22 May 2026 12:51:22 -0500 Subject: [PATCH 35/55] Increase timeout on sql notification test... not ideal but if it helps it helps. --- .../ManualTests/SQL/SqlNotificationTest/SqlNotificationTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlNotificationTest/SqlNotificationTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlNotificationTest/SqlNotificationTest.cs index e4bd1133ac..5823d323ae 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlNotificationTest/SqlNotificationTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlNotificationTest/SqlNotificationTest.cs @@ -11,7 +11,7 @@ namespace Microsoft.Data.SqlClient.ManualTesting.Tests public sealed class SqlNotificationTest : IDisposable { // Misc constants - private const int CALLBACK_TIMEOUT = 5000; // milliseconds + private const int CALLBACK_TIMEOUT = 20000; // milliseconds // Database schema private readonly string _tableName = $"dbo.[SQLDEP_{Guid.NewGuid().ToString()}]"; From fabed0916afd9984f087148d288de564a5256d20 Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Fri, 22 May 2026 12:55:23 -0500 Subject: [PATCH 36/55] Add retries to dotnet install steps --- eng/pipelines/common/steps/install-dotnet.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/eng/pipelines/common/steps/install-dotnet.yml b/eng/pipelines/common/steps/install-dotnet.yml index e6a50ee03f..9c1fe3b819 100644 --- a/eng/pipelines/common/steps/install-dotnet.yml +++ b/eng/pipelines/common/steps/install-dotnet.yml @@ -57,6 +57,7 @@ steps: # Install the SDK listed in the global.json file. - task: UseDotNet@2 displayName: Install .NET SDK (global.json) + retryCountOnTaskFailure: 3 inputs: installationPath: ${{ parameters.installDir }} packageType: sdk @@ -65,10 +66,12 @@ steps: env: PROCESSOR_ARCHITECTURE: x86 + # Install the desired Runtimes, if any. - ${{ each version in parameters.runtimes }}: - task: UseDotNet@2 displayName: Install .NET ${{ version }} Runtime + retryCountOnTaskFailure: 3 inputs: installationPath: ${{ parameters.installDir }} packageType: runtime @@ -83,6 +86,7 @@ steps: # Use the install script for ARM64. - task: PowerShell@2 displayName: Install .NET SDK and Runtimes for ARM64 + retryCountOnTaskFailure: 3 inputs: targetType: filePath pwsh: true From 1aae60b6fe575128c7b948df6ba423aee4e734a2 Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Tue, 26 May 2026 13:33:50 -0500 Subject: [PATCH 37/55] Cleanup and add explicit disposal logic to AlwaysEncrypted.ApiShould.TestExecuteReaderAsyncWithLargeQuery --- .../tests/Common/SqlDataReaderExtensions.cs | 28 ++++++++ .../ManualTests/AlwaysEncrypted/ApiShould.cs | 71 ++++++++++--------- 2 files changed, 67 insertions(+), 32 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/tests/Common/SqlDataReaderExtensions.cs b/src/Microsoft.Data.SqlClient/tests/Common/SqlDataReaderExtensions.cs index 43c7bde4bd..8851cb5210 100644 --- a/src/Microsoft.Data.SqlClient/tests/Common/SqlDataReaderExtensions.cs +++ b/src/Microsoft.Data.SqlClient/tests/Common/SqlDataReaderExtensions.cs @@ -2,6 +2,8 @@ // 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.Threading.Tasks; + namespace Microsoft.Data.SqlClient.Tests.Common { /// @@ -21,6 +23,19 @@ public static void FlushAllResults(this SqlDataReader dataReader) } while (dataReader.NextResult()); } + /// + /// Reads all result sets in the provided and discards them + /// asynchronously. + /// + /// Reader to flush results from. + public static async Task FlushAllResultsAsync(this SqlDataReader dataReader) + { + do + { + await dataReader.FlushResultSetAsync(); + } while (await dataReader.NextResultAsync()); + } + /// /// Reads all results in the current result set of the provided /// and discards them. @@ -33,5 +48,18 @@ public static void FlushResultSet(this SqlDataReader dataReader) // Discard results. } } + + /// + /// Reads all results in the current result set of the provided + /// and discards them asynchronously. + /// + /// Reader to flush results from. + public static async Task FlushResultSetAsync(this SqlDataReader dataReader) + { + while (await dataReader.ReadAsync()) + { + // Discard results. + } + } } } diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/ApiShould.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/ApiShould.cs index 1c16e90ac4..86285e437b 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/ApiShould.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/ApiShould.cs @@ -14,8 +14,11 @@ using Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider; using Microsoft.Data.SqlClient.ManualTesting.Tests.AlwaysEncrypted.Setup; using Microsoft.Data.SqlClient.ManualTesting.Tests.SystemDataInternals; +using Microsoft.Data.SqlClient.Tests.Common; using Xunit; +using CommonObjects = Microsoft.Data.SqlClient.Tests.Common.Fixtures.DatabaseObjects; + namespace Microsoft.Data.SqlClient.ManualTesting.Tests.AlwaysEncrypted { /// @@ -726,37 +729,41 @@ public void TestExecuteReader(string connection) [ClassData(typeof(AEConnectionStringProvider))] public async Task TestExecuteReaderAsyncWithLargeQuery(string connectionString) { - string randomName = DataTestUtility.GetShortName(Guid.NewGuid().ToString().Replace("-", ""), false); - if (randomName.Length > 50) - { - randomName = randomName.Substring(0, 50); - } - string tableName = $"VeryLong_{randomName}_TestTableName"; - int columnsCount = 50; - - // Arrange - drops the table with long name and re-creates it with 52 columns (ID, name, ColumnName0..49) - using SqlConnection connection = new SqlConnection(connectionString); + // Arrange + // - Set up connection to run the test + using SqlConnection connection = new(connectionString); await connection.OpenAsync(); - using Microsoft.Data.SqlClient.Tests.Common.Fixtures.DatabaseObjects.Table wideTable = new(connection, tableName, GenerateBitTableDefinition(columnsCount)); - string name = "nobody"; + // - Drop and create table with 52 columns (ID, name, ColumnName0..49) + string tableName = DataTestUtility.GetShortName("VeryLongTestTableName_", withBracket: false); + const int columnsCount = 50; + using CommonObjects.Table wideTable = new(connection, tableName, GenerateBitTableDefinition(columnsCount)); - // This creates a "select top 100" query that has over 40k characters - using SqlCommand sqlCommand = new(GenerateSelectQuery(wideTable.Name, columnsCount, 10, "WHERE Name = @FirstName AND ID = @CustomerId"), + // - Create SELECT query that has over 40k characters *and repeats 10 times* + using SqlCommand sqlCommand = new( + GenerateSelectQuery(wideTable.Name, columnsCount, 10, "WHERE Name = @FirstName AND ID = @CustomerId"), connection, transaction: null, columnEncryptionSetting: SqlCommandColumnEncryptionSetting.Enabled); - sqlCommand.Parameters.Add(@"CustomerId", SqlDbType.Int); - sqlCommand.Parameters.Add(@"FirstName", SqlDbType.VarChar, name.Length); - sqlCommand.Parameters[0].Value = 0; - sqlCommand.Parameters[1].Value = name; + SqlParameter parameter1 = sqlCommand.Parameters.Add(@"CustomerId", SqlDbType.Int); + parameter1.Value = 0; + + SqlParameter parameter2 = sqlCommand.Parameters.Add(@"FirstName", SqlDbType.VarChar); + parameter2.Value = "nobody"; - // Act and Assert - // Test that execute reader async does not throw an exception. - // The table is empty so there should be no results; however, the bug previously found is that it causes a TDS RPC exception on enclave. + // Act using SqlDataReader sqlDataReader = await sqlCommand.ExecuteReaderAsync(); + + // Assert + // - The table is empty so there should be no results; however, the bug previously + // found is that it causes a TDS RPC exception on enclave. Assert.False(sqlDataReader.HasRows, "The table should be empty"); + + // Cleanup + // - Explicitly throw away the results from the reader to avoid any race conditions in + // disposal logic. + await sqlDataReader.FlushAllResultsAsync(); } [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.IsTargetReadyForAeWithKeyStore))] @@ -1914,7 +1921,7 @@ public void TestExecuteXmlReader(string connection) IList values = GetValues(dataHint: 60); int numberOfRows = 10; - // Insert a bunch of rows in to the table. + // Insert a bunch of rows in to the table. int rowsAffected = InsertRows(tableName: _tableName, numberofRows: numberOfRows, values: values, connection: connection); Assert.True(rowsAffected == numberOfRows, "number of rows affected is unexpected."); @@ -1922,12 +1929,12 @@ public void TestExecuteXmlReader(string connection) { sqlConnection.Open(); - // select the set of rows that were inserted just now. + // select the set of rows that were inserted just now. using (SqlCommand sqlCommand = new SqlCommand($"SELECT LastName FROM [{_tableName}] WHERE FirstName = @FirstName AND CustomerId = @CustomerId FOR XML AUTO;", sqlConnection, transaction: null, columnEncryptionSetting: SqlCommandColumnEncryptionSetting.Enabled)) { if (DataTestUtility.EnclaveEnabled) { - //Increase Time out for enclave-enabled server. + //Increase Time out for enclave-enabled server. sqlCommand.CommandTimeout = 90; } sqlCommand.Parameters.Add(@"CustomerId", SqlDbType.Int); @@ -2031,7 +2038,7 @@ public void TestSqlCommandCancel(string connection, string value) * Use long-running tasks to create the thread. This enables any failed assertions to propagate, rather than * allowing the exception to kill the thread and the process. * These threads should progress in the sequence below: - * + * * Workload Thread | Cancel Thread * ------------------------------------ | ------------- * Start thread | Start thread @@ -2307,7 +2314,7 @@ public void TestConnectionCustomKeyStoreProviderDuringAeQuery(string connectionS () => ExecuteQueryThatRequiresCustomKeyStoreProvider(connection)); AssertExceptionCausedByFailureToDecrypt(ex); - // not required provider will replace the previous entry so required provider will not be found + // not required provider will replace the previous entry so required provider will not be found connection.RegisterColumnEncryptionKeyStoreProvidersOnConnection(_notRequiredProvider); ex = Assert.Throws( () => ExecuteQueryThatRequiresCustomKeyStoreProvider(connection)); @@ -2448,7 +2455,7 @@ public void TestRetryWhenAEParameterMetadataCacheIsStale(string connectionString cmd.CommandText = string.Format(alterCekQueryFormatString, _tableName, table.columnEncryptionKey2.Name); cmd.ExecuteNonQuery(); - // execute the select query again. it will attempt to use the stale cache entry, receive + // execute the select query again. it will attempt to use the stale cache entry, receive // a retryable error from the server, remove the stale cache entry, retry and succeed cmd.CommandText = enclaveSelectQuery; cmd.Parameters.AddWithValue("@CustomerId", 0); @@ -2562,7 +2569,7 @@ public void TestRetryWhenAEEnclaveCacheIsStale(string connectionString) readAsyncTask2.GetAwaiter().GetResult(); #endif */ - + // revert the CEK change to the CustomerId column cmd.Parameters.Clear(); cmd.CommandText = string.Format(alterCekQueryFormatString, _tableName, table.columnEncryptionKey1.Name); @@ -2699,8 +2706,8 @@ private DataTable CreateDataTable(string tableName, int numberofRows) }; table.Columns.Add(column); - // Create three new DataRow objects and add - // them to the DataTable + // Create three new DataRow objects and add + // them to the DataTable for (int i = 0; i < numberofRows; i++) { row = table.NewRow(); @@ -2810,7 +2817,7 @@ private async Task VerifyExecuteScalarAsync(SqlCommand sqlCommand) } /// - /// + /// /// /// /// @@ -2821,7 +2828,7 @@ private async Task ExecuteNonQueryAsync(SqlCommand sqlCommand, CancellationToken } /// - /// + /// /// /// /// From a49c9918697883bd8c83f859e130a5cb61dd11e8 Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Tue, 26 May 2026 14:06:11 -0500 Subject: [PATCH 38/55] Temporarily mark SqlNotificationTest.Test_SingleDependency_AllDefaults_SqlAuth as flay --- .../ManualTests/SQL/SqlNotificationTest/SqlNotificationTest.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlNotificationTest/SqlNotificationTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlNotificationTest/SqlNotificationTest.cs index 5823d323ae..24f34bbf12 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlNotificationTest/SqlNotificationTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlNotificationTest/SqlNotificationTest.cs @@ -143,6 +143,7 @@ public void Test_SingleDependency_Stopped() } [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup), nameof(DataTestUtility.IsNotAzureServer))] + [Trait("Category", "flaky")] public void Test_SingleDependency_AllDefaults_SqlAuth() { Assert.True(SqlDependency.Start(_startConnectionString), "Failed to start listener."); From 772e925d4f1882045cb15267944a78391ab6d621 Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Tue, 26 May 2026 18:35:24 -0500 Subject: [PATCH 39/55] Comments for pipeline, stages, jobs, variables. Moving the SA password retrieval deeper into the manual test job --- eng/pipelines/pr/jobs/test-buildproj-job.yml | 17 ++++++- .../pr/jobs/test-sqlclientmanual-job.yml | 49 +++++++++++++++---- eng/pipelines/pr/pr-pipeline.yml | 1 - .../pr/stages/generate-secrets-stage.yml | 4 +- eng/pipelines/pr/stages/pack-stage.yml | 6 +++ eng/pipelines/pr/stages/test-stages.yml | 29 ++++++++--- eng/pipelines/pr/variables/pr-variables.yml | 2 +- 7 files changed, 88 insertions(+), 20 deletions(-) diff --git a/eng/pipelines/pr/jobs/test-buildproj-job.yml b/eng/pipelines/pr/jobs/test-buildproj-job.yml index 579c86b0a0..520475c33e 100644 --- a/eng/pipelines/pr/jobs/test-buildproj-job.yml +++ b/eng/pipelines/pr/jobs/test-buildproj-job.yml @@ -7,28 +7,36 @@ parameters: # General Parameters ===================================================== + # Configuration with which to build the packages and execute the tests. - name: buildConfiguration type: string values: - Debug - Release + # Suffix to append to the package version to indicate it is a pre-release/development build. - name: buildSuffix type: string # Platform Parameters ==================================================== + # Display name of the platform. This will be formatted into the job's official name as well as + # the display name for the job. As such, only alphanumeric and _ characters are permitted. - name: platformDisplayName type: string + # TFM name of the version of dotnet to run this test with. - name: platformDotnet type: string + # Name of the image in the ADO-1ES-Pool to use to execute this job. - name: platformImage type: string # Test Parameters ======================================================== + # Name of the project to run tests for. This will be used to generate the build.proj target to + # execute: Test{packageShortName}{testProject} - name: packageShortName type: string values: @@ -39,9 +47,14 @@ parameters: - SqlClient - SqlServer + # Display name of the test target that is being executed. This will be formatted into the job's + # official name as well as the display name for the job. As such, only alphanumeric and _ + # characters are permitted. - name: testDisplayName type: string + # Optional test project name to execute. This only applies to packages that have >1 test target. + # eg, for TestSqlClientManual, this should be "Manual" - name: testProject type: string default: '' @@ -53,13 +66,15 @@ jobs: pool: name: ADO-1ES-Pool demands: - - imageOverride -equals ${{ parameters.platformImage }} + - imageOverride -equals ${{ parameters.platformImage }} steps: + # Install the version of the dotnet runtime we will use to execute the test target. - template: /eng/pipelines/pr/steps/install-dotnet.yml@self parameters: runtimeVersion: ${{ parameters.platformDotnet }} + # Execute the test target - template: /eng/pipelines/pr/steps/test-buildproj-step.yml parameters: buildConfiguration: ${{ parameters.buildConfiguration }} diff --git a/eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml b/eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml index 986949855a..56da7d2d66 100644 --- a/eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml +++ b/eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml @@ -5,83 +5,113 @@ ################################################################################# parameters: + # Configuration with which to build the packages and execute the tests. - name: buildConfiguration type: string values: - Debug - Release + # Suffix to append to the package version to indicate it is a pre-release/development build. - name: buildSuffix type: string + # Name of the stage that generated the SA password + - name: stageNameSecrets + type: string + # Platform Parameters ==================================================== + # Display name of the platform. This will be formatted into the job's official name as well as + # the display name for the job. As such, only alphanumeric and _ characters are permitted. - name: platformDisplayName type: string + # TFM name of the version of dotnet to run this test with. - name: platformDotnet type: string + # Name of the image in the ADO-1ES-Pool to use to execute this job. - name: platformImage type: string + # General name of the operating system that will be used to execute the job. + # Note: This is used at compile time to determine which SQL Server setup steps to use. As such, + # this cannot be replaced with the agent's operating system, as this value is only available + # at runtime. - name: platformOperatingSystem type: string + values: + - Windows + - Linux # Test Configuration Parameters ========================================== + # Azure Key Vault tenant ID that will be set in the config.json file. - name: azureKeyVaultTenantId type: string + # Azure Key Vault URL that will be set in the config.json file. - name: azureKeyVaultUrl type: string + # Connection string using named pipes that will be set in the config.json file. - name: connectionStringNp type: string + # Connection string using TCP that will be set in the config.json file. - name: connectionStringTcp type: string + # Path to use for file stream tests, this value will be stored in the config.json file. - name: fileStreamDirectory type: string + # Name of the local DB application name for localdb tests, this value will be stored in the + # config.json - name: localDbAppName type: string + # Name of the local DB shared instance name for localdb tests, this value will be stored in the + # config.json - name: localDbSharedInstanceName type: string - - name: saPassword - type: string - jobs: - job: "test_${{ parameters.platformDisplayName }}_sqlclient_manual" displayName: "sqlclient_manual_${{ parameters.platformDisplayName }}" pool: - # TEST name: ADO-1ES-Pool demands: - - imageOverride -equals ${{ parameters.platformImage }} + - imageOverride -equals ${{ parameters.platformImage }} + + variables: + # Bring the generated SA password from the secrets stage into scope for this test stage. + - name: saPassword + value: $[stageDependencies.${{ parameters.stageNameSecrets }}.secrets_job.outputs['SaPassword.Value']] steps: + # Install the version of the dotnet runtime we will use to execute the test target. - template: /eng/pipelines/pr/steps/install-dotnet.yml@self parameters: runtimeVersion: ${{ parameters.platformDotnet }} + # Configure the local SQL Server instance - template: /eng/pipelines/pr/steps/configure-sqlserver-step.yml@self parameters: fileStreamDirectory: ${{ parameters.fileStreamDirectory }} operatingSystem: ${{ parameters.platformOperatingSystem }} - saPassword: ${{ parameters.saPassword }} - - # @TODO: Document these thingies + saPassword: ${{ variables.saPassword }} + # Assign the generated SA password to the $Password field. This will allow $(Password) to be + # be replaced in connection strings with whatever was passed in as ${{ saPassword }}. - pwsh: | - $password = "${{ parameters.saPassword }}" + $password = "${{ variables.saPassword }}" Write-Host "##vso[task.setvariable variable=Password;isSecret=true]$password" displayName: Set Connection String Password + # Write configuration information to the config.json file. - pwsh: | # Read existing default configuration from file $defaultConfigPath = "$(REPO_ROOT)/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/config.default.json" @@ -113,6 +143,7 @@ jobs: Write-Host "##vso[task.setvariable variable=TEST_MDS_CONFIG]$configPath" displayName: 'Generate manual test config' + # Execute TestSqlClientManual target from build.proj - template: /eng/pipelines/pr/steps/test-buildproj-step.yml parameters: buildConfiguration: ${{ parameters.buildConfiguration }} diff --git a/eng/pipelines/pr/pr-pipeline.yml b/eng/pipelines/pr/pr-pipeline.yml index 423653f65c..e8ed3080bd 100644 --- a/eng/pipelines/pr/pr-pipeline.yml +++ b/eng/pipelines/pr/pr-pipeline.yml @@ -32,7 +32,6 @@ stages: stageNameSecrets: ${{ variables.stageNameSecrets }} platforms: - # @TODO: Expand to cover different SQL Server targets - displayName: "windows_net462" dotnet: "net462" image: "ADO-MMS22-SQL22" diff --git a/eng/pipelines/pr/stages/generate-secrets-stage.yml b/eng/pipelines/pr/stages/generate-secrets-stage.yml index 5fef8e9165..20a81fe626 100644 --- a/eng/pipelines/pr/stages/generate-secrets-stage.yml +++ b/eng/pipelines/pr/stages/generate-secrets-stage.yml @@ -7,13 +7,13 @@ # SaPassword - A random GUID suitable for use as the SA password of local SQL Server instances. # # Subsequent stages may reference these variables as: -# $[stageDependencies.secrets_stage.secrets_job.outputs['SaPassword.Value']] +# $[stageDependencies.${{ stageName }}.secrets_job.outputs['SaPassword.Value']] # # For further details on the stage-dependency syntax, see: # https://learn.microsoft.com/en-us/azure/devops/pipelines/process/set-variables-scripts?view=azure-devops&tabs=bash#set-an-output-variable-for-use-in-future-stages # # Any stages that use these secrets must depend on this stage: -# secrets_stage +# ${{ stageName }} # # None of the values produced here are actual secrets - they are just random values that are # suitable for testing purposes, and do not need to be protected. For simplicity, they are emitted diff --git a/eng/pipelines/pr/stages/pack-stage.yml b/eng/pipelines/pr/stages/pack-stage.yml index aaf8852e42..292dbdaf07 100644 --- a/eng/pipelines/pr/stages/pack-stage.yml +++ b/eng/pipelines/pr/stages/pack-stage.yml @@ -19,15 +19,21 @@ # alphabetically is the best way to arrange for now. parameters: + + # Configuration with which to build the packages and execute the tests. - name: buildConfiguration type: string values: - Debug - Release + # Suffix to append to the package version to indicate it is a pre-release/development build. - name: buildSuffix type: string + # Name to use for the stage. This is parameterized to allow a higher level of the pipeline to + # define the name and pass it to sibling stages (ie, test stage) and avoid relying on brittle + # hard-coded stage names. - name: stageName type: string diff --git a/eng/pipelines/pr/stages/test-stages.yml b/eng/pipelines/pr/stages/test-stages.yml index b54e7f669a..4eebfa6b81 100644 --- a/eng/pipelines/pr/stages/test-stages.yml +++ b/eng/pipelines/pr/stages/test-stages.yml @@ -9,47 +9,67 @@ # confidence and expedience of validation. parameters: + # Configuration with which to build the packages and execute the tests. - name: buildConfiguration type: string values: - Debug - Release + # Suffix to append to the package version to indicate it is a pre-release/development build. - name: buildSuffix type: string + # Name of the build/pack stage that this stage will depend on. - name: stageNamePack type: string + # Name of the secret generation job used to determine the path to the SA password variable. - name: stageNameSecrets type: string # Manual Test Configuration Parameters ================================== + # Azure Key Vault tenant ID that will be set in the config.json file for sqlclient manual tests. - name: manualTestAzureKeyVaultTenantId type: string + # Azure Key Vault URL that will be set in the config.json file for sqlclient manual tests. - name: manualTestAzureKeyVaultUrl type: string + # Connection string to Azure SQL using named pipes that will be set in the config.json file for + # sqlclient manual tests against Azure SQL. - name: manualTestConnectionStringNpAzure type: string + # Connection string to localhost using named pipes that will be set in the config.json file for + # sqlclient manual tests against a local box product. - name: manualTestConnectionStringNpLocalhost type: string + # Connection string to Azure SQL using TCP that will be set in the config.json file for sqlclient + # manual tests against Azure SQL. - name: manualTestConnectionStringTcpAzure type: string + # Connection string to localhost using TCP that will be set in the config.json file for sqlclient + # manual tests against a local box product. - name: manualTestConnectionStringTcpLocalhost type: string + # Path to use for file stream tests, this value will be stored in the config.json for sqlclient + # manual tests. - name: manualTestFileStreamDirectory type: string + # Name of the local DB application name for localdb tests, this value will be stored in the + # config.json for sqlclient manual tests. - name: manualTestLocalDbAppName type: string + # Name of the local DB shared instance name for localdb tests, this value will be stored in the + # config.json for sqlclient manual tests. - name: manualTestLocalDbSharedInstanceName type: string @@ -74,11 +94,6 @@ stages: - ${{ parameters.stageNamePack }} - ${{ parameters.stageNameSecrets }} - variables: - # Bring the generated SA password from the secrets stage into scope for this test stage. - - name: manualTestSaPassword - value: $[stageDependencies.${{ parameters.stageNameSecrets }}.secrets_job.outputs['SaPassword.Value']] - jobs: # TestAbstractions - template: /eng/pipelines/pr/jobs/test-buildproj-job.yml@self @@ -122,6 +137,8 @@ stages: parameters: buildConfiguration: ${{ parameters.buildConfiguration }} buildSuffix: ${{ parameters.buildSuffix }} + stageNameSecrets: ${{ parameters.stageNameSecrets }} + platformDisplayName: ${{ platform.displayName }} platformDotnet: ${{ platform.dotnet }} platformImage: ${{ platform.image }} @@ -134,8 +151,8 @@ stages: fileStreamDirectory: ${{ parameters.manualTestFileStreamDirectory }} localDbAppName: ${{ parameters.manualTestLocalDbAppName }} localDbSharedInstanceName: ${{ parameters.manualTestLocalDbSharedInstanceName }} - saPassword: $(manualTestSaPassword) + # @TODO: # # TestSqlClientManual - Azure # - template: /eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml@self # parameters: diff --git a/eng/pipelines/pr/variables/pr-variables.yml b/eng/pipelines/pr/variables/pr-variables.yml index af77ece7c1..04c381fc85 100644 --- a/eng/pipelines/pr/variables/pr-variables.yml +++ b/eng/pipelines/pr/variables/pr-variables.yml @@ -83,7 +83,7 @@ variables: # LocalDbSharedInstanceName - group: sqlclient-testconfig-v1 - # Well-known Variables =================================================== + # General Variables ====================================================== - name: stageNamePack value: "pack_stage" From 2934a36c7bb5d8596932dbbc0becd75be18c4d7c Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Wed, 27 May 2026 12:03:18 -0500 Subject: [PATCH 40/55] Fix SA password issue. --- eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml b/eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml index 56da7d2d66..455dc8bb88 100644 --- a/eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml +++ b/eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml @@ -88,6 +88,7 @@ jobs: variables: # Bring the generated SA password from the secrets stage into scope for this test stage. + # Note: Because this is set at runtime, it must be referenced as `$(saPassword)`. - name: saPassword value: $[stageDependencies.${{ parameters.stageNameSecrets }}.secrets_job.outputs['SaPassword.Value']] @@ -102,12 +103,12 @@ jobs: parameters: fileStreamDirectory: ${{ parameters.fileStreamDirectory }} operatingSystem: ${{ parameters.platformOperatingSystem }} - saPassword: ${{ variables.saPassword }} + saPassword: $(saPassword) # Assign the generated SA password to the $Password field. This will allow $(Password) to be - # be replaced in connection strings with whatever was passed in as ${{ saPassword }}. + # be replaced in connection strings with whatever set in the secrets stage. - pwsh: | - $password = "${{ variables.saPassword }}" + $password = "$(variables.saPassword)" Write-Host "##vso[task.setvariable variable=Password;isSecret=true]$password" displayName: Set Connection String Password From 357438e1298aa11beb5a7ffa63438325febcca3c Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Wed, 27 May 2026 13:02:58 -0500 Subject: [PATCH 41/55] :hammer: --- eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml b/eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml index 455dc8bb88..2c160e6bc3 100644 --- a/eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml +++ b/eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml @@ -108,7 +108,7 @@ jobs: # Assign the generated SA password to the $Password field. This will allow $(Password) to be # be replaced in connection strings with whatever set in the secrets stage. - pwsh: | - $password = "$(variables.saPassword)" + $password = "$(saPassword)" Write-Host "##vso[task.setvariable variable=Password;isSecret=true]$password" displayName: Set Connection String Password From 27912d5e2c37371b204304dbaafa8ebd5b58ab42 Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Wed, 27 May 2026 14:22:25 -0500 Subject: [PATCH 42/55] Exclude AE ApiShould tests on debug builds. --- .../tests/ManualTests/AlwaysEncrypted/ApiShould.cs | 2 ++ .../ManualTests/DataCommon/DataTestUtility.cs | 14 ++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/ApiShould.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/ApiShould.cs index 86285e437b..620d7bd99a 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/ApiShould.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/ApiShould.cs @@ -24,6 +24,8 @@ namespace Microsoft.Data.SqlClient.ManualTesting.Tests.AlwaysEncrypted /// /// Always Encrypted public API Manual tests. /// + // @TODO: These tests are known to not run reliably in DEBUG mode. + [ConditionalClass(typeof(DataTestUtility), nameof(DataTestUtility.IsNotDebugBuild))] public sealed class ApiShould : IClassFixture, IDisposable { private SQLSetupStrategy _fixture; diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs index 623f645ddb..550d713800 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs @@ -188,6 +188,20 @@ public static string SQLServerVersion IsSqlVectorSupported && CheckVectorFloat16Supported(); + public static bool IsDebugBuild + { + get + { + #if DEBUG + return true; + #else + return false; + #endif + } + } + + public static bool IsNotDebugBuild() => IsDebugBuild; + private static bool CheckVectorFloat16Supported() { try From 3afd2166e5ca8c3061d0e291b609ce7a29dc668e Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Thu, 28 May 2026 13:17:02 -0500 Subject: [PATCH 43/55] Address copilot feedback round 1 of `n` --- eng/pipelines/pr/stages/test-stages.yml | 12 +++++++----- eng/pipelines/pr/steps/build-buildproj-step.yml | 1 + eng/pipelines/pr/steps/pack-buildproj-step.yml | 1 + eng/pipelines/pr/steps/test-buildproj-step.yml | 1 + .../config.default.json | 2 +- 5 files changed, 11 insertions(+), 6 deletions(-) diff --git a/eng/pipelines/pr/stages/test-stages.yml b/eng/pipelines/pr/stages/test-stages.yml index 4eebfa6b81..c15ea61dd0 100644 --- a/eng/pipelines/pr/stages/test-stages.yml +++ b/eng/pipelines/pr/stages/test-stages.yml @@ -74,11 +74,13 @@ parameters: type: string # This is an array of objects with the following fields: - # - displayName - Friendly name to use when displaying the stage name and job names. This must - # only contain alphanumeric characters and '_'. It will be used for both display - # name fields and stage/job names. - # - dotnet - Version of dotnet runtime to use to execute the tests - # - image - Image to use to execute the test jobs in the pipeline + # - displayName - Friendly name to use when displaying the stage name and job names. This + # must only contain alphanumeric characters and '_'. It will be used for both + # display name fields and stage/job names. + # - dotnet - Version of dotnet runtime to use to execute the tests + # - image - Image to use to execute the test jobs in the pipeline + # - operatingSystem - General OS "class" that the image contains. This is used to switch between + # server configuration behaviors. # # Each one of the objects in this parameter will become a stage that executes all test projects # available. diff --git a/eng/pipelines/pr/steps/build-buildproj-step.yml b/eng/pipelines/pr/steps/build-buildproj-step.yml index fee994a0b4..3e81edfbf4 100644 --- a/eng/pipelines/pr/steps/build-buildproj-step.yml +++ b/eng/pipelines/pr/steps/build-buildproj-step.yml @@ -39,6 +39,7 @@ steps: projects: build.proj arguments: >- -t:Build${{ parameters.packageShortName }} + -p:Configuration=${{ parameters.buildConfiguration }} -p:BuildNumber='$(Build.BuildNumber)' -p:BuildSuffix='${{ parameters.buildSuffix }}' diff --git a/eng/pipelines/pr/steps/pack-buildproj-step.yml b/eng/pipelines/pr/steps/pack-buildproj-step.yml index d3c9fd73e7..6b2980cbb4 100644 --- a/eng/pipelines/pr/steps/pack-buildproj-step.yml +++ b/eng/pipelines/pr/steps/pack-buildproj-step.yml @@ -54,5 +54,6 @@ steps: verbosity: detailed arguments: >- -t:Pack${{ parameters.packageShortName }} + -p:Configuration=${{ parameters.buildConfiguration }} -p:BuildNumber='$(Build.BuildNumber)' -p:BuildSuffix='${{ parameters.buildSuffix }}' diff --git a/eng/pipelines/pr/steps/test-buildproj-step.yml b/eng/pipelines/pr/steps/test-buildproj-step.yml index 4082af30a2..5309e7ef96 100644 --- a/eng/pipelines/pr/steps/test-buildproj-step.yml +++ b/eng/pipelines/pr/steps/test-buildproj-step.yml @@ -53,6 +53,7 @@ steps: verbosity: detailed arguments: >- -t:Test${{ parameters.packageShortName }}${{ parameters.testProject }} + -p:Configuration=${{ parameters.buildConfiguration }} -p:BuildNumber='$(Build.BuildNumber)' -p:BuildSuffix='${{ parameters.buildSuffix }}' -p:TestFramework=${{ parameters.testFramework }} diff --git a/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/config.default.json b/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/config.default.json index df602f11bf..b2200b03c0 100644 --- a/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/config.default.json +++ b/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/config.default.json @@ -36,6 +36,6 @@ "AliasName": "", "WorkloadIdentityFederationServiceConnectionId": "", "KerberosDomainPassword": "", - "KerberosDomainuser": "", + "KerberosDomainUser": "", "IsManagedInstance": false } From 6419c73865ddf600a0a2ba009aa4bb7ee8cc4fe1 Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Thu, 28 May 2026 18:49:41 -0500 Subject: [PATCH 44/55] Config.json changes applied to pipelines. --- .../common/templates/jobs/ci-run-tests-job.yml | 6 ------ .../templates/steps/update-config-file-step.yml | 11 ----------- 2 files changed, 17 deletions(-) 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 737ac0fa23..5eed840236 100644 --- a/eng/pipelines/common/templates/jobs/ci-run-tests-job.yml +++ b/eng/pipelines/common/templates/jobs/ci-run-tests-job.yml @@ -30,11 +30,9 @@ parameters: # template expansion. # # EnclaveEnabled - # IsAzureSynapse # IsDNSCachingSupportedCR # IsDNSCachingSupportedTR # ManagedIdentitySupported - # SupportsFileStream # SupportsIntegratedSecurity # TracingEnabled # @@ -279,8 +277,6 @@ jobs: AliasName: ${{ parameters.configProperties.AliasName }} ${{ if parameters.configProperties.SupportsIntegratedSecurity }}: SupportsIntegratedSecurity: ${{ eq(parameters.configProperties.SupportsIntegratedSecurity, 'true') }} - ${{ if parameters.configProperties.SupportsFileStream }}: - SupportsFileStream: ${{ eq(parameters.configProperties.SupportsFileStream, 'true') }} ${{ if parameters.configProperties.DNSCachingConnString }}: DNSCachingConnString: ${{ parameters.configProperties.DNSCachingConnString }} ${{ if parameters.configProperties.DNSCachingServerCR }}: @@ -293,8 +289,6 @@ jobs: IsDNSCachingSupportedCR: ${{ eq(parameters.configProperties.IsDNSCachingSupportedCR, 'true') }} ${{ if parameters.configProperties.IsDNSCachingSupportedTR }}: IsDNSCachingSupportedTR: ${{ eq(parameters.configProperties.IsDNSCachingSupportedTR, 'true') }} - ${{ if parameters.configProperties.IsAzureSynapse }}: - IsAzureSynapse: ${{ eq(parameters.configProperties.IsAzureSynapse, 'true') }} ${{ if parameters.configProperties.ManagedIdentitySupported }}: ManagedIdentitySupported: ${{ eq(parameters.configProperties.ManagedIdentitySupported, 'true') }} diff --git a/eng/pipelines/common/templates/steps/update-config-file-step.yml b/eng/pipelines/common/templates/steps/update-config-file-step.yml index b10abdc617..b0612fa248 100644 --- a/eng/pipelines/common/templates/steps/update-config-file-step.yml +++ b/eng/pipelines/common/templates/steps/update-config-file-step.yml @@ -93,10 +93,6 @@ parameters: type: boolean default: false - - name: SupportsFileStream - type: boolean - default: false - - name: DNSCachingConnString type: string default: '' @@ -121,10 +117,6 @@ parameters: type: boolean default: false - - name: IsAzureSynapse - type: boolean - default: false - - name: ManagedIdentitySupported type: boolean default: true @@ -188,8 +180,6 @@ steps: $p.DNSCachingConnString="${{parameters.DNSCachingConnString }}" - $p.SupportsFileStream="${{parameters.SupportsFileStream }}" - $p.LocalDbAppName="${{parameters.LocalDbAppName }}" $p.TCPConnectionStringAASSGX="${{parameters.TCPConnectionStringAASSGX }}" @@ -201,7 +191,6 @@ steps: $p.UseManagedSNIOnWindows=[System.Convert]::ToBoolean("${{parameters.UseManagedSNIOnWindows }}") $p.SupportsIntegratedSecurity=[System.Convert]::ToBoolean("${{parameters.SupportsIntegratedSecurity }}") $p.ManagedIdentitySupported=[System.Convert]::ToBoolean("${{parameters.ManagedIdentitySupported }}") - $p.IsAzureSynapse=[System.Convert]::ToBoolean("${{parameters.IsAzureSynapse }}") $p.IsDNSCachingSupportedTR=[System.Convert]::ToBoolean("${{parameters.IsDNSCachingSupportedTR }}") $p.IsDNSCachingSupportedCR=[System.Convert]::ToBoolean("${{parameters.IsDNSCachingSupportedCR }}") $p.TracingEnabled=[System.Convert]::ToBoolean("${{parameters.TracingEnabled }}") From 76a23518da98a00a2e5d17f3fe8754102752ddbf Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Thu, 28 May 2026 19:01:23 -0500 Subject: [PATCH 45/55] Restore tools in all instances before running jobs. --- eng/pipelines/pr/steps/install-dotnet.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/eng/pipelines/pr/steps/install-dotnet.yml b/eng/pipelines/pr/steps/install-dotnet.yml index d6e808e65e..43656688ce 100644 --- a/eng/pipelines/pr/steps/install-dotnet.yml +++ b/eng/pipelines/pr/steps/install-dotnet.yml @@ -20,3 +20,5 @@ steps: ${{ if not(contains(parameters.runtimeVersion, 'net4')) }}: runtimes: - "${{ replace(parameters.runtimeVersion, 'net', '') }}.x" + + - template: /eng/pipelines/common/steps/restore-dotnet-tools.yml@self From 40db7373985c6576152b8e47062ce0e91ab608cf Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Thu, 28 May 2026 19:12:09 -0500 Subject: [PATCH 46/55] Getting really tired of these changes --- eng/pipelines/pr/stages/pack-stage.yml | 4 ++-- eng/pipelines/pr/steps/install-dotnet.yml | 7 +++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/eng/pipelines/pr/stages/pack-stage.yml b/eng/pipelines/pr/stages/pack-stage.yml index 292dbdaf07..c0a135e246 100644 --- a/eng/pipelines/pr/stages/pack-stage.yml +++ b/eng/pipelines/pr/stages/pack-stage.yml @@ -50,8 +50,8 @@ stages: vmImage: 'ubuntu-latest' steps: - # Install dotnet SDK - - template: /eng/pipelines/common/steps/install-dotnet.yml@self + # Install dotnet SDK and restore tools + - template: /eng/pipelines/pr/steps/install-dotnet.yml@self # ################################################################ # Build/Pack Microsoft.Data.SqlClient diff --git a/eng/pipelines/pr/steps/install-dotnet.yml b/eng/pipelines/pr/steps/install-dotnet.yml index 43656688ce..bbd10c98d3 100644 --- a/eng/pipelines/pr/steps/install-dotnet.yml +++ b/eng/pipelines/pr/steps/install-dotnet.yml @@ -8,16 +8,19 @@ # the SDK version specified in the global.json file, and if the runtime version specified does not # begin with "net4" (ie, indicating netfx runtime is being used), the version will be passed in as # part of the runtime parameters. +# +# This version chains into the common install-dotnet step to enable the pr pipeline to call a +# single step template and get the desired behavior without complexity. parameters: - name: runtimeVersion type: string + default: '' steps: - # @TODO: Include retry - template: /eng/pipelines/common/steps/install-dotnet.yml@self parameters: - ${{ if not(contains(parameters.runtimeVersion, 'net4')) }}: + ${{ if and(not(eq(parameters.runtimeVersion, '') not(contains(parameters.runtimeVersion, 'net4'))) }}: runtimes: - "${{ replace(parameters.runtimeVersion, 'net', '') }}.x" From cf343f52785511d97bc8fd9043024027f6b22d5f Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Thu, 28 May 2026 19:13:23 -0500 Subject: [PATCH 47/55] wouldn't it be nice if we had something to verify this before pushing a bunch of tiny little changes? --- eng/pipelines/pr/steps/install-dotnet.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eng/pipelines/pr/steps/install-dotnet.yml b/eng/pipelines/pr/steps/install-dotnet.yml index bbd10c98d3..9104006490 100644 --- a/eng/pipelines/pr/steps/install-dotnet.yml +++ b/eng/pipelines/pr/steps/install-dotnet.yml @@ -20,7 +20,7 @@ parameters: steps: - template: /eng/pipelines/common/steps/install-dotnet.yml@self parameters: - ${{ if and(not(eq(parameters.runtimeVersion, '') not(contains(parameters.runtimeVersion, 'net4'))) }}: + ${{ if and(not(eq(parameters.runtimeVersion, ''), not(contains(parameters.runtimeVersion, 'net4'))) }}: runtimes: - "${{ replace(parameters.runtimeVersion, 'net', '') }}.x" From 8a36223777696d8b201bd28c3fda28169c323ee0 Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Thu, 28 May 2026 19:17:11 -0500 Subject: [PATCH 48/55] Hope it can handle extra spaces. --- eng/pipelines/pr/steps/install-dotnet.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eng/pipelines/pr/steps/install-dotnet.yml b/eng/pipelines/pr/steps/install-dotnet.yml index 9104006490..fe1c8f7878 100644 --- a/eng/pipelines/pr/steps/install-dotnet.yml +++ b/eng/pipelines/pr/steps/install-dotnet.yml @@ -20,7 +20,7 @@ parameters: steps: - template: /eng/pipelines/common/steps/install-dotnet.yml@self parameters: - ${{ if and(not(eq(parameters.runtimeVersion, ''), not(contains(parameters.runtimeVersion, 'net4'))) }}: + ${{ if and( not(eq(parameters.runtimeVersion, '' )), not(contains(parameters.runtimeVersion, 'net4')) ) }}: runtimes: - "${{ replace(parameters.runtimeVersion, 'net', '') }}.x" From e95866172685feee7a64ae24f2b55a7a52f3852b Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Thu, 28 May 2026 19:27:32 -0500 Subject: [PATCH 49/55] Fix path to dotnet arm64 installation script --- eng/pipelines/common/steps/install-dotnet.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eng/pipelines/common/steps/install-dotnet.yml b/eng/pipelines/common/steps/install-dotnet.yml index 9c1fe3b819..152ce164ef 100644 --- a/eng/pipelines/common/steps/install-dotnet.yml +++ b/eng/pipelines/common/steps/install-dotnet.yml @@ -90,7 +90,7 @@ steps: inputs: targetType: filePath pwsh: true - filePath: $(Build.SourcesDirectory)/eng/pipelines/steps/install-dotnet-arm64.ps1 + filePath: $(Build.SourcesDirectory)/eng/pipelines/common/steps/install-dotnet-arm64.ps1 # Arguments: # # -Debug: From fb19a9162c14ff38e14eeb7e5b2051bad43a1a4f Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Thu, 28 May 2026 19:46:23 -0500 Subject: [PATCH 50/55] Remove reference to ADO Test Configuration Properties variable group. --- eng/pipelines/pr/variables/pr-variables.yml | 62 --------------------- 1 file changed, 62 deletions(-) diff --git a/eng/pipelines/pr/variables/pr-variables.yml b/eng/pipelines/pr/variables/pr-variables.yml index 04c381fc85..1e63c3e124 100644 --- a/eng/pipelines/pr/variables/pr-variables.yml +++ b/eng/pipelines/pr/variables/pr-variables.yml @@ -9,68 +9,6 @@ variables: # Libraries ============================================================== - # These variables are used to construct the config file for manual tests. - # - # AAD_PASSWORD_CONN_STR - # AAD_PASSWORD_CONN_STR_eastus - # AADAuthorityURL - # AADServicePrincipalId - # AADServicePrincipalSecret - # AZURE_DB_NP_CONN_STRING - # AZURE_DB_NP_CONN_STRING_eastus - # AZURE_DB_TCP_CONN_STRING - # AZURE_DB_TCP_CONN_STRING_eastus - # AZURE_DW_NP_CONN_STRING - # AZURE_DW_TCP_CONN_STRING - # Azure_Password - # Azure_SQL_Server_eastus - # Azure_SQL_Server_westus2 - # AZURE_USERNAME - # AzureKeyVaultTenantId - # AzureKeyVaultUrl - # AzureKeyVaultUrl_EastUS - # Database - # Enclave_Password - # EnclaveEnabled - # Encrypt - # EncryptOptions - # FileStreamDirectory - # LocalDbAppName - # LocalDbSharedInstanceName - # MI_Password - # MI_User - # NamedInstance - # Password - # saUser - # SQL_MI_NP_CONN_STRING - # SQL_MI_TCP_CONN_STRING - # SQL_NP_CONN_STRING - # SQL_NP_CONN_STRING_ENCRYPTED - # SQL_TCP_CONN_STRING - # SQL_TCP_CONN_STRING_AASSGX - # SQL_TCP_CONN_STRING_AASVBS - # SQL_TCP_CONN_STRING_ENCRYPTED - # SQL_TCP_CONN_STRING_ENCRYPTED_UNIX - # SQL_TCP_CONN_STRING_HGSVBS - # SQL_TCP_CONN_STRING_NoneVBS - # SQL_TCP_CONN_STRING_TDS8_Strict_HNIC - # SQL_TCP_INSTANCE_CONN_STRING - # SQL16RootPath - # SQL17RootPath - # SQL19-SGX - # SQL19-VBS - # SQL19RootPath - # SQL22RootPath - # SupportsIntegratedSecurity - # UseManagedSNIOnWindows - # user - # UserManagedIdentityClientId - # UserManagedIdentityClientId_eastus - # UserManagedIdentityObjectId - # UsermanagedIdentityObjectId_eastus - # WorkloadIdentityFederationServiceConnectionId - - group: ADO Test Configuration Properties - # These variables are used to construct the config file for manual tests. # # AzureKeyVaultTenantId From 6354712b96164db9cff1b0622abb287f939400d1 Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Thu, 28 May 2026 20:03:47 -0500 Subject: [PATCH 51/55] Parameterize the pool --- eng/pipelines/pr/jobs/test-buildproj-job.yml | 8 ++++++-- eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml | 8 ++++++-- eng/pipelines/pr/pr-pipeline.yml | 7 +++++++ eng/pipelines/pr/stages/test-stages.yml | 10 ++++++++++ eng/pipelines/pr/variables/pr-variables.yml | 1 + 5 files changed, 30 insertions(+), 4 deletions(-) diff --git a/eng/pipelines/pr/jobs/test-buildproj-job.yml b/eng/pipelines/pr/jobs/test-buildproj-job.yml index 520475c33e..0b051bf50e 100644 --- a/eng/pipelines/pr/jobs/test-buildproj-job.yml +++ b/eng/pipelines/pr/jobs/test-buildproj-job.yml @@ -29,10 +29,14 @@ parameters: - name: platformDotnet type: string - # Name of the image in the ADO-1ES-Pool to use to execute this job. + # Name of the image in the customized ADO pool to use to execute this job. - name: platformImage type: string + # Name of the pool to use for jobs that require customized VM images. + - name: poolName + type: string + # Test Parameters ======================================================== # Name of the project to run tests for. This will be used to generate the build.proj target to @@ -64,7 +68,7 @@ jobs: displayName: "${{ parameters.testDisplayName }}_${{ parameters.platformDisplayName }}" pool: - name: ADO-1ES-Pool + name: ${{ parameters.poolName }} demands: - imageOverride -equals ${{ parameters.platformImage }} diff --git a/eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml b/eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml index 2c160e6bc3..ff81d983a3 100644 --- a/eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml +++ b/eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml @@ -31,7 +31,7 @@ parameters: - name: platformDotnet type: string - # Name of the image in the ADO-1ES-Pool to use to execute this job. + # Name of the image in the customized ADO pool to use to execute this job. - name: platformImage type: string @@ -45,6 +45,10 @@ parameters: - Windows - Linux + # Name of the pool to use for jobs that require customized VM images. + - name: poolName + type: string + # Test Configuration Parameters ========================================== # Azure Key Vault tenant ID that will be set in the config.json file. @@ -82,7 +86,7 @@ jobs: displayName: "sqlclient_manual_${{ parameters.platformDisplayName }}" pool: - name: ADO-1ES-Pool + name: ${{ parameters.poolName }} demands: - imageOverride -equals ${{ parameters.platformImage }} diff --git a/eng/pipelines/pr/pr-pipeline.yml b/eng/pipelines/pr/pr-pipeline.yml index e8ed3080bd..ec1cfd966a 100644 --- a/eng/pipelines/pr/pr-pipeline.yml +++ b/eng/pipelines/pr/pr-pipeline.yml @@ -6,6 +6,12 @@ name: $(DayOfYear)$(Rev:rr) +parameters: + # Name of the pool to use for jobs that require customized VM images. + - name: poolName + type: string + default: $(PoolNameDefault) + variables: - template: /eng/pipelines/common/variables/common-variables.yml@self - template: /eng/pipelines/pr/variables/pr-variables.yml@self @@ -28,6 +34,7 @@ stages: parameters: buildConfiguration: Debug buildSuffix: pr + poolName: ${{ parameters.poolName }} stageNamePack: ${{ variables.stageNamePack }} stageNameSecrets: ${{ variables.stageNameSecrets }} diff --git a/eng/pipelines/pr/stages/test-stages.yml b/eng/pipelines/pr/stages/test-stages.yml index c15ea61dd0..f2ffbc09cf 100644 --- a/eng/pipelines/pr/stages/test-stages.yml +++ b/eng/pipelines/pr/stages/test-stages.yml @@ -28,6 +28,10 @@ parameters: - name: stageNameSecrets type: string + # Name of the pool to use for jobs that require customized VM images. + - name: poolName + type: string + # Manual Test Configuration Parameters ================================== # Azure Key Vault tenant ID that will be set in the config.json file for sqlclient manual tests. @@ -105,6 +109,7 @@ stages: platformDisplayName: ${{ platform.displayName }} platformDotnet: ${{ platform.dotnet }} platformImage: ${{ platform.image }} + poolName: ${{ parameters.poolName }} packageShortName: "Abstractions" testDisplayName: "abstractions" @@ -117,6 +122,7 @@ stages: platformDisplayName: ${{ platform.displayName }} platformDotnet: ${{ platform.dotnet }} platformImage: ${{ platform.image }} + poolName: ${{ parameters.poolName }} packageShortName: "Azure" testDisplayName: "azure" @@ -129,6 +135,7 @@ stages: platformDisplayName: ${{ platform.displayName }} platformDotnet: ${{ platform.dotnet }} platformImage: ${{ platform.image }} + poolName: ${{ parameters.poolName }} packageShortName: "SqlClient" testDisplayName: "sqlclient_functional" @@ -145,6 +152,7 @@ stages: platformDotnet: ${{ platform.dotnet }} platformImage: ${{ platform.image }} platformOperatingSystem: ${{ platform.operatingSystem }} + poolName: ${{ parameters.poolName }} azureKeyVaultTenantId: ${{ parameters.manualTestAzureKeyVaultTenantId }} azureKeyVaultUrl: ${{ parameters.manualTestAzureKeyVaultUrl }} @@ -163,6 +171,7 @@ stages: # platformDisplayName: ${{ platform.displayName }} # platformDotnet: ${{ platform.dotnet }} # platformImage: ${{ platform.image }} +# poolName: ${{ parameters.poolName }} # # azureKeyVaultTenantId: ${{ parameters.manualTestAzureKeyVaultTenantId }} # azureKeyVaultUrl: ${{ parameters.manualTestAzureKeyVaultUrl }} @@ -181,6 +190,7 @@ stages: platformDisplayName: ${{ platform.displayName }} platformDotnet: ${{ platform.dotnet }} platformImage: ${{ platform.image }} + poolName: ${{ parameters.poolName }} packageShortName: "SqlClient" testDisplayName: "sqlclient_unit" diff --git a/eng/pipelines/pr/variables/pr-variables.yml b/eng/pipelines/pr/variables/pr-variables.yml index 1e63c3e124..4a28253dc7 100644 --- a/eng/pipelines/pr/variables/pr-variables.yml +++ b/eng/pipelines/pr/variables/pr-variables.yml @@ -19,6 +19,7 @@ variables: # ConnectionStringTcp_LocalhostDefault_UsernamePassword # LocalDbAppName # LocalDbSharedInstanceName + # PoolNameDefault - group: sqlclient-testconfig-v1 # General Variables ====================================================== From 4a034e1b61bf96cf41706bb572e723239782a208 Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Thu, 28 May 2026 20:07:59 -0500 Subject: [PATCH 52/55] It's not a pipeline parameter you stupid :robot: --- eng/pipelines/pr/pr-pipeline.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/eng/pipelines/pr/pr-pipeline.yml b/eng/pipelines/pr/pr-pipeline.yml index ec1cfd966a..b84d88547f 100644 --- a/eng/pipelines/pr/pr-pipeline.yml +++ b/eng/pipelines/pr/pr-pipeline.yml @@ -6,12 +6,6 @@ name: $(DayOfYear)$(Rev:rr) -parameters: - # Name of the pool to use for jobs that require customized VM images. - - name: poolName - type: string - default: $(PoolNameDefault) - variables: - template: /eng/pipelines/common/variables/common-variables.yml@self - template: /eng/pipelines/pr/variables/pr-variables.yml@self From 675a824face211a8bbd4e06a332931722a6a5fda Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Thu, 28 May 2026 20:11:18 -0500 Subject: [PATCH 53/55] :rage: --- eng/pipelines/pr/pr-pipeline.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eng/pipelines/pr/pr-pipeline.yml b/eng/pipelines/pr/pr-pipeline.yml index b84d88547f..9774ebdbfa 100644 --- a/eng/pipelines/pr/pr-pipeline.yml +++ b/eng/pipelines/pr/pr-pipeline.yml @@ -28,7 +28,7 @@ stages: parameters: buildConfiguration: Debug buildSuffix: pr - poolName: ${{ parameters.poolName }} + poolName: $(PoolNameDefault) stageNamePack: ${{ variables.stageNamePack }} stageNameSecrets: ${{ variables.stageNameSecrets }} From ca6a6c2bc891368fd0fd99764f078a2c95baa1f4 Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Fri, 29 May 2026 11:32:32 -0500 Subject: [PATCH 54/55] INVERSION --- .../tests/ManualTests/DataCommon/DataTestUtility.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs index 550d713800..9bf1c0f519 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs @@ -200,7 +200,7 @@ public static bool IsDebugBuild } } - public static bool IsNotDebugBuild() => IsDebugBuild; + public static bool IsNotDebugBuild() => !IsDebugBuild; private static bool CheckVectorFloat16Supported() { From 218eb35ddd56bacc93f285cea1e588eff3db593c Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Fri, 29 May 2026 12:36:56 -0500 Subject: [PATCH 55/55] Fix kerberos pipeline install-dotnet.yml path --- eng/pipelines/kerberos/sqlclient-kerberos.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/eng/pipelines/kerberos/sqlclient-kerberos.yml b/eng/pipelines/kerberos/sqlclient-kerberos.yml index 57325dc3a7..f43ee0a280 100644 --- a/eng/pipelines/kerberos/sqlclient-kerberos.yml +++ b/eng/pipelines/kerberos/sqlclient-kerberos.yml @@ -127,7 +127,7 @@ stages: fetchDepth: 1 fetchTags: false - - template: /eng/pipelines/steps/install-dotnet.yml@self + - template: /eng/pipelines/common/steps/install-dotnet.yml@self parameters: runtimes: [8.x, 9.x] @@ -224,7 +224,7 @@ stages: fetchTags: false # --- Install .NET SDK and runtimes --- - - template: /eng/pipelines/steps/install-dotnet.yml@self + - template: /eng/pipelines/common/steps/install-dotnet.yml@self parameters: runtimes: [8.x, 9.x]