Skip to content

Pipelines | Move CI and PR jobs off Microsoft-hosted agents - #4515

Open
cheenamalhotra wants to merge 14 commits into
dev/automation/ci-net10-coveragefrom
dev/automation/ci-retire-hosted-agents
Open

Pipelines | Move CI and PR jobs off Microsoft-hosted agents#4515
cheenamalhotra wants to merge 14 commits into
dev/automation/ci-net10-coveragefrom
dev/automation/ci-retire-hosted-agents

Conversation

@cheenamalhotra

@cheenamalhotra cheenamalhotra commented Aug 7, 2026

Copy link
Copy Markdown
Member

Stacked PR 3 of 3. Targets dev/automation/ci-net10-coverage (#4514) - review #4513 and #4514 first.

Summary

Every job that previously ran on the Microsoft-hosted Azure Pipelines pool now runs on our 1ES pools. The sole exception is macOS, since our 1ES pools do not offer macOS images.

  • Parameterize the pool name and image for the secrets, pack, verify-nuget, and code-coverage jobs in both the CI and PR pipelines, defaulting to the 1ES pool with ADO-UB24-SQL25 (or ADO-MMS25-SQL25 for verify-nuget, which needs Windows).
  • Point the Abstractions package Linux and Windows test jobs at ADO-UB24-SQL25 and ADO-MMS25-SQL25.
  • Drop the redundant hosted Linux and Windows Azure package test jobs. The self-hosted integration jobs already cover the same runtimes, and additionally exercise a local SQL Server, so the hosted jobs were pure duplication. pack_azure_package_job dependencies were trimmed accordingly.
  • Pass explicit pool names from the stress and Kerberos pipelines. Those pipelines reuse these shared templates but import neither ci-build-variables.yml nor sqlclient-testconfig-v1, so the default pool variables are not defined there.
  • Move the CI package pipeline off ADO-UB24 / ADO-Win25 and onto ADO-UB24-SQL25 / ADO-MMS25-SQL25.
  • Move the GitHub sync pipeline off the hosted ubuntu-latest image and onto ADO-UB24-SQL25, using the same internal/public conditional pool convention as the other pipelines. pwsh is available natively on that image, so no install step is needed.
  • Support both pool types in every template that now takes poolName / vmImage. Selecting the image with a 1ES imageOverride demand unconditionally would break any caller still pointing at the hosted Azure Pipelines pool, which requires vmImage instead. These templates now use the same conditional pool block the test-* job templates already use.

Remaining hosted usage

Intentionally retained, all macOS:

  • dotnet-sqlclient-ci-core.yml - macOS test configuration
  • stages/build-azure-package-ci-stage.yml - macOS Azure package job
  • stages/build-abstractions-package-ci-stage.yml - macOS abstractions job
  • ci/stress/sqlclient-ci-stress-stage.yml - macOS stress job

There is no remaining non-macOS use of a Microsoft-hosted image in eng/pipelines.

Action required before merge

ADO-MMS25-SQL25 and ADO-UB24-SQL25 must be available in both ADO-1ES-Pool and ADO-CI-1ES-Pool, since the package and GitHub sync pipelines select the pool based on the project they run in.

Checklist

  • Tests added or updated - n/a, pipeline-only change
  • Public API changes documented - n/a
  • Verified against customer repro - n/a
  • Ensure no breaking changes introduced - no product code touched; note the two dropped duplicate Azure package jobs above

All modified YAML files parse cleanly. These changes have not yet been executed against Azure DevOps. Capacity planning note: this shifts load onto the 1ES pools, so agent allocation should be reviewed before merge.

Copilot AI lite review requested due to automatic review settings August 7, 2026 22:57
@cheenamalhotra
cheenamalhotra requested a review from a team as a code owner August 7, 2026 22:57
@github-project-automation github-project-automation Bot moved this to To triage in SqlClient Board Aug 7, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR completes the hosted-agent retirement work for the Azure DevOps CI/PR YAML by moving previously Microsoft-hosted jobs onto 1ES pools (except macOS), parameterizing pool/image selection across shared templates, and removing redundant hosted Azure package test jobs that duplicated integration coverage.

Changes:

  • Parameterized poolName/vmImage for multiple CI/PR stages and jobs, switching selection to 1ES-style imageOverride demands.
  • Removed redundant hosted Linux/Windows Azure package test jobs and trimmed downstream dependsOn accordingly.
  • Passed explicit pool names into stress and Kerberos pipelines that reuse templates without importing the default CI variable groups.

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
eng/pipelines/stages/verify-nuget-packages-ci-stage.yml Parameterizes pool/image and moves verify job to 1ES pool selection.
eng/pipelines/stages/generate-secrets-ci-stage.yml Parameterizes pool/image and moves secrets job to 1ES pool selection.
eng/pipelines/stages/build-azure-package-ci-stage.yml Removes redundant hosted Azure test jobs; keeps macOS hosted; trims pack dependencies.
eng/pipelines/stages/build-abstractions-package-ci-stage.yml Routes Linux/Windows abstractions tests to 1ES images; keeps macOS hosted.
eng/pipelines/pr/stages/pack-stage.yml Parameterizes pool/image and moves PR pack stage onto 1ES pool selection.
eng/pipelines/pr/stages/generate-secrets-stage.yml Parameterizes pool/image and moves PR secrets stage onto 1ES pool selection.
eng/pipelines/pr/stages/collect-coverage-stage.yml Parameterizes pool/image and moves PR coverage stage onto 1ES pool selection.
eng/pipelines/jobs/pack-sqlserver-package-ci-job.yml Parameterizes pool/image and moves SqlServer pack job onto 1ES pool selection.
eng/pipelines/jobs/pack-logging-package-ci-job.yml Parameterizes pool/image and moves Logging pack job onto 1ES pool selection.
eng/pipelines/jobs/pack-azure-package-ci-job.yml Parameterizes pool/image and moves Azure pack job onto 1ES pool selection.
eng/pipelines/jobs/pack-abstractions-package-ci-job.yml Parameterizes pool/image and moves Abstractions pack job onto 1ES pool selection.
eng/pipelines/common/templates/jobs/ci-code-coverage-job.yml Parameterizes pool/image and moves coverage publish job onto 1ES pool selection.
eng/pipelines/ci/stress/sqlclient-ci-stress-pipeline.yml Explicitly passes poolName/vmImage for secrets stage (no CI vars imported).
eng/pipelines/ci/kerberos/sqlclient-ci-kerberos-pipeline.yml Explicitly passes poolName/vmImage for code coverage job (no CI vars imported).

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread eng/pipelines/stages/verify-nuget-packages-ci-stage.yml
Comment thread eng/pipelines/stages/generate-secrets-ci-stage.yml Outdated
Comment thread eng/pipelines/common/templates/jobs/ci-code-coverage-job.yml
Comment thread eng/pipelines/jobs/pack-sqlserver-package-ci-job.yml
Comment thread eng/pipelines/jobs/pack-logging-package-ci-job.yml
Comment thread eng/pipelines/jobs/pack-azure-package-ci-job.yml
Comment thread eng/pipelines/jobs/pack-abstractions-package-ci-job.yml
Comment thread eng/pipelines/pr/stages/pack-stage.yml
Comment thread eng/pipelines/pr/stages/collect-coverage-stage.yml
Comment thread eng/pipelines/pr/stages/generate-secrets-stage.yml Outdated
@cheenamalhotra
cheenamalhotra marked this pull request as draft August 7, 2026 23:18
Copilot AI review requested due to automatic review settings August 8, 2026 04:11
@cheenamalhotra
cheenamalhotra force-pushed the dev/automation/ci-retire-hosted-agents branch from b75fd7d to 8fb349a Compare August 8, 2026 04:13

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 15 out of 15 changed files in this pull request and generated no new comments.

Copilot AI review requested due to automatic review settings August 8, 2026 04:16

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 15 out of 15 changed files in this pull request and generated no new comments.

Suppressed comments (2)

eng/pipelines/stages/generate-secrets-ci-stage.yml:60

  • The comment says “any Linux image … will do”, but this job is actually pinned to a specific image via the imageOverride demand (defaulting to ADO-UB24-SQL25). This can confuse future edits (e.g., someone might remove/alter the demand thinking it’s unnecessary). Update the comment to clarify that the job only requires a Linux agent, but is still selecting a specific pool image via vmImage/imageOverride.
        pool:
          # We don't need anything special, so any Linux image in our 1ES pool
          # will do.

eng/pipelines/pr/stages/generate-secrets-stage.yml:60

  • The comment says “any Linux image … will do”, but this job is actually pinned to a specific image via the imageOverride demand (defaulting to ADO-UB24-SQL25). Update the comment to make it clear the job requires Linux but still selects an explicit pool image via vmImage/imageOverride, to avoid confusion when someone changes pool settings later.
        pool:
          # We don't need anything special, so any Linux image in our 1ES pool
          # will do.

Copilot AI review requested due to automatic review settings August 8, 2026 06:04

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 16 out of 16 changed files in this pull request and generated no new comments.

Suppressed comments (1)

eng/pipelines/github-sync-pipeline.yml:67

  • PR description states eng/pipelines/github-sync-pipeline.yml is "out of scope and untouched" and still uses a hosted image, but this PR changes the job pool to 1ES with an imageOverride demand. Please reconcile this by either updating the PR description (if the change is intended) or reverting this pool change (if it’s truly out of scope).
    # This pipeline only ever runs in the ADO.Net project, but the pool is
    # selected conditionally to match the convention used by the other
    # pipelines in this repo.
    pool:
      ${{ if eq(variables['System.TeamProject'], 'ADO.Net') }}:

Copilot AI review requested due to automatic review settings August 8, 2026 06:49
@cheenamalhotra
cheenamalhotra force-pushed the dev/automation/ci-retire-hosted-agents branch from 22e6b04 to 1aa857c Compare August 8, 2026 06:49
@cheenamalhotra

Copy link
Copy Markdown
Member Author

Also addressing the two suppressed comments from the earlier review passes:

  • generate-secrets-ci-stage.yml:60 / generate-secrets-stage.yml:60 - the "any Linux image in our 1ES pool will do" comments were misleading now that the job pins an image. Reworded in 1aa857c3a to state that the job has no special image requirements, defaults to Linux, and is repointable by the caller via the poolName/vmImage parameters.
  • github-sync-pipeline.yml:67 - correctly flagged as contradicting the PR description. The pool change is intended (it was the last non-macOS hosted image left in eng/pipelines), so I updated the PR description rather than reverting.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 16 out of 16 changed files in this pull request and generated no new comments.

Suppressed comments (1)

eng/pipelines/github-sync-pipeline.yml:67

  • PR description says eng/pipelines/github-sync-pipeline.yml is “out of scope and untouched” and still uses a hosted image, but this diff switches it to 1ES pools with an imageOverride demand. Please either update the PR description to include this pipeline in scope, or revert this file change to keep the stated “remaining hosted usage” accurate.
    # This pipeline only ever runs in the ADO.Net project, but the pool is
    # selected conditionally to match the convention used by the other
    # pipelines in this repo.
    pool:
      ${{ if eq(variables['System.TeamProject'], 'ADO.Net') }}:

@paulmedynski paulmedynski left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a good step to having consistent pool and image selection for our pipline jobs, and getting us off the generic Azure Pipelines pool except for macOS.

I would like to see us using the minimal image wherever possible to save time and resources - i.e. only use an image with a SQL Server if we're running integration tests that need it. Jobs that build, pack, run unit/functional tests, or use a remote SQL Server don't need a local SQL Server. We also don't need the large MMS tooling (that includes Visual Studio and a bunch of other stuff) for most (all?) of our jobs. I realize that some of our SQL Server images are currently based on MMS, so for now we can't avoid it with the local integration jobs.

We currently have ADO-Win25 and ADO-UB24 in both 1ES pools, and those can be used for these legacy pipeline non-integration jobs. The nascent 1ES Pipeline Plan will have us creating new images to meet our new PR/CI pipeline needs, and we can use those in the new pipelines once they are created. I don't expect ADO-Win25 and ADO-UB24 to survive that transition.

I'm also wondering if we really need the pool and image names to be configurable. Do we plan to change either regularly? Would it be sufficient to put the pool name selection in a common template and expose it as a static variable that can be used as ${{ variables.poolName }} at template-expansion time? The image names are essentially hardcoded already anyway, so that's fine.

Comment thread eng/pipelines/ci/kerberos/sqlclient-ci-kerberos-pipeline.yml Outdated
Comment thread eng/pipelines/ci/package/sqlclient-ci-package-pipeline.yml Outdated
Comment thread eng/pipelines/common/templates/jobs/ci-code-coverage-job.yml Outdated
Comment thread eng/pipelines/common/templates/jobs/ci-code-coverage-job.yml Outdated
Comment thread eng/pipelines/jobs/pack-abstractions-package-ci-job.yml Outdated
@github-project-automation github-project-automation Bot moved this from To triage to Waiting for customer in SqlClient Board Aug 8, 2026
Copilot AI review requested due to automatic review settings August 10, 2026 17:01
@cheenamalhotra
cheenamalhotra force-pushed the dev/automation/ci-retire-hosted-agents branch from 1aa857c to 0d48a08 Compare August 10, 2026 17:01

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 16 out of 16 changed files in this pull request and generated no new comments.

Suppressed comments (10)

eng/pipelines/stages/verify-nuget-packages-ci-stage.yml:77

  • The ${{ if eq(parameters.poolName, 'Azure Pipelines') }} branch is evaluated at template-expansion time. If poolName is provided via a runtime macro (e.g. the default $(ci_var_defaultPoolName)), this comparison will never match, so the job will still take the 1ES demands: imageOverride path even when the variable resolves to Azure Pipelines at runtime (hosted agents), causing the job to fail.
          ${{ if eq(parameters.poolName, 'Azure Pipelines') }}:
            vmImage: ${{ parameters.vmImage }}
          # Images provided by 1ES must be selected using a demand.
          ${{ else }}:
            demands:

eng/pipelines/stages/generate-secrets-ci-stage.yml:69

  • This pool-type switch uses a compile-time condition (${{ if eq(parameters.poolName, 'Azure Pipelines') }}), but the default poolName is the runtime macro $(ci_var_defaultPoolName). If that macro ever resolves to Azure Pipelines at runtime, the condition still won’t match and the job will incorrectly use the 1ES imageOverride demand on a hosted pool.
          ${{ if eq(parameters.poolName, 'Azure Pipelines') }}:
            vmImage: ${{ parameters.vmImage }}
          # Images provided by 1ES must be selected using a demand.
          ${{ else }}:
            demands:

eng/pipelines/common/templates/jobs/ci-code-coverage-job.yml:46

  • The hosted-vs-1ES pool selection relies on ${{ if eq(parameters.poolName, 'Azure Pipelines') }}, which is evaluated during template expansion. Because the default poolName is $(ci_var_defaultPoolName) (a runtime macro), this condition can’t detect a hosted pool chosen via that variable and will still emit the 1ES imageOverride demands block.
      ${{ if eq(parameters.poolName, 'Azure Pipelines') }}:
        vmImage: ${{ parameters.vmImage }}
      # Images provided by 1ES must be selected using a demand.
      ${{ else }}:
        demands:

eng/pipelines/jobs/pack-sqlserver-package-ci-job.yml:79

  • The condition ${{ if eq(parameters.poolName, 'Azure Pipelines') }} is compile-time, but poolName defaults to the runtime macro $(ci_var_defaultPoolName). If that macro resolves to Azure Pipelines (hosted) at runtime, this template will still take the demands: imageOverride branch and fail on hosted agents.
      ${{ if eq(parameters.poolName, 'Azure Pipelines') }}:
        vmImage: ${{ parameters.vmImage }}
      # Images provided by 1ES must be selected using a demand.
      ${{ else }}:
        demands:

eng/pipelines/jobs/pack-logging-package-ci-job.yml:83

  • Because ${{ if eq(parameters.poolName, 'Azure Pipelines') }} is evaluated at template-expansion time, it can’t see the resolved value of the default runtime macro $(ci_var_defaultPoolName). If that variable ever points to the hosted Azure Pipelines pool, the template will still emit the 1ES imageOverride demands branch and the job will fail.
      ${{ if eq(parameters.poolName, 'Azure Pipelines') }}:
        vmImage: ${{ parameters.vmImage }}
      # Images provided by 1ES must be selected using a demand.
      ${{ else }}:
        demands:

eng/pipelines/jobs/pack-azure-package-ci-job.yml:119

  • This template’s hosted-vs-1ES branching is compile-time (${{ if eq(parameters.poolName, 'Azure Pipelines') }}), but the default pool name is the runtime macro $(ci_var_defaultPoolName). If that macro resolves to Azure Pipelines at runtime, the hosted branch will not be selected and the job will still run with 1ES imageOverride demands, which hosted agents don’t satisfy.
      ${{ if eq(parameters.poolName, 'Azure Pipelines') }}:
        vmImage: ${{ parameters.vmImage }}
      # Images provided by 1ES must be selected using a demand.
      ${{ else }}:
        demands:

eng/pipelines/jobs/pack-abstractions-package-ci-job.yml:107

  • The ${{ if eq(parameters.poolName, 'Azure Pipelines') }} check is evaluated during template expansion, but the default poolName is $(ci_var_defaultPoolName) (runtime). If that macro ever resolves to Azure Pipelines, this template will still emit the 1ES imageOverride demands branch and fail when run on hosted agents.
      ${{ if eq(parameters.poolName, 'Azure Pipelines') }}:
        vmImage: ${{ parameters.vmImage }}
      # Images provided by 1ES must be selected using a demand.
      ${{ else }}:
        demands:

eng/pipelines/pr/stages/pack-stage.yml:73

  • The pool-type switch uses a compile-time template expression (${{ if eq(parameters.poolName, 'Azure Pipelines') }}), but poolName defaults to $(PoolNameDefault) (runtime macro from a variable group). If PoolNameDefault resolves to Azure Pipelines, this condition still won’t match and the stage will incorrectly use the 1ES imageOverride demands path, failing on hosted agents.
          ${{ if eq(parameters.poolName, 'Azure Pipelines') }}:
            vmImage: ${{ parameters.vmImage }}
          # Images provided by 1ES must be selected using a demand.
          ${{ else }}:
            demands:

eng/pipelines/pr/stages/generate-secrets-stage.yml:69

  • ${{ if eq(parameters.poolName, 'Azure Pipelines') }} is evaluated at template-expansion time, so it can’t detect that the runtime macro $(PoolNameDefault) resolved to Azure Pipelines at runtime. In that scenario the 1ES imageOverride demand branch will still be emitted and the hosted job will fail.
          ${{ if eq(parameters.poolName, 'Azure Pipelines') }}:
            vmImage: ${{ parameters.vmImage }}
          # Images provided by 1ES must be selected using a demand.
          ${{ else }}:
            demands:

eng/pipelines/pr/stages/collect-coverage-stage.yml:47

  • The branch between hosted (vmImage) and 1ES (demands: imageOverride) is compile-time (${{ if eq(parameters.poolName, 'Azure Pipelines') }}), but the default pool name is the runtime macro $(PoolNameDefault). If the variable group sets PoolNameDefault to Azure Pipelines, the condition will still not match and this stage will emit the 1ES demands block, which will fail on hosted agents.
          ${{ if eq(parameters.poolName, 'Azure Pipelines') }}:
            vmImage: ${{ parameters.vmImage }}
          # Images provided by 1ES must be selected using a demand.
          ${{ else }}:
            demands:

cheenamalhotra and others added 2 commits August 13, 2026 22:50
This was the last job outside of macOS still running on a
Microsoft-hosted agent.  Move it to ADO-UB24-SQL25 on the 1ES pool,
selecting the pool based on the project the way the stress and package
pipelines do.

The job runs a PowerShell script with pwsh, which the ADO-UB24-SQL25
image already provides -- the stress job relies on the same thing
without installing PowerShell first.

After this change, the only remaining Microsoft-hosted jobs are the
macOS ones, since our 1ES pools do not offer macOS images.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 10246002-c950-42a7-adf5-1698f9af4b3d
The pack, secrets, coverage and NuGet verification templates now take
poolName/vmImage parameters, but selected the image with a 1ES imageOverride
demand unconditionally.  That breaks if a caller (or a variable group that has
not been migrated yet) still points poolName at the hosted 'Azure Pipelines'
pool, which requires vmImage instead.

Use the same conditional pool block the test-* job templates already use, so
these templates work with either pool type.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 10246002-c950-42a7-adf5-1698f9af4b3d
Copilot AI review requested due to automatic review settings August 14, 2026 05:50
@cheenamalhotra
cheenamalhotra force-pushed the dev/automation/ci-retire-hosted-agents branch from 0d48a08 to 410e337 Compare August 14, 2026 05:50

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 16 out of 16 changed files in this pull request and generated no new comments.

cheenamalhotra and others added 4 commits August 20, 2026 13:20
Retire every SQL Server 2022 agent image in favour of the SQL Server 2025
equivalents:

  ADO-MMS22-SQL22 -> ADO-MMS25-SQL25
  ADO-UB22-SQL22  -> ADO-UB24-SQL25

This covers the CI test configurations, the PR pipeline platform list,
the Azure package integration test jobs (including the SQL root path,
which becomes SQL25RootPath), the Managed Instance jobs, the stress test
jobs, and the Linux enclave configuration.

Two notes on the change:

  - CI test stage names derive from the image keys, so stages such as
    Win22_Sql22 are now named Win25_Sql25.  Any branch policies or
    required status checks that reference the old stage names will need
    to be updated.

  - The Linux SQL configuration previously ran on both ADO-UB20-SQL22
    and ADO-UB22-SQL22.  We only have a single Ubuntu SQL 2025 image, so
    it now runs on ADO-UB24-SQL25 alone.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 10246002-c950-42a7-adf5-1698f9af4b3d
The Linux enclave image key doubles as the generated ADO stage name and is
referenced by branch policies and required status checks, so it is kept as-is.
The 'Sql19' suffix also remains accurate because these tests target a remote
Enclave-enabled SQL Server 2019; only the agent image moved to Ubuntu 24.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 10246002-c950-42a7-adf5-1698f9af4b3d
The SQL Server 2025 agent images ship the engine but not the command line
tools, so the Linux SQL configuration steps failed with:

  ERROR: 'sqlcmd' was not found on PATH or in the standard mssql-tools locations.

Add a shared 'Install sqlcmd [Linux]' step that reuses an existing sqlcmd when
the image provides one and otherwise installs mssql-tools18, then publishes the
resolved path via the SqlCmdBin variable.  Both the PR and CI Linux
configuration steps now run it, and the CI step no longer hardcodes
/opt/mssql-tools/bin/sqlcmd, which does not exist on these images.

sqlcmd from mssql-tools18 encrypts by default, so the step also publishes
SqlCmdTrustArg ('-C') to trust the local server's self-signed certificate.
Without it every connection to localhost would fail certificate validation.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 10246002-c950-42a7-adf5-1698f9af4b3d
Introduce primaryTargetFrameworks and primaryTargetFrameworksUnix, which
apply only to the primary test configurations: local SQL Server 2025 and
Azure SQL, on both Windows and Linux.  Those configurations now run
net10.0 in addition to the existing target frameworks.

Restricting .NET 10 to the primary configurations keeps the added agent
cost bounded rather than multiplying it across every legacy SQL Server
image.  The other pipelines that extend the CI core pin the new
parameters to their existing target framework lists, so their behaviour
is unchanged.

Note that the driver itself only targets net462, net8.0, and net9.0, so
the net10.0 test assemblies resolve the net9.0 driver build.  These jobs
therefore validate the driver on the .NET 10 runtime rather than
validating a .NET 10 build of the driver.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 10246002-c950-42a7-adf5-1698f9af4b3d
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings August 20, 2026 20:26
@cheenamalhotra cheenamalhotra added this to the 8.0.0-preview1 milestone Aug 20, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 19 out of 19 changed files in this pull request and generated no new comments.

Suppressed comments (13)

eng/pipelines/stages/verify-nuget-packages-ci-stage.yml:73

  • The pool block always selects the agent image via an imageOverride demand. If poolName is set to Azure Pipelines, this job will fail because hosted agents require vmImage selection and don’t expose the imageOverride capability. Use the same conditional pool logic used in eng/pipelines/jobs/test-azure-package-ci-job.yml / test-abstractions-package-ci-job.yml.
        pool:
          name: ${{ parameters.poolName }}

          demands:
            - imageOverride -equals ${{ parameters.vmImage }}

eng/pipelines/stages/generate-secrets-ci-stage.yml:67

  • This stage always uses an imageOverride demand to select the image. If poolName is Azure Pipelines, hosted agents require vmImage and the job won’t start. Add the same Azure Pipelines vs 1ES conditional pool block used by the test job templates.
          name: ${{ parameters.poolName }}

          demands:
            - imageOverride -equals ${{ parameters.vmImage }}

eng/pipelines/stages/compute-versions-ci-stage.yml:47

  • The pool block always uses an imageOverride demand. If a caller sets poolName: Azure Pipelines, this will fail because hosted pools require specifying vmImage instead of a demand. Match the conditional pool selection pattern used in the test job templates.
        pool:
          name: ${{ parameters.poolName }}
          demands:
            - imageOverride -equals ${{ parameters.vmImage }}

eng/pipelines/common/templates/jobs/ci-code-coverage-job.yml:42

  • This job template always selects the image via an imageOverride demand, which breaks if poolName is ever set to the hosted Azure Pipelines pool (hosted agents require vmImage). Consider using the same conditional pool block used by the test job templates to support both pool types.
    pool:
      name: ${{ parameters.poolName }}

      demands:
        - imageOverride -equals ${{ parameters.vmImage }}

eng/pipelines/pr/stages/pack-stage.yml:69

  • This PR stage always selects the image via an imageOverride demand. If PoolNameDefault (or a caller override) points at Azure Pipelines, this won’t work because hosted pools require vmImage. Use the same conditional pool selection pattern as the test job templates.
        pool:
          name: ${{ parameters.poolName }}

          demands:
            - imageOverride -equals ${{ parameters.vmImage }}

eng/pipelines/pr/stages/generate-secrets-stage.yml:63

  • This PR secrets stage always uses an imageOverride demand to select the image. If the pool is Azure Pipelines (or becomes it during rollout), hosted agents require vmImage instead. Add the Azure Pipelines vs 1ES conditional pool block used elsewhere.
          name: ${{ parameters.poolName }}

          demands:
            - imageOverride -equals ${{ parameters.vmImage }}

eng/pipelines/pr/stages/collect-coverage-stage.yml:43

  • This PR coverage collection stage always selects the agent image via an imageOverride demand. If poolName is Azure Pipelines, hosted agents require vmImage selection instead, so the job would fail to queue. Use the same conditional pool block as the test job templates.
        pool:
          name: ${{ parameters.poolName }}

          demands:
            - imageOverride -equals ${{ parameters.vmImage }}

eng/pipelines/jobs/pack-sqlserver-package-ci-job.yml:75

  • This job template always selects the agent image via an imageOverride demand. If poolName is set to Azure Pipelines, hosted pools require vmImage selection and the job will fail to queue. Use the same conditional pool block used by the test-* job templates.
    pool:
      name: ${{ parameters.poolName }}

      demands:
        - imageOverride -equals ${{ parameters.vmImage }}

eng/pipelines/jobs/pack-logging-package-ci-job.yml:76

  • This job template always selects the agent image via an imageOverride demand. If poolName is ever Azure Pipelines, hosted pools require vmImage selection and don’t expose the imageOverride capability. Add the Azure Pipelines vs 1ES conditional pool block used in other templates.
    pool:
      name: ${{ parameters.poolName }}

      demands:
        - imageOverride -equals ${{ parameters.vmImage }}

eng/pipelines/jobs/pack-azure-package-ci-job.yml:99

  • This job template always uses an imageOverride demand to pick the VM image. If poolName is Azure Pipelines, hosted pools require vmImage selection, so this job would fail. Use the same conditional pool logic used by test-azure-package-ci-job.yml.
    pool:
      name: ${{ parameters.poolName }}

      demands:
        - imageOverride -equals ${{ parameters.vmImage }}

eng/pipelines/jobs/pack-abstractions-package-ci-job.yml:93

  • This job template always selects the agent image via an imageOverride demand. If poolName is set to Azure Pipelines, hosted pools require vmImage and don’t provide imageOverride. Add the same conditional pool block used in the test-* job templates.
    pool:
      name: ${{ parameters.poolName }}

      demands:
        - imageOverride -equals ${{ parameters.vmImage }}

eng/pipelines/dotnet-sqlclient-ci-core.yml:506

  • The stage name key Win22_Azure_Sql no longer matches the agent image (ADO-Win25 / Windows Server 2025). Since ci-run-tests-stage.yml uses image.key as the stage name, this mismatch is easy to misinterpret later (and suggests the stage is still on Win22). Either rename the key to Win25_Azure_Sql, or add a NOTE explaining why the key is intentionally kept as Win22_* despite running on Win25.
        windows_azure_sql:
          pool: ${{parameters.defaultPoolName }}
          images:
            Win22_Azure_Sql: ADO-Win25
            Win11_Azure_Sql: ADO-CI-Win11

eng/pipelines/dotnet-sqlclient-ci-core.yml:639

  • Win22_Enclave_Sql19 is used as the generated stage name (see ci-run-tests-stage.yml), but it now runs on ADO-Win25. If this key is intentionally kept for branch policy/status check compatibility (similar to the note on Ubuntu20_Enclave_Sql19), add an explicit NOTE here as well; otherwise, consider renaming it to Win25_Enclave_Sql19 to avoid misleading stage names.
          windows_enclave_sql:
            pool: ADO-CI-AE-1ES-Pool
            images:
              Win22_Enclave_Sql19: ADO-Win25

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings August 20, 2026 20:35
@cheenamalhotra cheenamalhotra moved this from Waiting for customer to In review in SqlClient Board Aug 20, 2026
@cheenamalhotra
cheenamalhotra marked this pull request as ready for review August 20, 2026 20:39

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 19 out of 19 changed files in this pull request and generated no new comments.

Suppressed comments (11)

eng/pipelines/stages/verify-nuget-packages-ci-stage.yml:73

  • The pool block selects the image via an imageOverride demand unconditionally. That works for 1ES pools, but will fail if poolName is ever set to the hosted Azure Pipelines pool (which requires vmImage selection), contradicting the template’s intent to support both pool types.
        pool:
          name: ${{ parameters.poolName }}

          demands:
            - imageOverride -equals ${{ parameters.vmImage }}

eng/pipelines/stages/generate-secrets-ci-stage.yml:67

  • This pool block uses an imageOverride demand unconditionally. If a caller sets poolName: Azure Pipelines, the job won’t start because hosted agents don’t support selecting images via demands (they require vmImage).
        pool:
          # This job has no special image requirements, so use a minimal Linux image.
          name: ${{ parameters.poolName }}

          demands:
            - imageOverride -equals ${{ parameters.vmImage }}

eng/pipelines/stages/compute-versions-ci-stage.yml:47

  • The template parameterizes poolName/vmImage, but the job’s pool block still assumes a 1ES pool by always using an imageOverride demand. This breaks reuse with the hosted Azure Pipelines pool, which requires vmImage.
        pool:
          name: ${{ parameters.poolName }}
          demands:
            - imageOverride -equals ${{ parameters.vmImage }}

eng/pipelines/common/templates/jobs/ci-code-coverage-job.yml:42

  • This job template selects the VM image via an imageOverride demand only. If poolName is ever set to the hosted Azure Pipelines pool, the job will fail because hosted agents require vmImage instead of a demand-based image selector.
    pool:
      name: ${{ parameters.poolName }}

      demands:
        - imageOverride -equals ${{ parameters.vmImage }}

eng/pipelines/jobs/pack-sqlserver-package-ci-job.yml:75

  • This pack job template always selects the image via an imageOverride demand. That works for 1ES pools but will fail if poolName is set to the hosted Azure Pipelines pool (which requires vmImage).
    pool:
      name: ${{ parameters.poolName }}

      demands:
        - imageOverride -equals ${{ parameters.vmImage }}

eng/pipelines/jobs/pack-logging-package-ci-job.yml:76

  • This pack job template assumes a 1ES pool by unconditionally using an imageOverride demand. If a caller uses poolName: Azure Pipelines, the job won’t be able to select an image and will fail to queue.
    pool:
      name: ${{ parameters.poolName }}

      demands:
        - imageOverride -equals ${{ parameters.vmImage }}

eng/pipelines/jobs/pack-azure-package-ci-job.yml:99

  • This pack job template selects the image via an imageOverride demand only. That won’t work if poolName is set to the hosted Azure Pipelines pool, which requires vmImage selection instead of a demand.
    pool:
      name: ${{ parameters.poolName }}

      demands:
        - imageOverride -equals ${{ parameters.vmImage }}

eng/pipelines/jobs/pack-abstractions-package-ci-job.yml:93

  • This pack job template assumes a 1ES pool by always using an imageOverride demand. If poolName is ever set to the hosted Azure Pipelines pool, the job will fail because hosted agents require vmImage.
    pool:
      name: ${{ parameters.poolName }}

      demands:
        - imageOverride -equals ${{ parameters.vmImage }}

eng/pipelines/pr/stages/pack-stage.yml:69

  • This PR stage always selects the image via an imageOverride demand. If PoolNameDefault is (or becomes) Azure Pipelines, the stage will fail because hosted agents require image selection via vmImage.
        pool:
          name: ${{ parameters.poolName }}

          demands:
            - imageOverride -equals ${{ parameters.vmImage }}

eng/pipelines/pr/stages/generate-secrets-stage.yml:63

  • This PR secrets stage assumes a 1ES pool by unconditionally using an imageOverride demand. If a caller uses the hosted Azure Pipelines pool, the job won’t start because hosted agents require vmImage selection.
        pool:
          # This job has no special image requirements, so use a minimal Linux image.
          name: ${{ parameters.poolName }}

          demands:
            - imageOverride -equals ${{ parameters.vmImage }}

eng/pipelines/pr/stages/collect-coverage-stage.yml:43

  • This PR coverage stage selects the VM image via an imageOverride demand only. That will fail if PoolNameDefault is set to the hosted Azure Pipelines pool, which requires vmImage instead.
        pool:
          name: ${{ parameters.poolName }}

          demands:
            - imageOverride -equals ${{ parameters.vmImage }}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: In review

Development

Successfully merging this pull request may close these issues.

4 participants