From 0a6c3d71fb9562c4e47fdf6878a705d8b775c2a0 Mon Sep 17 00:00:00 2001 From: "Dustin L. Howett" Date: Fri, 24 Apr 2026 15:39:27 -0500 Subject: [PATCH] build: Add a 1ES Pipeline Templates version of Canary (#20127) This pipeline runs on our agents, rather than OneBranch's, and doesn't use all of the OneBranch machinery--which is only required for producing a vpack that we check into Windows. Since Canary will never be a vpack, we don't need to worry. It runs at about twice the speed _and_ we control the build images! This pull request also adds support for the "Terrapin Retrieval Tool," which will allow us to move away from having vcpkg contact remote servers directly to download source code (and which may become mandatory even in our OneBranch pipelines.) --- .github/actions/spelling/expect/expect.txt | 1 + build/config/tsa.json | 1 + build/pipelines/1espt-nightly.yml | 64 +++++ .../templates-v2/job-build-package-wpf.yml | 4 + .../templates-v2/job-build-project.yml | 4 + .../job-merge-msix-into-bundle.yml | 4 + .../templates-v2/job-package-conpty.yml | 4 + .../pipeline-1espt-full-release-build.yml | 233 ++++++++++++++++++ .../pipeline-full-release-build.yml | 5 +- .../pipeline-onebranch-full-release-build.yml | 5 +- .../templates-v2/steps-install-terrapin.yml | 6 + 11 files changed, 329 insertions(+), 2 deletions(-) create mode 100644 build/pipelines/1espt-nightly.yml create mode 100644 build/pipelines/templates-v2/pipeline-1espt-full-release-build.yml create mode 100644 build/pipelines/templates-v2/steps-install-terrapin.yml diff --git a/.github/actions/spelling/expect/expect.txt b/.github/actions/spelling/expect/expect.txt index 6c226753b9..571abdbafb 100644 --- a/.github/actions/spelling/expect/expect.txt +++ b/.github/actions/spelling/expect/expect.txt @@ -541,6 +541,7 @@ EPres EQU ERASEBKGND ERRORONEXIT +espt esrp ESV ETW diff --git a/build/config/tsa.json b/build/config/tsa.json index 61924ef4bd..f6cb80d2ce 100644 --- a/build/config/tsa.json +++ b/build/config/tsa.json @@ -1,4 +1,5 @@ { + "codebaseName": "VSTS_Microsoft_OSGS_OpenConsole", "instanceUrl": "https://microsoft.visualstudio.com", "projectName": "OS", "areaPath": "OS\\Windows Client and Services\\WinPD\\DFX-Developer Fundamentals and Experiences\\DEFT\\SHINE\\Terminal", diff --git a/build/pipelines/1espt-nightly.yml b/build/pipelines/1espt-nightly.yml new file mode 100644 index 0000000000..cbd6cfef72 --- /dev/null +++ b/build/pipelines/1espt-nightly.yml @@ -0,0 +1,64 @@ +trigger: none +pr: none +schedules: + - cron: "30 3 * * 2-6" # Run at 03:30 UTC Tuesday through Saturday (After the work day in Pacific, Mon-Fri) + displayName: "Nightly Terminal Build" + branches: + include: + - main + always: false # only run if there's code changes! + +parameters: + - name: publishToAzure + displayName: "Deploy to **PUBLIC** Azure Storage" + type: boolean + default: true + - name: official + displayName: "Run on Official 1ES Pipeline Templates" + type: boolean + default: true + +name: $(BuildDefinitionName)_$(date:yyMM).$(date:dd)$(rev:rrr) + +variables: + - template: templates-v2/variables-nuget-package-version.yml + parameters: + branding: Canary + +extends: + template: templates-v2/pipeline-1espt-full-release-build.yml + parameters: + official: ${{ parameters.official }} + branding: Canary + buildTerminal: true + pgoBuildMode: Optimize + codeSign: true + signingIdentity: + serviceName: $(SigningServiceName) + appId: $(SigningAppId) + tenantId: $(SigningTenantId) + akvName: $(SigningAKVName) + authCertName: $(SigningAuthCertName) + signCertName: $(SigningSignCertName) + useManagedIdentity: $(SigningUseManagedIdentity) + clientId: $(SigningOriginalClientId) + publishSymbolsToPublic: true + symbolExpiryTime: 15 + symbolPublishingSubscription: $(SymbolPublishingServiceConnection) + symbolPublishingProject: $(SymbolPublishingProject) + ${{ if eq(true, parameters.publishToAzure) }}: + extraPublishJobs: + - template: build/pipelines/templates-v2/job-deploy-to-azure-storage.yml@self + parameters: + pool: + name: SHINE-INT-S + os: windows + dependsOn: [PublishSymbols] + storagePublicRootURL: $(AppInstallerRootURL) + subscription: $(AzureSubscriptionName) + storageAccount: $(AzureStorageAccount) + storageContainer: $(AzureStorageContainer) + buildConfiguration: Release + buildPlatforms: [x64, x86, arm64] + environment: production-canary + diff --git a/build/pipelines/templates-v2/job-build-package-wpf.yml b/build/pipelines/templates-v2/job-build-package-wpf.yml index b71341bcac..d8d40a01f5 100644 --- a/build/pipelines/templates-v2/job-build-package-wpf.yml +++ b/build/pipelines/templates-v2/job-build-package-wpf.yml @@ -30,9 +30,13 @@ parameters: - name: signingIdentity type: object default: {} + - name: outerTemplateContext + type: object + default: {} jobs: - job: ${{ parameters.jobName }} + templateContext: ${{ parameters.outerTemplateContext }} ${{ if ne(length(parameters.pool), 0) }}: pool: ${{ parameters.pool }} ${{ if eq(parameters.codeSign, true) }}: diff --git a/build/pipelines/templates-v2/job-build-project.yml b/build/pipelines/templates-v2/job-build-project.yml index c6d84c4bad..659f95a126 100644 --- a/build/pipelines/templates-v2/job-build-project.yml +++ b/build/pipelines/templates-v2/job-build-project.yml @@ -74,9 +74,13 @@ parameters: - name: afterBuildSteps type: stepList default: [] + - name: outerTemplateContext + type: object + default: {} jobs: - job: ${{ parameters.jobName }} + templateContext: ${{ parameters.outerTemplateContext }} ${{ if ne(length(parameters.pool), 0) }}: pool: ${{ parameters.pool }} strategy: diff --git a/build/pipelines/templates-v2/job-merge-msix-into-bundle.yml b/build/pipelines/templates-v2/job-merge-msix-into-bundle.yml index 261750db8f..c4624a0d01 100644 --- a/build/pipelines/templates-v2/job-merge-msix-into-bundle.yml +++ b/build/pipelines/templates-v2/job-merge-msix-into-bundle.yml @@ -35,9 +35,13 @@ parameters: - name: signingIdentity type: object default: {} + - name: outerTemplateContext + type: object + default: {} jobs: - job: ${{ parameters.jobName }} + templateContext: ${{ parameters.outerTemplateContext }} ${{ if ne(length(parameters.pool), 0) }}: pool: ${{ parameters.pool }} ${{ if eq(parameters.codeSign, true) }}: diff --git a/build/pipelines/templates-v2/job-package-conpty.yml b/build/pipelines/templates-v2/job-package-conpty.yml index b91c2989f3..21455cd11f 100644 --- a/build/pipelines/templates-v2/job-package-conpty.yml +++ b/build/pipelines/templates-v2/job-package-conpty.yml @@ -30,9 +30,13 @@ parameters: - name: signingIdentity type: object default: {} + - name: outerTemplateContext + type: object + default: {} jobs: - job: ${{ parameters.jobName }} + templateContext: ${{ parameters.outerTemplateContext }} ${{ if ne(length(parameters.pool), 0) }}: pool: ${{ parameters.pool }} ${{ if eq(parameters.codeSign, true) }}: diff --git a/build/pipelines/templates-v2/pipeline-1espt-full-release-build.yml b/build/pipelines/templates-v2/pipeline-1espt-full-release-build.yml new file mode 100644 index 0000000000..62e541a2c1 --- /dev/null +++ b/build/pipelines/templates-v2/pipeline-1espt-full-release-build.yml @@ -0,0 +1,233 @@ +parameters: + - name: official + type: boolean + default: false + - name: branding + type: string + default: Release + values: + - Release + - Preview + - Canary + - Dev + - name: buildTerminal + type: boolean + default: true + - name: buildConPTY + type: boolean + default: false + - name: buildWPF + type: boolean + default: false + - name: pgoBuildMode + type: string + default: Optimize + values: + - Optimize + - Instrument + - None + - name: buildConfigurations + type: object + default: + - Release + - name: buildPlatforms + type: object + default: + - x64 + - x86 + - arm64 + - name: codeSign + type: boolean + default: true + - name: terminalInternalPackageVersion + type: string + default: '0.0.8' + + - name: publishSymbolsToPublic + type: boolean + default: true + - name: symbolExpiryTime + type: string + default: 36530 # This is the default from PublishSymbols@2 + - name: symbolPublishingSubscription + type: string + - name: symbolPublishingProject + type: string + + - name: extraPublishJobs + type: object + default: [] + - name: signingIdentity + type: object + default: {} + +resources: + repositories: + - repository: 1esPipelines + type: git + name: 1ESPipelineTemplates/1ESPipelineTemplates + ref: refs/tags/release + +extends: + ${{ if eq(parameters.official, true) }}: + template: v1/1ES.Official.PipelineTemplate.yml@1esPipelines + ${{ else }}: + template: v1/1ES.Unofficial.PipelineTemplate.yml@1esPipelines + parameters: + customBuildTags: + - 1ES.PT.ViaStartRight + pool: + name: SHINE-INT-L + os: windows + sdl: + tsa: + enabled: true + configFile: '$(Build.SourcesDirectory)\build\config\tsa.json' + binskim: + enabled: true + policheck: + enabled: false + severity: Note + baseline: + baselineFile: '$(Build.SourcesDirectory)\build\config\release.gdnbaselines' + suppressionSet: default + + stages: + - stage: Build + displayName: Build + dependsOn: [] + jobs: + - template: ./build/pipelines/templates-v2/job-build-project.yml@self + parameters: + outerTemplateContext: + outputs: + - output: pipelineArtifact + targetPath: $(JobOutputDirectory) + artifactName: $(JobOutputArtifactName) + publishArtifacts: false # Handled by 1ESPT + branding: ${{ parameters.branding }} + buildTerminal: ${{ parameters.buildTerminal }} + buildConPTY: ${{ parameters.buildConPTY }} + buildWPF: ${{ parameters.buildWPF }} + pgoBuildMode: ${{ parameters.pgoBuildMode }} + buildConfigurations: ${{ parameters.buildConfigurations }} + buildPlatforms: ${{ parameters.buildPlatforms }} + generateSbom: false # this is handled by 1ESPT + removeAllNonSignedFiles: true # appease the overlords + codeSign: ${{ parameters.codeSign }} + signingIdentity: ${{ parameters.signingIdentity }} + beforeBuildSteps: + - template: ./build/pipelines/templates-v2/steps-setup-versioning.yml@self + + - template: ./build/pipelines/templates-v2/steps-install-terrapin.yml@self + + - task: UniversalPackages@0 + displayName: Download terminal-internal Universal Package + inputs: + feedListDownload: 2b3f8893-a6e8-411f-b197-a9e05576da48 + packageListDownload: e82d490c-af86-4733-9dc4-07b772033204 + versionListDownload: ${{ parameters.terminalInternalPackageVersion }} + + - ${{ if eq(parameters.buildWPF, true) }}: + # Add an Any CPU build flavor for the WPF control bits + - template: ./build/pipelines/templates-v2/job-build-project.yml@self + parameters: + outerTemplateContext: + outputs: + - output: pipelineArtifact + targetPath: $(JobOutputDirectory) + artifactName: $(JobOutputArtifactName) + publishArtifacts: false # Handled by 1ESPT + jobName: BuildWPF + branding: ${{ parameters.branding }} + buildTerminal: false + buildWPFDotNetComponents: true + buildConfigurations: ${{ parameters.buildConfigurations }} + buildPlatforms: + - Any CPU + generateSbom: false # this is handled by 1ESPT + removeAllNonSignedFiles: true # appease the overlords + codeSign: ${{ parameters.codeSign }} + signingIdentity: ${{ parameters.signingIdentity }} + beforeBuildSteps: + - template: ./build/pipelines/templates-v2/steps-setup-versioning.yml@self + # WPF doesn't need the localizations or the universal package, but if it does... put them here. + + - stage: Package + displayName: Package + dependsOn: [Build] + jobs: + - ${{ if eq(parameters.buildTerminal, true) }}: + - template: ./build/pipelines/templates-v2/job-merge-msix-into-bundle.yml@self + parameters: + pool: + name: SHINE-INT-S + os: windows + outerTemplateContext: + outputs: + - output: pipelineArtifact + targetPath: $(JobOutputDirectory) + artifactName: $(JobOutputArtifactName) + publishArtifacts: false # Handled by 1ESPT + jobName: Bundle + branding: ${{ parameters.branding }} + buildConfigurations: ${{ parameters.buildConfigurations }} + buildPlatforms: ${{ parameters.buildPlatforms }} + generateSbom: false # Handled by 1ESPT + codeSign: ${{ parameters.codeSign }} + signingIdentity: ${{ parameters.signingIdentity }} + + - ${{ if eq(parameters.buildConPTY, true) }}: + - template: ./build/pipelines/templates-v2/job-package-conpty.yml@self + parameters: + pool: + name: SHINE-INT-S + os: windows + outerTemplateContext: + outputs: + - output: pipelineArtifact + targetPath: $(JobOutputDirectory) + artifactName: $(JobOutputArtifactName) + publishArtifacts: false # Handled by 1ESPT + buildConfigurations: ${{ parameters.buildConfigurations }} + buildPlatforms: ${{ parameters.buildPlatforms }} + generateSbom: false # this is handled by 1ESPT + codeSign: ${{ parameters.codeSign }} + signingIdentity: ${{ parameters.signingIdentity }} + + - ${{ if eq(parameters.buildWPF, true) }}: + - template: ./build/pipelines/templates-v2/job-build-package-wpf.yml@self + parameters: + pool: + name: SHINE-INT-S + os: windows + outerTemplateContext: + outputs: + - output: pipelineArtifact + targetPath: $(JobOutputDirectory) + artifactName: $(JobOutputArtifactName) + publishArtifacts: false # Handled by 1ESPT + buildConfigurations: ${{ parameters.buildConfigurations }} + buildPlatforms: ${{ parameters.buildPlatforms }} + generateSbom: false # this is handled by 1ESPT + codeSign: ${{ parameters.codeSign }} + signingIdentity: ${{ parameters.signingIdentity }} + + - stage: Publish + displayName: Publish + dependsOn: + - Build + - ${{ if or(parameters.buildTerminal, parameters.buildConPTY, parameters.buildWPF) }}: + - Package + jobs: + - template: ./build/pipelines/templates-v2/job-publish-symbols-using-symbolrequestprod-api.yml@self + parameters: + pool: + name: SHINE-INT-S + os: windows + includePublicSymbolServer: ${{ parameters.publishSymbolsToPublic }} + symbolExpiryTime: ${{ parameters.symbolExpiryTime }} + subscription: ${{ parameters.symbolPublishingSubscription }} + symbolProject: ${{ parameters.symbolPublishingProject }} + + - ${{ parameters.extraPublishJobs }} diff --git a/build/pipelines/templates-v2/pipeline-full-release-build.yml b/build/pipelines/templates-v2/pipeline-full-release-build.yml index 8651f54568..9a65d6e08a 100644 --- a/build/pipelines/templates-v2/pipeline-full-release-build.yml +++ b/build/pipelines/templates-v2/pipeline-full-release-build.yml @@ -153,7 +153,10 @@ stages: - stage: Publish displayName: Publish pool: ${{ parameters.pool }} - dependsOn: [Build, Package] + dependsOn: + - Build + - ${{ if or(parameters.buildTerminal, parameters.buildConPTY, parameters.buildWPF) }}: + - Package jobs: # We only support the vpack for Release builds that include Terminal - ${{ if and(containsValue(parameters.buildConfigurations, 'Release'), parameters.buildTerminal, parameters.publishVpackToWindows) }}: diff --git a/build/pipelines/templates-v2/pipeline-onebranch-full-release-build.yml b/build/pipelines/templates-v2/pipeline-onebranch-full-release-build.yml index f2111de855..bd78a0d5f9 100644 --- a/build/pipelines/templates-v2/pipeline-onebranch-full-release-build.yml +++ b/build/pipelines/templates-v2/pipeline-onebranch-full-release-build.yml @@ -279,7 +279,10 @@ extends: - stage: Publish displayName: Publish - dependsOn: [Build] + dependsOn: + - Build + - ${{ if or(parameters.buildTerminal, parameters.buildConPTY, parameters.buildWPF) }}: + - Package jobs: - template: ./build/pipelines/templates-v2/job-publish-symbols-using-symbolrequestprod-api.yml@self parameters: diff --git a/build/pipelines/templates-v2/steps-install-terrapin.yml b/build/pipelines/templates-v2/steps-install-terrapin.yml new file mode 100644 index 0000000000..c8330c803d --- /dev/null +++ b/build/pipelines/templates-v2/steps-install-terrapin.yml @@ -0,0 +1,6 @@ +steps: +- pwsh: |- + nuget install -source "https://pkgs.dev.azure.com/microsoft/_packaging/WindowsTerminal/nuget/v3/index.json" TerrapinRetrievalTool -Prerelease -OutputDirectory _trt + $TerrapinRetrievalToolPath = (Get-Item _trt\TerrapinRetrievalTool.*\win-x64\TerrapinRetrievalTool.exe).FullName + Write-Host "##vso[task.setvariable variable=X_VCPKG_ASSET_SOURCES]x-script,${TerrapinRetrievalToolPath} -b https://vcpkg.storage.devpackages.microsoft.io/artifacts/ -a true -u None -p {url} -s {sha512} -d {dst};x-block-origin" + displayName: Set up the Terrapin Retrieval Tool (vcpkg cache)