Pipelines | Move CI and PR jobs off Microsoft-hosted agents - #4515
Pipelines | Move CI and PR jobs off Microsoft-hosted agents#4515cheenamalhotra wants to merge 4 commits into
Conversation
There was a problem hiding this comment.
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/vmImagefor multiple CI/PR stages and jobs, switching selection to 1ES-styleimageOverridedemands. - Removed redundant hosted Linux/Windows Azure package test jobs and trimmed downstream
dependsOnaccordingly. - 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.
| pool: | ||
| name: Azure Pipelines | ||
| vmImage: windows-latest | ||
| name: ${{ parameters.poolName }} | ||
| demands: | ||
| - imageOverride -equals ${{ parameters.vmImage }} |
There was a problem hiding this comment.
Addressed in 1aa857c3a. All ten of these templates now use the same conditional pool block the test-* job templates already use, so they work with either a 1ES pool (imageOverride demand) or the hosted Azure Pipelines pool (vmImage).
| # We don't need anything special, so any Linux image in our 1ES pool | ||
| # will do. | ||
| name: ${{ parameters.poolName }} | ||
| demands: | ||
| - imageOverride -equals ${{ parameters.vmImage }} |
There was a problem hiding this comment.
Addressed in 1aa857c3a. All ten of these templates now use the same conditional pool block the test-* job templates already use, so they work with either a 1ES pool (imageOverride demand) or the hosted Azure Pipelines pool (vmImage).
| pool: | ||
| name: Azure Pipelines | ||
| vmImage: ubuntu-latest | ||
| name: ${{ parameters.poolName }} | ||
| demands: | ||
| - imageOverride -equals ${{ parameters.vmImage }} |
There was a problem hiding this comment.
Addressed in 1aa857c3a. All ten of these templates now use the same conditional pool block the test-* job templates already use, so they work with either a 1ES pool (imageOverride demand) or the hosted Azure Pipelines pool (vmImage).
| pool: | ||
| name: Azure Pipelines | ||
| vmImage: ubuntu-latest | ||
| name: ${{ parameters.poolName }} | ||
| demands: | ||
| - imageOverride -equals ${{ parameters.vmImage }} |
There was a problem hiding this comment.
Addressed in 1aa857c3a. All ten of these templates now use the same conditional pool block the test-* job templates already use, so they work with either a 1ES pool (imageOverride demand) or the hosted Azure Pipelines pool (vmImage).
| pool: | ||
| name: Azure Pipelines | ||
| vmImage: ubuntu-latest | ||
| name: ${{ parameters.poolName }} | ||
| demands: | ||
| - imageOverride -equals ${{ parameters.vmImage }} |
There was a problem hiding this comment.
Addressed in 1aa857c3a. All ten of these templates now use the same conditional pool block the test-* job templates already use, so they work with either a 1ES pool (imageOverride demand) or the hosted Azure Pipelines pool (vmImage).
| pool: | ||
| name: Azure Pipelines | ||
| vmImage: ubuntu-latest | ||
| name: ${{ parameters.poolName }} | ||
| demands: | ||
| - imageOverride -equals ${{ parameters.vmImage }} |
There was a problem hiding this comment.
Addressed in 1aa857c3a. All ten of these templates now use the same conditional pool block the test-* job templates already use, so they work with either a 1ES pool (imageOverride demand) or the hosted Azure Pipelines pool (vmImage).
| pool: | ||
| name: Azure Pipelines | ||
| vmImage: ubuntu-latest | ||
| name: ${{ parameters.poolName }} | ||
| demands: | ||
| - imageOverride -equals ${{ parameters.vmImage }} |
There was a problem hiding this comment.
Addressed in 1aa857c3a. All ten of these templates now use the same conditional pool block the test-* job templates already use, so they work with either a 1ES pool (imageOverride demand) or the hosted Azure Pipelines pool (vmImage).
| pool: | ||
| vmImage: 'ubuntu-latest' | ||
| name: ${{ parameters.poolName }} | ||
| demands: | ||
| - imageOverride -equals ${{ parameters.vmImage }} |
There was a problem hiding this comment.
Addressed in 1aa857c3a. All ten of these templates now use the same conditional pool block the test-* job templates already use, so they work with either a 1ES pool (imageOverride demand) or the hosted Azure Pipelines pool (vmImage).
| pool: | ||
| vmImage: ubuntu-latest | ||
| name: ${{ parameters.poolName }} | ||
| demands: | ||
| - imageOverride -equals ${{ parameters.vmImage }} |
There was a problem hiding this comment.
Addressed in 1aa857c3a. All ten of these templates now use the same conditional pool block the test-* job templates already use, so they work with either a 1ES pool (imageOverride demand) or the hosted Azure Pipelines pool (vmImage).
| # We don't need anything special, so any Linux image in our 1ES pool | ||
| # will do. | ||
| name: ${{ parameters.poolName }} | ||
| demands: | ||
| - imageOverride -equals ${{ parameters.vmImage }} |
There was a problem hiding this comment.
Addressed in 1aa857c3a. All ten of these templates now use the same conditional pool block the test-* job templates already use, so they work with either a 1ES pool (imageOverride demand) or the hosted Azure Pipelines pool (vmImage).
b75fd7d to
8fb349a
Compare
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.ymlis "out of scope and untouched" and still uses a hosted image, but this PR changes the job pool to 1ES with animageOverridedemand. 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') }}:
All jobs that previously ran on the Microsoft-hosted 'Azure Pipelines'
pool now run on our 1ES pools, with the sole exception of macOS jobs,
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 a Linux image (or a
Windows image, for verify-nuget).
- 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.
- Pass explicit pool names from the stress and Kerberos pipelines,
which reuse these templates but do not import the CI build
variables.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 10246002-c950-42a7-adf5-1698f9af4b3d
The nightly package build pipeline still offered ADO-UB24 and ADO-Win25 as its agentImage choices. Move it onto the same images the rest of CI now uses: ADO-UB24-SQL25 and ADO-MMS25-SQL25. The job only runs build.proj Pack, so it does not depend on the SQL Server instance these images carry. Aligning them means we maintain one set of agent images rather than two. Note that both ADO-1ES-Pool and ADO-CI-1ES-Pool must publish these images before this merges, since the pool is chosen based on whether the build is internal or public. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 10246002-c950-42a7-adf5-1698f9af4b3d
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
22e6b04 to
1aa857c
Compare
|
Also addressing the two suppressed comments from the earlier review passes:
|
There was a problem hiding this comment.
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.ymlis “out of scope and untouched” and still uses a hosted image, but this diff switches it to 1ES pools with animageOverridedemand. 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') }}:
There was a problem hiding this comment.
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.
| # This pipeline does not import the CI build variables, so the pool | ||
| # must be named explicitly. Reuse the Linux stage's pool and image. | ||
| poolName: ADO-Trusted-Linux-WestUS2 | ||
| vmImage: ADO-UB20-SQL22 |
There was a problem hiding this comment.
Can we use a minimal OS-only image, like ADO-UB24? Collecting code coverage shouldn't require a local SQL Server.
| displayName: Agent Image | ||
| type: string | ||
| default: ADO-UB24 | ||
| default: ADO-UB24-SQL25 |
There was a problem hiding this comment.
These jobs don't need a local SQL Server or any extra tooling (like MMS brings). They only need a base OS and minimal tooling.
| # The name of the VM image to run on, within the pool. | ||
| - name: vmImage | ||
| type: string | ||
| default: ADO-UB24-SQL25 |
There was a problem hiding this comment.
No need for local SQL Server - this can use ADO-UB24.
| name: ${{ parameters.poolName }} | ||
|
|
||
| # Images provided by Azure Pipelines must be selected using 'vmImage'. | ||
| ${{ if eq(parameters.poolName, 'Azure Pipelines') }}: |
There was a problem hiding this comment.
At template expansion time (when ${{ }} expressions are evaluated), the parameters.poolName value will be the literal string $(ci_var_defaultPoolName) if the default is used, in which case we will end up in the ${{ else }} block regardless of what the runtime-expanded value of $(ci_var_defaultPoolName) is. We can't use a library variable to choose images like this unfortunately.
Do we really need the flexibility to change pool and image names as pipeline configuration?
| # The name of the VM image to run on, within the pool. | ||
| - name: vmImage | ||
| type: string | ||
| default: ADO-UB24-SQL25 |
There was a problem hiding this comment.
Building and packing doesn't require a local SQL Server.
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 Pipelinespool now runs on our 1ES pools. The sole exception is macOS, since our 1ES pools do not offer macOS images.ADO-UB24-SQL25(orADO-MMS25-SQL25for verify-nuget, which needs Windows).ADO-UB24-SQL25andADO-MMS25-SQL25.pack_azure_package_jobdependencies were trimmed accordingly.ci-build-variables.ymlnorsqlclient-testconfig-v1, so the default pool variables are not defined there.ADO-UB24/ADO-Win25and ontoADO-UB24-SQL25/ADO-MMS25-SQL25.ubuntu-latestimage and ontoADO-UB24-SQL25, using the same internal/public conditional pool convention as the other pipelines.pwshis available natively on that image, so no install step is needed.poolName/vmImage. Selecting the image with a 1ESimageOverridedemand unconditionally would break any caller still pointing at the hostedAzure Pipelinespool, which requiresvmImageinstead. These templates now use the same conditional pool block thetest-*job templates already use.Remaining hosted usage
Intentionally retained, all macOS:
dotnet-sqlclient-ci-core.yml- macOS test configurationstages/build-azure-package-ci-stage.yml- macOS Azure package jobstages/build-abstractions-package-ci-stage.yml- macOS abstractions jobci/stress/sqlclient-ci-stress-stage.yml- macOS stress jobThere is no remaining non-macOS use of a Microsoft-hosted image in
eng/pipelines.Action required before merge
ADO-MMS25-SQL25andADO-UB24-SQL25must be available in bothADO-1ES-PoolandADO-CI-1ES-Pool, since the package and GitHub sync pipelines select the pool based on the project they run in.Checklist
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.