From 87610eb50b52f90804794c2bef0442935dd87d9a Mon Sep 17 00:00:00 2001 From: Daniel Jurek Date: Mon, 25 Mar 2024 15:34:30 -0700 Subject: [PATCH] 1ES Migration (#3557) * Refactor release-cli.yml to stage templates * Refactor for 1ES * Insert syntax * Parameters syntax * Proper parameter syntax * Parameter testing... * convertToJson * Revert syntax testing * Publishing * s * Revert template * image * Matrix expansion * Formatting * Variables * Spelling * Pool info * Tabbing * macos-12 * Notes * Insert syntax * Log matrix parts * Syntax * No variables * Mac images, also swap formatting * Remove BaseUrl * Formatting, chomping * Test un-chomped * Tabbing * Not a variable * Uncomment * Cred Scan Suppression * Bring New-TestResources.ps1 up to date * CredScan suppressions * Docker install on macOS * Skip live test * Task version * s * Test in short mode * M365 * Do not use variables for OS * Fix pool.os in other places * Linux ARM * ImageKey * Setup Golang in ARM64 * aarch64 * PreSteps, Host Arch * Wire up HostArchitecture * Wire up HostArchitecture * sudo * Exclude _manifest, Skip live tests * Template wiring * fix YAML * Artifact staging * workingDirectory * Build output * standalone.json * Add options suggested by BinSkim * Parameters for release * /Qspectre * Variable expansion * vcxproj configs * vscode 1ES migration * ImageKey * vmImage/image * Set shield artifact condition * image * string true * s * image * outputs * Ensure variables * Remove ARM64 linux * Refactor deployments * deployments need to consume artifacts * checkout * Inputs * Names * Expand variables * Re-enable deployments * Migrate repoman pipeline to 1ES * templateContext * Test change * use env vars in script * do not skip az login * no condition * Address TODOs * Revert NOTICE.txt * Review feedback, spacing * Re-add Skip.LiveTest condition to azd-login.yml --------- Co-authored-by: Victor Vazquez --- cli/installer/windows-actions/actions.vcxproj | 169 +- eng/CredScanSuppression.json | 12 + .../TestResources/New-TestResources.ps1 | 8 +- eng/pipelines/release-cli.yml | 1589 +---------------- eng/pipelines/release-vscode.yml | 324 +--- eng/pipelines/repoman.yml | 315 ++-- eng/pipelines/templates/jobs/build-cli.yml | 217 +++ .../templates/jobs/cross-build-cli.yml | 102 ++ .../templates/jobs/run-template-tests.yml | 19 +- .../templates/jobs/verify-installers.yml | 170 ++ eng/pipelines/templates/jobs/vscode-build.yml | 107 ++ .../templates/stages/1es-redirect.yml | 44 + .../templates/stages/build-and-test.yml | 219 +++ .../templates/stages/code-coverage-upload.yml | 73 + eng/pipelines/templates/stages/publish.yml | 579 ++++++ eng/pipelines/templates/stages/sign.yml | 204 +++ .../templates/stages/verify-installers.yml | 322 ++++ .../stages/vscode-build-and-test.yml | 45 + .../stages/vscode-publish-integration.yml | 106 ++ .../stages/vscode-publish-manual.yml | 80 + .../templates/stages/vscode-sign.yml | 52 + .../templates/steps/publish-cli-choco.yml | 6 +- .../templates/steps/publish-cli-winget.yml | 6 +- eng/pipelines/templates/steps/publish-cli.yml | 7 +- eng/pipelines/templates/steps/setup-go.yml | 25 + eng/pipelines/templates/variables/image.yml | 33 + 26 files changed, 2700 insertions(+), 2133 deletions(-) create mode 100644 eng/CredScanSuppression.json create mode 100644 eng/pipelines/templates/jobs/build-cli.yml create mode 100644 eng/pipelines/templates/jobs/cross-build-cli.yml create mode 100644 eng/pipelines/templates/jobs/verify-installers.yml create mode 100644 eng/pipelines/templates/jobs/vscode-build.yml create mode 100644 eng/pipelines/templates/stages/1es-redirect.yml create mode 100644 eng/pipelines/templates/stages/build-and-test.yml create mode 100644 eng/pipelines/templates/stages/code-coverage-upload.yml create mode 100644 eng/pipelines/templates/stages/publish.yml create mode 100644 eng/pipelines/templates/stages/sign.yml create mode 100644 eng/pipelines/templates/stages/verify-installers.yml create mode 100644 eng/pipelines/templates/stages/vscode-build-and-test.yml create mode 100644 eng/pipelines/templates/stages/vscode-publish-integration.yml create mode 100644 eng/pipelines/templates/stages/vscode-publish-manual.yml create mode 100644 eng/pipelines/templates/stages/vscode-sign.yml create mode 100644 eng/pipelines/templates/variables/image.yml diff --git a/cli/installer/windows-actions/actions.vcxproj b/cli/installer/windows-actions/actions.vcxproj index f01685c1260..1885f5fec18 100644 --- a/cli/installer/windows-actions/actions.vcxproj +++ b/cli/installer/windows-actions/actions.vcxproj @@ -1,74 +1,95 @@ - - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - {51D5518D-64BD-43C6-9A8A-91A5936BC2D6} - Release - Win32 - bin/$(Platform)/$(Configuration)/ - obj/$(Platform)/$(Configuration)/ - 10.0 - - - - DynamicLibrary - v143 - Unicode - - - - - - MaxSpeed - Use - pch.h - MultiThreadedDebug - MultiThreaded - - - msi.lib;version.lib;%(AdditionalDependencies) - actions.def - Windows - - - - - - - - Create - - - - - - - - - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - + + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {51D5518D-64BD-43C6-9A8A-91A5936BC2D6} + Release + Win32 + bin/$(Platform)/$(Configuration)/ + obj/$(Platform)/$(Configuration)/ + 10.0 + + + + DynamicLibrary + v143 + Unicode + + + Spectre + + + Spectre + + + Spectre + + + Spectre + + + + + + MaxSpeed + Use + pch.h + MultiThreadedDebug + MultiThreaded + Guard + /ZH:SHA_256 /GUARD:CF %(AdditionalOptions) + /ZH:SHA_256 /GUARD:CF %(AdditionalOptions) + Level3 + Level3 + /ZH:SHA_256 /GUARD:CF %(AdditionalOptions) + /ZH:SHA_256 /GUARD:CF %(AdditionalOptions) + + + msi.lib;version.lib;%(AdditionalDependencies) + actions.def + Windows + true + /GUARD:CF %(AdditionalOptions) + + + + + + + + Create + + + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + \ No newline at end of file diff --git a/eng/CredScanSuppression.json b/eng/CredScanSuppression.json new file mode 100644 index 00000000000..994217b1706 --- /dev/null +++ b/eng/CredScanSuppression.json @@ -0,0 +1,12 @@ +{ + "tool": "Credential Scanner", + "suppressions": [ + { + "file": [ + "cli/azd/pkg/auth/testdata/certificate.pem", + "eng/common/testproxy/dotnet-devcert.pfx" + ], + "_justification": "File contains private key used by test code." + } + ] + } \ No newline at end of file diff --git a/eng/common/TestResources/New-TestResources.ps1 b/eng/common/TestResources/New-TestResources.ps1 index 76fbfc51a67..d60734dce1e 100644 --- a/eng/common/TestResources/New-TestResources.ps1 +++ b/eng/common/TestResources/New-TestResources.ps1 @@ -67,7 +67,7 @@ param ( [string] $Environment = 'AzureCloud', [Parameter()] - [ValidateSet('test', 'perf')] + [ValidateSet('test', 'perf', 'stress-test')] [string] $ResourceType = 'test', [Parameter()] @@ -196,14 +196,14 @@ function NewServicePrincipalWrapper([string]$subscription, [string]$resourceGrou # Submitting a password credential object without specifying a password will result in one being generated on the server side. $password = New-Object -TypeName "Microsoft.Azure.PowerShell.Cmdlets.Resources.MSGraph.Models.ApiV10.MicrosoftGraphPasswordCredential" $password.DisplayName = "Password for $displayName" - $credential = Retry { New-AzADSpCredential -PasswordCredentials $password -ServicePrincipalObject $servicePrincipal } + $credential = Retry { New-AzADSpCredential -PasswordCredentials $password -ServicePrincipalObject $servicePrincipal -ErrorAction 'Stop' } $spPassword = ConvertTo-SecureString $credential.SecretText -AsPlainText -Force $appId = $servicePrincipal.AppId } else { Write-Verbose "Creating service principal credential via MS Graph API" # In 5.2.0 the password credential issue was fixed (see https://github.com/Azure/azure-powershell/pull/16690) but the # parameter set was changed making the above call fail due to a missing ServicePrincipalId parameter. - $credential = Retry { $servicePrincipal | New-AzADSpCredential } + $credential = Retry { $servicePrincipal | New-AzADSpCredential -ErrorAction 'Stop' } $spPassword = ConvertTo-SecureString $credential.SecretText -AsPlainText -Force $appId = $servicePrincipal.AppId } @@ -1119,4 +1119,4 @@ Run this in an Azure DevOps CI (with approrpiate variables configured) before executing live tests. The script will output variables as secrets (to enable log redaction). -#> +#> \ No newline at end of file diff --git a/eng/pipelines/release-cli.yml b/eng/pipelines/release-cli.yml index 148102d4ecc..1745c5219b9 100644 --- a/eng/pipelines/release-cli.yml +++ b/eng/pipelines/release-cli.yml @@ -1,10 +1,3 @@ -resources: - repositories: - - repository: azure-sdk-build-tools - type: git - name: internal/azure-sdk-build-tools - ref: refs/tags/azure-sdk-build-tools_20240320.1 - # Continuous deployment trigger trigger: branches: @@ -24,1580 +17,16 @@ pr: - eng/pipelines/release-cli.yml - eng/pipelines/templates/steps/publish-cli.yml -variables: - - template: /eng/pipelines/templates/variables/globals.yml - -parameters: [] - -stages: - - stage: BuildAndTest - jobs: - - job: BuildCLI - strategy: - matrix: - Windows: - Pool: azsdk-pool-mms-win-2022-general - OSVmImage: MMS2022 - BuildTarget: azd-windows-amd64.exe - BuildOutputName: azd.exe - BuildTestMsi: true - AZURE_DEV_CI_OS: win - Codeql.Enabled: true - Codeql.SkipTaskAutoInjection: false - Codeql.BuildIdentifier: cli_windows - Linux: - Pool: azsdk-pool-mms-ubuntu-2004-general - OSVmImage: MMSUbuntu20.04 - BuildTarget: azd-linux-amd64 - BuildOutputName: azd - SetExecutableBit: true - SetShieldInfo: true - BuildLinuxPackages: true - AZURE_DEV_CI_OS: lin - Codeql.Enabled: true - Codeql.SkipTaskAutoInjection: false - Codeql.BuildIdentifier: cli_linux - Mac: - Pool: Azure Pipelines - OSVmImage: macOS-11 - BuildTarget: azd-darwin-amd64 - BuildOutputName: azd - MacLocalSign: false - SetExecutableBit: true - AZURE_DEV_CI_OS: mac - # CodeQL on macOS not supported by the Azure DevOps task as-of current. - # Codeql.BuildIdentifier: cli_darwin - pool: - name: $(Pool) - vmImage: $(OSVmImage) - timeoutInMinutes: 180 - steps: - - checkout: self - - template: /eng/pipelines/templates/steps/setup-go.yml - parameters: - Condition: and(succeeded(), ne(variables['Skip.LiveTest'], 'true')) - - - template: /eng/pipelines/templates/steps/set-cli-version-cd.yml - - - task: PowerShell@2 - inputs: - pwsh: true - targetType: filePath - filePath: eng/scripts/Set-CliVersionVariable.ps1 - displayName: Set CLI_VERSION - - - task: PowerShell@2 - inputs: - pwsh: true - targetType: filePath - filePath: eng/scripts/Set-CliBuildVariables.ps1 - arguments: -BuildReason $(Build.Reason) - displayName: Set CLI build run variables - - - task: PowerShell@2 - inputs: - pwsh: true - targetType: filePath - filePath: cli/azd/ci-build.ps1 - arguments: >- - -Version $(CLI_VERSION) - -SourceVersion $(Build.SourceVersion) - -CodeCoverageEnabled - -BuildRecordMode - workingDirectory: cli/azd - displayName: Build Go Binary (For tests) - - - template: /eng/pipelines/templates/steps/build-msi.yml - parameters: - Title: Build Test MSI - Condition: and(succeeded(), eq(variables['BuildTestMsi'], 'true')) - # Build the test MSI with the same configuration as the - # release MSI (no special upgrade behavior) - ShouldBuildForRelease: true - - - template: /eng/pipelines/templates/steps/install-terraform.yml - - template: /eng/pipelines/templates/steps/install-kubectl.yml - - # Pinning DockerInstaller to 0.209.0 because 0.214.0 has failures. - # Remove this pin when later versions succeed. - - task: DockerInstaller@0.209.0 - displayName: Docker Installer - condition: and(succeeded(), contains(variables['OSVmImage'], 'macOS')) - inputs: - dockerVersion: 17.09.0-ce - releaseType: stable - - # Live testing uses dotnet 8.0.x in the WebApp project deployment - - task: UseDotNet@2 - condition: and(succeeded(), ne(variables['Skip.LiveTest'], 'true')) - inputs: - version: 8.0.x - - - bash: dotnet nuget add source --name dotnet8 https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet8/nuget/v3/index.json - displayName: Add internal dotnet nuget feed - - - template: /eng/pipelines/templates/steps/az-login.yml - parameters: - Condition: and(succeeded(), ne(variables['Skip.LiveTest'], 'true')) - - - template: /eng/pipelines/templates/steps/azd-login.yml - parameters: - AzdDirectory: cli/azd - - - task: PowerShell@2 - condition: and(succeeded(), ne(variables['Skip.LiveTest'], 'true')) - inputs: - pwsh: true - targetType: filePath - filePath: cli/azd/ci-test.ps1 - arguments: >- - -UnitTestCoverageDir './cover-$(AZURE_DEV_CI_OS)/unit' - -IntegrationTestCoverageDir './cover-$(AZURE_DEV_CI_OS)/int' - workingDirectory: cli/azd - displayName: Test Go Binary - env: - # AZD live test setup variables - CI: true - AZD_TEST_CLI_VERSION: $(CLI_VERSION) - AZD_TEST_CLIENT_ID: $(arm-client-id) - AZD_TEST_CLIENT_SECRET: $(arm-client-secret) - AZD_TEST_TENANT_ID: $(arm-tenant-id) - AZD_TEST_AZURE_SUBSCRIPTION_ID: $(SubscriptionId) - AZD_TEST_AZURE_LOCATION: eastus2 - AZURE_RECORD_MODE: $(AZURE_RECORD_MODE) - # AZD Live Test: Terraform service principal authentication - ARM_CLIENT_ID: $(arm-client-id) - ARM_CLIENT_SECRET: $(arm-client-secret) - ARM_TENANT_ID: $(arm-tenant-id) - # Code Coverage: Generate junit report to publish results - GOTESTSUM_JUNITFILE: junitTestReport.xml - - - task: PublishTestResults@2 - inputs: - testResultsFormat: JUnit - testResultsFiles: '**/junitTestReport.xml' - testRunTitle: $(Agent.JobName) - searchFolder: cli/azd - publishRunAttachments: true - displayName: Publish test results - condition: succeededOrFailed() - - - task: PowerShell@2 - inputs: - pwsh: true - targetType: filePath - filePath: cli/azd/ci-build.ps1 - arguments: >- - -Version $(CLI_VERSION) - -SourceVersion $(Build.SourceVersion) - workingDirectory: cli/azd - displayName: Build Go Binary - - - pwsh: Move-Item $(BuildOutputName) $(BuildTarget) - workingDirectory: cli/azd - displayName: Rename binaries - - - bash: chmod +x $(BuildTarget) - condition: and(succeeded(), eq(variables['SetExecutableBit'], 'true')) - workingDirectory: cli/azd - displayName: Set executable bit for non-Windows binaries - - - template: /eng/pipelines/templates/steps/build-linux-packages.yml - parameters: - Condition: and(succeeded(), eq(variables['BuildLinuxPackages'], 'true')) - - - task: PowerShell@2 - condition: and(succeeded(), eq(variables['SetShieldInfo'], 'true')) - inputs: - pwsh: true - targetType: filePath - filePath: eng/scripts/Set-ShieldInfo.ps1 - arguments: >- - -TemplatePath eng/shields/standalone.json - -Version "$(CLI_VERSION)" - displayName: Set shield info - - - publish: cli/azd/cover-$(AZURE_DEV_CI_OS) - condition: and(succeeded(), ne(variables['Skip.LiveTest'], 'true')) - artifact: cover-$(AZURE_DEV_CI_OS) - displayName: Upload code coverage - - - publish: eng/shields/standalone.json - condition: and(succeeded(), eq(variables['SetShieldInfo'], 'true')) - artifact: shield-standalone - displayName: Upload standalone shield json - - - publish: cli/azd/$(BuildTarget) - artifact: $(BuildTarget) - condition: always() - displayName: Upload azd binary to artifact store - - - publish: cli/installer/windows/bin/Release - artifact: test-msi - condition: and(succeeded(), eq(variables['BuildTestMsi'], 'true')) - displayName: Upload test MSI - - - publish: cli/installer/fpm/artifact - artifact: linux-packages-amd64 - condition: and(succeeded(), eq(variables['BuildLinuxPackages'], 'true')) - displayName: Upload linux packages to artifact store - - # This is separated today because Skip.LiveTest is a queue-time variable - # and cannot be set in a matrix entry. - - job: CrossBuildCLI - strategy: - matrix: - LinuxARM64: - Pool: azsdk-pool-mms-ubuntu-2004-general - OSVmImage: MMSUbuntu20.04 - BuildTarget: azd-linux-arm64 - BuildOutputName: azd - SetExecutableBit: true - GOOS: linux - GOARCH: arm64 - BuildLinuxPackages: true - MacARM64: - Pool: Azure Pipelines - OSVmImage: macOS-11 - BuildTarget: azd-darwin-arm64 - BuildOutputName: azd - SetExecutableBit: true - GOOS: darwin - GOARCH: arm64 - # CGO_ENABLED is required on MacOS to cross-compile pkg/outil/osversion - CGO_ENABLED: 1 - pool: - name: $(Pool) - vmImage: $(OSVmImage) - timeoutInMinutes: 20 - steps: - - checkout: self - - - template: /eng/pipelines/templates/steps/setup-go.yml - parameters: - Condition: false - - - template: /eng/pipelines/templates/steps/set-cli-version-cd.yml - - - task: PowerShell@2 - inputs: - pwsh: true - targetType: filePath - filePath: eng/scripts/Set-CliVersionVariable.ps1 - displayName: Set CLI_VERSION - - - task: PowerShell@2 - inputs: - pwsh: true - targetType: filePath - filePath: cli/azd/ci-build.ps1 - arguments: >- - -Version $(CLI_VERSION) - -SourceVersion $(Build.SourceVersion) - workingDirectory: cli/azd - displayName: Build Go Binary (cross compile) - - - pwsh: file azd - workingDirectory: cli/azd - displayName: Get file info - - - pwsh: Move-Item $(BuildOutputName) $(BuildTarget) - workingDirectory: cli/azd - displayName: Rename binaries - - - bash: chmod +x $(BuildTarget) - condition: and(succeeded(), eq(variables['SetExecutableBit'], 'true')) - workingDirectory: cli/azd - displayName: Set executable bit for non-Windows binaries - - - template: /eng/pipelines/templates/steps/build-linux-packages.yml - parameters: - Architecture: arm64 - Condition: and(succeeded(), eq(variables['BuildLinuxPackages'], 'true')) - - - publish: cli/azd/$(BuildTarget) - artifact: $(BuildTarget) - condition: always() - displayName: Upload azd binary to artifact store - - - publish: cli/installer/fpm/artifact - artifact: linux-packages-arm64 - condition: and(succeeded(), eq(variables['BuildLinuxPackages'], 'true')) - displayName: Upload linux packages to artifact store - - - job: MergeLinuxPackages - pool: - name: azsdk-pool-mms-ubuntu-2004-general - dependsOn: - - CrossBuildCLI - - BuildCLI - steps: - - download: current - artifact: linux-packages-amd64 - displayName: Download linux-packages-amd64 - - - download: current - artifact: linux-packages-arm64 - displayName: Download linux-packages-arm64 - - # Merge the folders - - pwsh: | - New-Item -ItemType Directory -Path linux-packages - Get-ChildItem $(Pipeline.Workspace)/linux-packages-amd64 | ForEach-Object { Copy-Item $_ linux-packages } - Get-ChildItem $(Pipeline.Workspace)/linux-packages-arm64 | ForEach-Object { Copy-Item $_ linux-packages } - displayName: Merge linux packages - - - publish: linux-packages - artifact: linux-packages - displayName: Publish merged linux packages - - - job: ValidateCrossCompile - dependsOn: CrossBuildCLI - pool: - name: azsdk-pool-mms-ubuntu-2004-arm - vmImage: MMSUbuntu20.04ARM64 - timeoutInMinutes: 5 - steps: - - checkout: none - - - task: DownloadPipelineArtifact@2 - inputs: - artifact: azd-linux-arm64 - targetPath: $(Build.SourcesDirectory) - - - bash: pwd && ls && chmod +x ./azd-linux-arm64 && ./azd-linux-arm64 version - displayName: azd version - - - job: GenerateReleaseArtifacts - pool: - name: azsdk-pool-mms-ubuntu-2004-general - vmImage: MMSUbuntu20.04 - - steps: - - checkout: self - - - template: /eng/pipelines/templates/steps/setup-go.yml - - # Install scripts - - pwsh: | - New-Item -ItemType Directory -Path installer - Copy-Item cli/installer/*install-azd.ps1 installer/ - displayName: Copy installer scripts (*.ps1) for artifact upload - - - task: PublishPipelineArtifact@1 - displayName: Publish install scripts to artifacts for signing - inputs: - artifactName: install-pwsh - targetPath: installer - - # CLI ref docs - - pwsh: New-Item -ItemType Directory -Path docs - workingDirectory: $(Pipeline.Workspace) - displayName: Create docs artifact folder - - - pwsh: go run docgen.go - workingDirectory: cli/azd/docs - displayName: Generate CLI documentation - - - pwsh: Copy-Item $(Build.SourcesDirectory)/cli/azd/docs/md/* docs/ -Recurse - workingDirectory: $(Pipeline.Workspace) - displayName: Copy CLI docs for pipeline artifact staging - - # azure.yaml.json schema docs - - task: UsePythonVersion@0 - inputs: - versionSpec: 3.x - - - pwsh: pip install jsonschema2md - displayName: Install jsonschema2md - - - pwsh: jsonschema2md schemas/v1.0/azure.yaml.json $(Pipeline.Workspace)/docs/azure.yaml.schema.md - displayName: Generate azure.yaml schema - - # Upload docs for CLI ref and azure.yaml schema - - pwsh: Get-ChildItem . - workingDirectory: $(Pipeline.Workspace)/docs - displayName: Show doc artifacts to publish - - - publish: $(Pipeline.Workspace)/docs/ - artifact: docs - displayName: Upload generated documentation - - - stage: CodeCoverage_Upload - condition: and(succeeded(), ne(variables['Skip.LiveTest'], 'true')) - dependsOn: BuildAndTest - jobs: - - job: Upload - pool: - name: azsdk-pool-mms-ubuntu-2004-general - vmImage: MMSUbuntu20.04 - steps: - - template: /eng/pipelines/templates/steps/setup-go.yml - - template: /eng/pipelines/templates/steps/download-artifacts.yml - parameters: - Artifacts: - - cover-win - - cover-lin - - cover-mac - - pwsh: | - New-Item -ItemType Directory -Force -Path cover - New-Item -ItemType Directory -Force -Path cover-int - New-Item -ItemType Directory -Force -Path cover-unit - - $unitCoverage = (Get-ChildItem cover-*/unit).FullName -join "," - $integrationCoverage = (Get-ChildItem cover-*/int).FullName -join "," - - # Merge unit test coverage across platforms - go tool covdata merge -i="$unitCoverage" -o cover-unit - if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } - - # Merge integration test coverage across platforms - go tool covdata merge -i="$integrationCoverage" -o cover-int - if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } - - # Merge unit and integration code coverage - go tool covdata merge -i="cover-unit,cover-int" -o cover - if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } - - # Convert to text format - go tool covdata textfmt -i=cover -o cover.out - if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } - - go install github.com/axw/gocov/gocov@latest - if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } - go install github.com/AlekSi/gocov-xml@latest - if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } - - ~/go/bin/gocov convert cover.out | ~/go/bin/gocov-xml > coverage.xml - if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } - displayName: Merge code coverage files - - - publish: cover-unit - artifact: cover-unit - displayName: Upload unit test code coverage - - - publish: cover-int - artifact: cover-int - displayName: Upload integration test code coverage - - - task: PublishCodeCoverageResults@1 - inputs: - codeCoverageTool: Cobertura - summaryFileLocation: '$(Build.SourcesDirectory)/**/coverage.xml' - displayName: Publish Code Coverage to DevOps - - - stage: Sign - dependsOn: BuildAndTest - jobs: - - - job: SignMac - pool: - name: azsdk-pool-mms-win-2022-general - vmImage: MMS2022 - - steps: - - task: DownloadPipelineArtifact@2 - inputs: - artifact: azd-darwin-amd64 - path: mac-artifacts - - - task: DownloadPipelineArtifact@2 - inputs: - artifact: azd-darwin-arm64 - path: mac-artifacts - - - pwsh: | - New-Item -ItemType Directory -Path mac - - Compress-Archive ` - -Path mac-artifacts/azd-darwin-amd64 ` - -DestinationPath mac/azd-darwin-amd64.zip - - Compress-Archive ` - -Path mac-artifacts/azd-darwin-arm64 ` - -DestinationPath mac/azd-darwin-arm64.zip - displayName: Package mac binary for signing - - - ${{ if and(in(variables['Build.Reason'], 'IndividualCI', 'BatchedCI', 'Manual'), eq(variables['Build.Repository.Name'], 'Azure/azure-dev')) }}: - - template: pipelines/steps/azd-cli-mac-signing.yml@azure-sdk-build-tools - parameters: - MacPath: mac - - - ${{ else }}: - - pwsh: Write-Host "Skipping signing. Build reason - $(Build.Reason)" - displayName: Signing process skipped for non-release build - - - pwsh: | - Expand-Archive -Path mac/azd-darwin-amd64.zip -DestinationPath mac/ - Expand-Archive -Path mac/azd-darwin-arm64.zip -DestinationPath mac/ - - Remove-Item mac/azd-darwin-amd64.zip - Remove-Item mac/azd-darwin-arm64.zip - displayName: Extract azd-darwin-amd64 from zip and remove zip - - - pwsh: | - New-Item -ItemType Directory -Path signed-mac - Copy-Item mac/* signed-mac/ -Recurse - displayName: Copy signing outputs - condition: always() - - # TODO: Replace with https://github.com/Azure/azure-sdk-tools/blob/main/eng/common/pipelines/templates/steps/publish-artifact.yml - # when the common engsys is imported. - # https://github.com/Azure/azure-dev/issues/956 - - task: PublishPipelineArtifact@1 - condition: succeeded() - displayName: Publish Signed Artifacts - inputs: - artifactName: signed-mac - path: signed-mac/ - - - task: PublishPipelineArtifact@1 - condition: failed() - displayName: Publish failed Signed Artifacts - inputs: - artifactName: signed-mac-FailedAttempt$(System.JobAttempt) - path: signed-mac/ - - - job: SignWindows - pool: - name: azsdk-pool-mms-win-2022-general - vmImage: MMS2022 - - steps: - # Checkout required to build MSI - - checkout: self - - - task: DownloadPipelineArtifact@2 - inputs: - artifact: azd-windows-amd64.exe - path: win - - - task: DownloadPipelineArtifact@2 - inputs: - artifact: install-pwsh - path: installer - - - pwsh: Copy-Item installer/*.ps1 win - displayName: Copy install scripts to win/ - - - ${{ if and(in(variables['Build.Reason'], 'IndividualCI', 'BatchedCI', 'Manual'), eq(variables['Build.Repository.Name'], 'Azure/azure-dev')) }}: - - template: pipelines/steps/azd-cli-win-signing.yml@azure-sdk-build-tools - parameters: - WinPath: win - WinPattern: '**' - - - ${{ else }}: - - pwsh: Write-Host "Skipping signing. Build reason - $(Build.Reason)" - displayName: Signing process skipped for non-release build - - - pwsh: | - New-Item -ItemType Directory -Path signed-win - Copy-Item win/* signed-win/ -Recurse - Copy-Item win/azd-windows-amd64.exe cli/azd/azd.exe - displayName: Copy signing outputs for publishing and MSI build - condition: always() - - - task: PowerShell@2 - inputs: - pwsh: true - targetType: filePath - filePath: eng/scripts/Set-CliVersionVariable.ps1 - displayName: Set CLI_VERSION for MSI build - - - template: /eng/pipelines/templates/steps/build-msi.yml - parameters: - Title: Build Release MSI - # Only build for release in a manual (releasing) build. Otherwise - # the package version will be 0.1.0 with upgrade logic that allows - # it to be installed over any previously installed version. - ShouldBuildForRelease: ${{ eq(variables['Build.Reason'], 'Manual') }} - - - ${{ if and(in(variables['Build.Reason'], 'IndividualCI', 'BatchedCI', 'Manual'), eq(variables['Build.Repository.Name'], 'Azure/azure-dev')) }}: - - template: pipelines/steps/azd-cli-win-signing.yml@azure-sdk-build-tools - parameters: - WinPath: cli/installer/windows/bin/Release - WinPattern: '*.msi' - - - ${{ else }}: - - pwsh: Write-Host "Skipping signing. Build reason - $(Build.Reason)" - displayName: Signing process skipped for non-release build - - - pwsh: Copy-Item cli/installer/windows/bin/Release/* signed-win/ - displayName: Copy MSI for publishing - - # TODO: Replace with https://github.com/Azure/azure-sdk-tools/blob/main/eng/common/pipelines/templates/steps/publish-artifact.yml - # when the common engsys is imported. - # https://github.com/Azure/azure-dev/issues/956 - - task: PublishPipelineArtifact@1 - condition: succeeded() - displayName: Publish Signed Artifacts - inputs: - artifactName: signed-win - path: signed-win/ - - - task: PublishPipelineArtifact@1 - condition: failed() - displayName: Publish failed Signed Artifacts - inputs: - artifactName: signed-win-FailedAttempt$(System.JobAttempt) - path: signed-win/ - - - job: SignLinux - pool: - name: azsdk-pool-mms-win-2022-general - vmImage: MMS2022 - - steps: - - task: DownloadPipelineArtifact@2 - inputs: - artifact: linux-packages - path: linux - - - ${{ if and(in(variables['Build.Reason'], 'IndividualCI', 'BatchedCI', 'Manual'), eq(variables['Build.Repository.Name'], 'Azure/azure-dev')) }}: - - template: pipelines/steps/azd-cli-linux-signing.yml@azure-sdk-build-tools - parameters: - LinuxPath: linux - - - ${{ else }}: - - pwsh: Write-Host "Skipping signing. Build reason - $(Build.Reason)" - displayName: Signing process skipped for non-release build - - - pwsh: | - New-Item -ItemType Directory -Path signed-linux - Copy-Item linux/* signed-linux/ -Recurse - displayName: Copy signing outputs - condition: always() - - - task: PublishPipelineArtifact@1 - condition: succeeded() - displayName: Publish Signed Artifacts - inputs: - artifactName: signed-linux - path: signed-linux/ - - - task: PublishPipelineArtifact@1 - condition: failed() - displayName: Publish failed Signed Artifacts - inputs: - artifactName: signed-linux-FailedAttempt$(System.JobAttempt) - path: signed-linux/ - - - - stage: Verify_Installers - condition: and(succeeded(), ne(variables['Skip.VerifyInstallers'], 'true')) - dependsOn: BuildAndTest - jobs: - - job: Compress_For_Hosting - pool: - name: azsdk-pool-mms-ubuntu-2004-general - vmImage: MMSUbuntu20.04 - - steps: - - checkout: self - - - task: DownloadPipelineArtifact@2 - inputs: - artifact: azd-windows-amd64.exe - path: azd-windows-amd64.exe - - - task: DownloadPipelineArtifact@2 - inputs: - artifact: azd-linux-amd64 - path: azd-linux-amd64 - - - task: DownloadPipelineArtifact@2 - inputs: - artifact: azd-darwin-amd64 - path: azd-darwin-amd64 - - - task: DownloadPipelineArtifact@2 - inputs: - artifact: test-msi - path: msi - - - pwsh: | - Write-Host "Moving downloaded files to hosting folder" - New-Item -ItemType Directory -Path hosting - - Write-Host "Compressing artifacts as if publishing" - zip hosting/azd-windows-amd64.zip -j azd-windows-amd64.exe/azd-windows-amd64.exe - - chmod +x azd-darwin-amd64/azd-darwin-amd64 - zip hosting/azd-darwin-amd64.zip -j azd-darwin-amd64/azd-darwin-amd64 - - chmod +x azd-linux-amd64/azd-linux-amd64 - tar -C azd-linux-amd64 -cvzf hosting/azd-linux-amd64.tar.gz azd-linux-amd64 - - Copy-Item msi/azd-windows-amd64.msi hosting/ - - Copy-Item cli/installer/*stall-azd.* hosting/ - - Get-ChildItem hosting/ -Recurse | Select-Object -Property Name,Size - displayName: Move folders to hosting location - - - publish: hosting - artifact: test-hosting - - - job: Verify_MSI - dependsOn: Compress_For_Hosting - pool: azsdk-pool-mms-win-2022-general - variables: - AZURE_DEV_COLLECT_TELEMETRY: no - strategy: - matrix: - PerUser: - PerMachine: $false - AllUsers: - PerMachine: $true - steps: - - checkout: self - - - task: DownloadPipelineArtifact@2 - inputs: - artifact: test-msi - path: msi - - - task: PowerShell@2 - inputs: - pwsh: true - targetType: filePath - filePath: cli/installer/windows/test-win-msi.ps1 - arguments: >- - -PerMachine:$(PerMachine) - -MsiPath msi/azd-windows-amd64.msi - # Do not exit on first Write-Error, write all messages and let the - # script handle exiting with an error status. - errorActionPreference: continue - displayName: Test MSI - - - job: Verify_Mac_InstallOver - dependsOn: Compress_For_Hosting - pool: - name: Azure Pipelines - vmImage: macOS-12 - - steps: - - checkout: self - - - bash: ./install-azd.sh --version daily --verbose - displayName: Install "daily" version - workingDirectory: cli/installer/ - - - pwsh: azd version - displayName: Run azd version - - - bash: ./install-azd.sh --version latest --verbose - displayName: Install "latest" version - workingDirectory: cli/installer/ - - - pwsh: azd version - displayName: Run azd version (expect no failure) - - - job: Verify_Installers - dependsOn: Compress_For_Hosting - strategy: - matrix: - LinuxDockerSh: - Pool: azsdk-pool-mms-ubuntu-2004-general - OSVmImage: MMSUbuntu20.04 - TestShell: pwsh - TestInstallCommand: > - ./test-installer-containers.ps1 - -BaseUrl "http://host.docker.internal:8080" - -Version '' - -ContainerPrefix '$(docker-mirror-tag-prefix)/' - -AdditionalRunArgs '--add-host=host.docker.internal:host-gateway' - LinuxSh: - Pool: azsdk-pool-mms-ubuntu-2004-general - OSVmImage: MMSUbuntu20.04 - TestShell: bash - TestInstallCommand: > - ./test-sh-install.sh "bash" "$BASEURL" "" && - ./test-telemetry-functions.sh "telemetry/linux.sh.telemetry.csv" && - ./test-sh-install-errors.sh "bash" "$BASEURL" "" - LinuxPwsh: - Pool: azsdk-pool-mms-ubuntu-2004-general - OSVmImage: MMSUbuntu20.04 - TestShell: pwsh - TestInstallCommand: > - ./test-pwsh-xplat-install.ps1 - -BaseUrl $env:BASEURL - -Version '' - -InstallShScriptUrl "$($env:BASEURL)/install-azd.sh" - -UninstallShScriptUrl "$($env:BASEURL)/uninstall-azd.sh"; - ./test-telemetry-functions.ps1 -NonInteractive -Shell pwsh -ExpectedFieldMap telemetry/linux.telemetry.json - - Mac11Sh: - Pool: Azure Pipelines - OSVmImage: macOS-11 - TestShell: bash - TestInstallCommand: > - ./test-sh-install.sh "bash" "$BASEURL" "" && - ./test-telemetry-functions.sh "telemetry/macos11.sh.telemetry.csv" && - ./test-sh-install-errors.sh "bash" "$BASEURL" "" - Mac12Sh: - Pool: Azure Pipelines - OSVmImage: macOS-12 - TestShell: bash - TestInstallCommand: > - ./test-sh-install.sh "bash" "$BASEURL" "" && - ./test-telemetry-functions.sh "telemetry/macos12.sh.telemetry.csv" && - ./test-sh-install-errors.sh "bash" "$BASEURL" "" - Mac12Pwsh: - Pool: Azure Pipelines - OSVmImage: macOS-12 - TestShell: pwsh - # Should also test telemetry functions but cannot because of macOS - # host limitations in DevOps which do not reproduce on non-DevOps - # macs. Disabled for now. - # ./test-telemetry-functions.ps1 -Shell pwsh -ExpectedFieldMap telemetry/macos.telemetry.json - TestInstallCommand: > - ./test-pwsh-xplat-install.ps1 - -BaseUrl $env:BASEURL - -Version '' - -InstallShScriptUrl "$($env:BASEURL)/install-azd.sh" - -UninstallShScriptUrl "$($env:BASEURL)/uninstall-azd.sh" - Mac11Pwsh: - Pool: Azure Pipelines - OSVmImage: macOS-11 - TestShell: pwsh - # Should also test telemetry functions but cannot because of macOS - # host limitations in DevOps which do not reproduce on non-DevOps - # macs. Disabled for now. - # ./test-telemetry-functions.ps1 -Shell pwsh -ExpectedFieldMap telemetry/macos.telemetry.json - TestInstallCommand: > - ./test-pwsh-xplat-install.ps1 - -BaseUrl $env:BASEURL - -Version '' - -InstallShScriptUrl "$($env:BASEURL)/install-azd.sh" - -UninstallShScriptUrl "$($env:BASEURL)/uninstall-azd.sh" - WindowsCmd: - Pool: azsdk-pool-mms-win-2022-general - OSVmImage: MMS2022 - TestShell: cmd - TestInstallCommand: cmd /c test-windows-install.cmd %BASEURL% - WindowsPwsh: - Pool: azsdk-pool-mms-win-2022-general - OSVmImage: MMS2022 - TestShell: pwsh - TestInstallCommand: > - $ErrorActionPreference = 'Stop'; - ./test-win-install.ps1 -BaseUrl $env:BASEURL -Version ''; - ./test-telemetry-functions.ps1 -Shell pwsh -ExpectedFieldMap telemetry/windows.pwsh.telemetry.json - WindowsPowerShell: - Pool: azsdk-pool-mms-win-2022-general - OSVmImage: MMS2022 - TestShell: powershell - TestInstallCommand: > - $ErrorActionPreference = 'Stop'; - ./test-win-install.ps1 -BaseUrl $env:BASEURL -Version ''; - ./test-telemetry-functions.ps1 -Shell powershell -ExpectedFieldMap telemetry/windows.powershell.telemetry.json - - pool: - name: $(Pool) - vmImage: $(OSVmImage) - - variables: - BaseUrl: http://127.0.0.1:8080 - - timeoutInMinutes: 10 - - steps: - - checkout: self - - - task: DownloadPipelineArtifact@2 - inputs: - artifact: test-hosting - path: hosting - - - bash: ls - workingDirectory: hosting - - - bash: | - unzip ./azd-darwin-amd64.zip -d ./tmp - - # Ad-hoc signing with "-" identity - codesign -s - tmp/azd-darwin-amd64 - - zip azd-darwin-amd64.zip -j tmp/azd-darwin-amd64 - displayName: Self-sign (Darwin) - condition: and(succeeded(), contains(variables['Agent.OS'], 'Darwin')) - workingDirectory: hosting - - - pwsh: | - $ErrorActionPreference = 'Stop' - - # Generate self-sign cert - $cert = New-SelfSignedCertificate -CertStoreLocation Cert:\LocalMachine\My -Type CodeSigningCert -Subject "azd installer tests code signing" - - # Add as temporary trusted root CA - try { - Export-Certificate -Cert $cert -FilePath code_signing.crt - Import-Certificate -FilePath .\code_signing.crt -Cert Cert:\LocalMachine\Root - } - finally { - Remove-Item -Force .\code_signing.crt -ErrorAction SilentlyContinue - } - - # Sign the windows binary - Set-AuthenticodeSignature .\azd-windows-amd64.msi -Certificate $cert - displayName: Self-sign (Windows) - condition: and(succeeded(), contains(variables['Agent.OS'], 'Windows')) - workingDirectory: hosting - - - bash: nohup npx -y http-server & - displayName: Start server in hosting/ (bash) - condition: and(succeeded(), not(contains(variables['Agent.OS'], 'Windows'))) - workingDirectory: hosting - - - pwsh: | - Start-Process npx.cmd ` - -ArgumentList @('-y', 'http-server') ` - -NoNewWindow ` - -PassThru ` - -RedirectStandardOutput ../server.log - Write-Host "Server started, waiting for server to initialize" - Start-Sleep -Seconds 15 - displayName: Start server in hosting/ (pwsh) - condition: and(succeeded(), contains(variables['Agent.OS'], 'Windows')) - workingDirectory: hosting - - - pwsh: | - $tmpFile = New-TemporaryFile - $timer = [Diagnostics.Stopwatch]::StartNew() - $MAX_ELAPSED_SECONDS = 120 - $TIMEOUT_SECONDS = 12 - $SLEEP_SECONDS = 1 - - while ($timer.Elapsed.TotalSeconds -lt $MAX_ELAPSED_SECONDS) { - try { - Write-Host "Downloading file..." - Invoke-WebRequest ` - $(BaseUrl)/azd-windows-amd64.zip ` - -OutFile $tmpFile ` - -TimeoutSec $TIMEOUT_SECONDS - - if ($LASTEXITCODE) { - throw "Failed downloading file" - } - } catch { - Write-Host "Error downloading file." - Write-Host $_ - Start-Sleep -Seconds $SLEEP_SECONDS - continue - } - - # Exit if the downloaded file size is less than a small threshold - # this could mean an error in how the files are being served. - if ((Get-Item $tmpFile).Length -le 100000) { - Get-Content $tmpFile - exit 1 - } - - break - } - - Get-Item $tmpFile | Select-Object -Property Name,Length - displayName: Verify installer hosting - - - pwsh: $(TestInstallCommand) - condition: and(succeeded(), eq('pwsh', variables['TestShell'])) - workingDirectory: cli/installer/ - displayName: Test install script (pwsh) - - - powershell: $(TestInstallCommand) - condition: and(succeeded(), eq('powershell', variables['TestShell'])) - workingDirectory: cli/installer/ - displayName: Test install script (PowerShell) - - - bash: $(TestInstallCommand) - condition: and(succeeded(), eq('bash', variables['TestShell'])) - workingDirectory: cli/installer/ - displayName: Test install script (bash) - - - task: CmdLine@2 - condition: and(succeeded(), eq('cmd', variables['TestShell'])) - inputs: - script: $(TestInstallCommand) - workingDirectory: cli/installer/ - displayName: Test install script (cmd) - - - pwsh: | - Get-ChildItem Cert:\LocalMachine\My | ForEach-Object { - if ($_.Subject -match "azd installer tests code signing") { - Write-Host "Deleting $($_.PSPath) - $($_.Subject)" - Remove-Item -Force $_.PSPath - } - } - - Get-ChildItem Cert:\LocalMachine\Root | ForEach-Object { - if ($_.Subject -match "azd installer tests code signing") { - Write-Host "Deleting $($_.PSPath) - $($_.Subject)" - Remove-Item -Force $_.PSPath - } - } - displayName: Clean up self-signed certificates (Windows) - condition: contains(variables['Agent.OS'], 'Windows') - workingDirectory: hosting - - - job: Verify_LinuxPackages - - strategy: - matrix: - LinuxAMD64: - Pool: azsdk-pool-mms-ubuntu-2004-general - OSVmImage: MMSUbuntu20.04 - Architecture: amd64 - # TODO: When Docker can be installed and run properly on the ARM - # host this can be used to validate the ARM64 Linux packages. - # https://github.com/Azure/azure-dev/issues/2617 - # LinuxARM64: - # Pool: azsdk-pool-mms-ubuntu-2004-arm - # OSVmImage: MMSUbuntu20.04ARM64 - # Architecture: arm64 - - pool: - name: $(Pool) - vmImage: $(OSVmImage) - - steps: - - checkout: self - - - task: DownloadPipelineArtifact@2 - inputs: - artifact: linux-packages-$(Architecture) - path: cli/installer/fpm - - - task: PowerShell@2 - displayName: Verify Linux Packages - inputs: - pwsh: true - workingDirectory: cli/installer/fpm - filePath: eng/scripts/Test-LinuxPackages.ps1 - arguments: -DockerImagePrefix "$(docker-mirror-tag-prefix)/" - - - ${{ if eq(variables['Build.Repository.Name'], 'Azure/azure-dev') }}: - - stage: PublishCLI - dependsOn: Sign - condition: >- - and( - succeeded(), - ne(variables['Skip.Release'], 'true'), - or( - eq('Manual', variables['BuildReasonOverride']), - and( - eq('', variables['BuildReasonOverride']), - eq('Manual', variables['Build.Reason']) - ) - ) - ) - jobs: - - deployment: Publish_Release - condition: >- - and( - succeeded(), - ne('true', variables['Skip.Publish']) - ) - environment: azure-dev - - pool: - name: azsdk-pool-mms-ubuntu-2004-general - OSVmImage: MMSUbuntu20.04 - - strategy: - runOnce: - deploy: - steps: - - checkout: self - - task: PowerShell@2 - inputs: - pwsh: true - targetType: filePath - filePath: eng/scripts/Set-CliVersionVariable.ps1 - displayName: Set CLI_VERSION - - - pwsh: | - # Initial upload locations - $publishUploadLocations = 'release/$(CLI_VERSION);release/latest' - - $isPublishingGa = eng/scripts/Test-ShouldReleasePackageVersion.ps1 ` - -CliVersion '$(CLI_VERSION)' - - if ($isPublishingGa) { - $publishUploadLocations += ";release/stable" - } - - Write-Host "Setting StorageUploadLocations to $publishUploadLocations" - Write-Host "###vso[task.setvariable variable=StorageUploadLocations]$publishUploadLocations" - displayName: Set StorageUploadLocations - - - pwsh: | - # Initial tag - $dockerTags = '$(CLI_VERSION)' - - $isPublishingGa = eng/scripts/Test-ShouldReleasePackageVersion.ps1 ` - -CliVersion '$(CLI_VERSION)' - - if ($isPublishingGa) { - $dockerTags += ";latest" - } - - Write-Host "Setting DockerImageTags to $dockerTags" - Write-Host "###vso[task.setvariable variable=DockerImageTags]$dockerTags" - displayName: Set DockerImageTags - - - template: /eng/pipelines/templates/steps/publish-cli.yml - parameters: - CreateGitHubRelease: true - PublishUploadLocations: $(StorageUploadLocations) - PublishShield: true - DockerImageTags: $(DockerImageTags) - ReleaseSyndicatedDockerContainer: true - PublishUpdatedDocs: true - UploadMsi: true - PublishBrewFormula: true - PublishArm64Binaries: true - - - deployment: Publish_Choco - dependsOn: Publish_Release - condition: >- - and( - succeeded(), - ne('true', variables['Skip.Publish']) - ) - environment: azure-dev - - pool: - name: azsdk-pool-mms-win-2022-general - - strategy: - runOnce: - deploy: - steps: - - checkout: self - - task: PowerShell@2 - inputs: - pwsh: true - targetType: filePath - filePath: eng/scripts/Set-CliVersionVariable.ps1 - displayName: Set CLI_VERSION - - - template: /eng/pipelines/templates/steps/publish-cli-choco.yml - parameters: - CliVersion: $(CLI_VERSION) - - - deployment: Publish_WinGet - dependsOn: Publish_Release - condition: >- - and( - succeeded(), - ne('true', variables['Skip.Publish']) - ) - environment: azure-dev - - pool: - name: azsdk-pool-mms-win-2022-general - - strategy: - runOnce: - deploy: - steps: - - checkout: self - - task: PowerShell@2 - inputs: - pwsh: true - targetType: filePath - filePath: eng/scripts/Set-CliVersionVariable.ps1 - displayName: Set CLI_VERSION - - - template: /eng/pipelines/templates/steps/publish-cli-winget.yml - parameters: - CliVersion: $(CLI_VERSION) - - - deployment: Increment_Version - condition: >- - and( - succeeded(), - ne('true', variables['Skip.IncrementVersion']) - ) - dependsOn: Publish_Release - environment: azure-dev - - pool: - name: azsdk-pool-mms-ubuntu-2004-general - OSVmImage: MMSUbuntu20.04 - - strategy: - runOnce: - deploy: - steps: - - checkout: self - - - task: PowerShell@2 - inputs: - pwsh: true - targetType: filePath - filePath: eng/scripts/Update-CliVersion.ps1 - displayName: Increment CLI version - - - template: /eng/common/pipelines/templates/steps/create-pull-request.yml - parameters: - PRBranchName: cli-version-increment-$(Build.BuildId) - CommitMsg: Increment CLI version after release - PRTitle: Increment CLI version after release - - - stage: PublishVersionTxt - dependsOn: PublishCLI - - condition: >- - and( - succeeded(), - ne(variables['Skip.Release'], 'true'), - or( - eq('Manual', variables['BuildReasonOverride']), - and( - eq('', variables['BuildReasonOverride']), - eq('Manual', variables['Build.Reason']) - ) - ) - ) - - jobs: - - deployment: Upload_Version_Txt - condition: >- - and( - succeeded(), - ne('true', variables['Skip.Publish']) - ) - environment: azure-dev - - pool: - name: azsdk-pool-mms-win-2022-general - - strategy: - runOnce: - deploy: - steps: - - checkout: self - - task: PowerShell@2 - inputs: - pwsh: true - targetType: filePath - filePath: eng/scripts/Set-CliVersionVariable.ps1 - displayName: Set CLI_VERSION - - - task: PowerShell@2 - displayName: Set MSI_VERSION - inputs: - pwsh: true - targetType: filePath - filePath: eng/scripts/Get-MsiVersion.ps1 - arguments: >- - -CliVersion '$(CLI_VERSION)' - -DevOpsOutput - - - task: PowerShell@2 - displayName: Wait for WinGet package - inputs: - pwsh: true - targetType: filePath - filePath: eng/scripts/Wait-WinGetPackage.ps1 - arguments: >- - -PackageName 'Microsoft.Azd' - -PackageVersion '$(MSI_VERSION)' - - - task: PowerShell@2 - displayName: Wait for Choco package - inputs: - pwsh: true - targetType: filePath - filePath: eng/scripts/Wait-ChocoPackage.ps1 - arguments: >- - -PackageName 'azd' - -PackageVersion '$(MSI_VERSION)' - - - pwsh: | - New-Item -ItemType Directory -Path release - Write-Output $(CLI_VERSION) | Out-File -Encoding utf8 -FilePath ./release/version.txt - displayName: Write version.txt file for release - - - pwsh: | - $isPublishingGa = eng/scripts/Test-ShouldReleasePackageVersion.ps1 ` - -CliVersion '$(CLI_VERSION)' - - $publishUploadLocations = @('release/latest') - if ($isPublishingGa) { - $publishUploadLocations += @('release/stable') - } - - Get-ChildItem release/ - - foreach ($folder in $publishUploadLocations) { - Write-Host "Upload to azd/standalone/$folder" - az storage blob upload-batch ` - --account-name '$(azdev-storage-account-name)' ` - --account-key '$(azdev-storage-account-key)' ` - --auth-mode key ` - -s release/ ` - -d "azd/standalone/$folder" ` - --overwrite - - if ($LASTEXITCODE) { - Write-Error "Upload failed" - exit 1 - } - } - displayName: Upload version.txt to storage account - - - stage: Publish_Integration - dependsOn: Sign - jobs: - # Only publish Continuous Deployment if this is the public repo - - ${{ if eq(variables['Build.Repository.Name'], 'Azure/azure-dev') }}: - - job: Publish_Continuous_Deployment - condition: >- - and( - succeeded(), - ne(variables['Skip.Release'], 'true'), - or( - in(variables['BuildReasonOverride'], 'IndividualCI', 'BatchedCI'), - and( - eq('', variables['BuildReasonOverride']), - in(variables['Build.Reason'], 'IndividualCI', 'BatchedCI') - ) - ) - ) - pool: - name: azsdk-pool-mms-ubuntu-2004-general - OSVmImage: MMSUbuntu20.04 - - steps: - - checkout: self - - template: /eng/pipelines/templates/steps/set-cli-version-cd.yml - - - task: PowerShell@2 - inputs: - pwsh: true - targetType: filePath - filePath: eng/scripts/Set-CliVersionVariable.ps1 - displayName: Set CLI_VERSION - - - template: /eng/pipelines/templates/steps/publish-cli.yml - parameters: - CreateGitHubRelease: false - PublishUploadLocations: release/daily;daily/archive/$(Build.BuildId)-$(Build.SourceVersion) - PublishShield: false - DockerImageTags: daily;$(CLI_VERSION) - UploadMsi: true - PublishArm64Binaries: true - - - job: Publish_For_PR - condition: >- - and( - succeeded(), - ne(variables['Skip.Release'], 'true'), - or( - eq('PullRequest', variables['BuildReasonOverride']), - and( - eq('', variables['BuildReasonOverride']), - eq(variables['Build.Reason'], 'PullRequest') - ) - ) - ) - pool: - name: azsdk-pool-mms-ubuntu-2004-general - OSVmImage: MMSUbuntu20.04 - - variables: - ${{ if eq(variables['Build.Repository.Name'], 'Azure/azure-dev') }}: - storage-account-name: $(azdev-storage-account-name) - ${{ else }}: - storage-account-name: $(azdev-storage-account-name-pr) - - - steps: - - checkout: self - - pwsh: | - $PRNumber = '$(System.PullRequest.PullRequestNumber)' - if ($env:PRNUMBEROVERRIDE) { - Write-Host "PR Number override: $($env:PRNUMBEROVERRIDE)" - $PRNumber = "$($env:PRNUMBEROVERRIDE)" - } - Write-Host "##vso[task.setvariable variable=PRNumber]$PRNumber" - displayName: Set PR Number Variable - - - task: PowerShell@2 - inputs: - pwsh: true - targetType: filePath - filePath: eng/scripts/Set-CliVersionVariable.ps1 - displayName: Set CLI_VERSION - - - template: /eng/pipelines/templates/steps/publish-cli.yml - parameters: - CreateGitHubRelease: false - PublishUploadLocations: pr/$(PRNumber) - UploadInstaller: true - UploadMsi: true - PublishArm64Binaries: true - - ${{ if eq(variables['Build.Repository.Name'], 'Azure/azure-dev') }}: - PublishContainer: true - DockerImageTags: pr-$(PRNumber) - StorageAccountName: $(azdev-storage-account-name) - StorageAccountKey: $(azdev-storage-account-key) - ${{ else }}: - PublishContainer: false - StorageAccountName: $(azdev-storage-account-name-pr) - StorageAccountKey: $(azdev-storage-account-key-pr) - - - - pwsh: | - $urlBase = "https://$(storage-account-name).blob.core.windows.net/azd/standalone/pr/$(PRNumber)" - Write-Host "##vso[task.setvariable variable=UrlBase;isOutput=true]$urlBase" - name: GenerateUrlBase - displayName: Set UrlBase - - - task: DownloadPipelineArtifact@2 - inputs: - artifact: docs - path: docs - - - pwsh: | - $urlBase = "$(GenerateUrlBase.UrlBase)" - $linuxReleaseUrl = "$urlBase/azd-linux-amd64.tar.gz" - $linuxReleaseUrlArm64 = "$urlBase/azd-linux-arm64.tar.gz" - $macosReleaseUrl = "$urlBase/azd-darwin-amd64.zip" - $macosReleaseUrlArm64 = "$urlBase/azd-darwin-arm64.zip" - $windowsReleaseUrl = "$urlBase/azd-windows-amd64.zip" - $msiReleaseUrl = "$urlBase/azd-windows-amd64.msi" - - $refDocContent = Get-Content docs/azd.md -Raw - - $content = @" - - ## Azure Dev CLI Install Instructions - - ### Install scripts - - #### MacOS/Linux - - > May elevate using ``sudo`` on some platforms and configurations - - bash: - `````` - curl -fsSL $urlBase/uninstall-azd.sh | bash; - curl -fsSL $urlBase/install-azd.sh | bash -s -- --base-url $urlBase --version '' --verbose --skip-verify - `````` - - pwsh: - `````` - Invoke-RestMethod '$urlBase/uninstall-azd.ps1' -OutFile uninstall-azd.ps1; ./uninstall-azd.ps1 - Invoke-RestMethod '$urlBase/install-azd.ps1' -OutFile install-azd.ps1; ./install-azd.ps1 -BaseUrl '$urlBase' -Version '' -SkipVerify -Verbose - `````` - - - #### Windows - - PowerShell install - - `````` - powershell -c "Set-ExecutionPolicy Bypass Process; irm '$urlBase/uninstall-azd.ps1' > uninstall-azd.ps1; ./uninstall-azd.ps1;" - powershell -c "Set-ExecutionPolicy Bypass Process; irm '$urlBase/install-azd.ps1' > install-azd.ps1; ./install-azd.ps1 -BaseUrl '$urlBase' -Version '' -SkipVerify -Verbose;" - `````` - - MSI install - `````` - powershell -c "irm '$msiReleaseUrl' -OutFile azd-windows-amd64.msi; msiexec /i azd-windows-amd64.msi /qn" - `````` - - ### Standalone Binary - - * Linux - - * x86_64 - $linuxReleaseUrl - * ARM64 - $linuxReleaseUrlArm64 - * MacOS - - * x86_64 - $macosReleaseUrl - * ARM64 - $macosReleaseUrlArm64 - * Windows - $windowsReleaseUrl - - ### MSI - - * $msiReleaseUrl - - ## Documentation - -
- learn.microsoft.com documentation - - $refDocContent - -
- "@ - $file = New-TemporaryFile - Set-Content -Path $file -Value $content - Write-Host "##vso[task.setvariable variable=CommentBodyFile]$file" - displayName: Write body content to temporary file - - - task: PowerShell@2 - displayName: Add PR comment - inputs: - pwsh: true - targetType: filePath - filePath: ./eng/scripts/Update-PRComment.ps1 - arguments: >- - -Repo "$(Build.Repository.Name)" - -PrNumber $(PRNumber) - -Tag "" - -BodyFile $(CommentBodyFile) - env: - GH_TOKEN: $(azuresdk-github-pat) - - - ${{ if eq(variables['Build.Repository.Name'], 'Azure/azure-dev') }}: - - stage: PublishInstallers - dependsOn: Sign - condition: >- - and( - succeeded(), - ne(variables['Skip.Release'], 'true'), - or( - eq('Manual', variables['BuildReasonOverride']), - and( - eq('', variables['BuildReasonOverride']), - eq('Manual', variables['Build.Reason']) - ) - ) - ) - jobs: - - deployment: PublishInstallers - environment: azure-dev - pool: - name: azsdk-pool-mms-ubuntu-2004-general - OSVmImage: MMSUbuntu20.04 +extends: + template: /eng/pipelines/templates/stages/1es-redirect.yml + parameters: + stages: + - template: /eng/pipelines/templates/stages/build-and-test.yml - strategy: - runOnce: - deploy: - steps: - - checkout: self + - template: /eng/pipelines/templates/stages/code-coverage-upload.yml - - task: DownloadPipelineArtifact@2 - inputs: - artifact: signed-win - path: signed-win + - template: /eng/pipelines/templates/stages/sign.yml - - pwsh: | - New-Item -ItemType Directory -Path script-release - Copy-Item signed-win/*.ps1 script-release/ - Copy-Item cli/installer/*.sh script-release/ - displayName: Copy scripts for release upload + - template: /eng/pipelines/templates/stages/verify-installers.yml - - pwsh: | - az storage blob upload-batch ` - --account-name '$(azdev-storage-account-name)' ` - --account-key '$(azdev-storage-account-key)' ` - --auth-mode key ` - -s script-release/ ` - -d "azd/standalone/installer" ` - --overwrite - displayName: Upload installer to storage location + - template: /eng/pipelines/templates/stages/publish.yml diff --git a/eng/pipelines/release-vscode.yml b/eng/pipelines/release-vscode.yml index f376d55163d..dd33af8e9d0 100644 --- a/eng/pipelines/release-vscode.yml +++ b/eng/pipelines/release-vscode.yml @@ -1,10 +1,3 @@ -resources: - repositories: - - repository: azure-sdk-build-tools - type: git - name: internal/azure-sdk-build-tools - ref: refs/tags/azure-sdk-build-tools_20240320.1 - # Continuous deployment trigger trigger: branches: @@ -21,315 +14,14 @@ pr: - ext/vscode - eng/pipelines/release-vscode.yml -variables: - - template: /eng/pipelines/templates/variables/globals.yml - -stages: - - stage: BuildAndTest - jobs: - - job: BuildVscode - strategy: - matrix: - Windows: - Pool: azsdk-pool-mms-win-2022-general - OSVmImage: MMS2022 - Linux: - Pool: azsdk-pool-mms-ubuntu-2004-general - OSVmImage: MMSUbuntu20.04 - UploadArtifact: true - Codeql.Enabled: true - Codeql.SkipTaskAutoInjection: false - Codeql.BuildIdentifier: vscode_linux - Mac: - Pool: Azure Pipelines - OSVmImage: macOS-11 - - pool: - name: $(Pool) - vmImage: $(OSVmImage) - - variables: - NodeVersion: 18.x - - steps: - - checkout: self - - task: NodeTool@0 - inputs: - versionSpec: $(NodeVersion) - - - pwsh: | - npm i -g npm vsce - npm ci --no-optional - workingDirectory: ext/vscode - displayName: Install dependencies - - - pwsh: ./ci-test.ps1 - workingDirectory: ext/vscode - displayName: Test - - # Sets the version in package.json if this is a Continuous Deployment - # build. - - template: /eng/pipelines/templates/steps/set-vscode-version.yml - - # Set PACKAGE_ARGS to an empty string so the version number is - # included in the filename (default behavior) - - pwsh: | - $buildReason = '$(Build.Reason)' - if ($env:BUILDREASONOVERRIDE) { - Write-Host "Build reason override: $($env:BUILDREASONOVERRIDE)" - $buildReason = $env:BUILDREASONOVERRIDE - } - - $packageArgs = '' - if ($buildReason -in @('IndividualCI', 'BatchedCI')) { - Write-Host "CD build detected, using latest configuration for PACKAGE_ARGS" - $packageArgs = '--out azure-dev-latest.vsix' - } - Write-Host "##vso[task.setvariable variable=PACKAGE_ARGS;]$packageArgs" - displayName: Set PACKAGE_ARGS - condition: and(succeeded(), eq('true', variables['UploadArtifact'])) - - - pwsh: ./ci-package.ps1 -PackageArguments '$(PACKAGE_ARGS)' - condition: and(succeeded(), eq('true', variables['UploadArtifact'])) - workingDirectory: ext/vscode - displayName: Package - - - task: PowerShell@2 - condition: and(succeeded(), eq('true', variables['UploadArtifact'])) - inputs: - pwsh: true - targetType: filePath - filePath: eng/scripts/Set-ShieldInfo.ps1 - arguments: >- - -TemplatePath eng/shields/vscode.json - -Version "$(VSIX_VERSION)" - displayName: Set shield info - - - pwsh: | - New-Item -ItemType Directory -Force -Path build - Copy-Item *.vsix build/ - workingDirectory: ext/vscode - condition: and(succeeded(), eq('true', variables['UploadArtifact'])) - displayName: Copy *.vsix to build for upload - - - publish: eng/shields/vscode.json - condition: and(succeeded(), eq('true', variables['UploadArtifact'])) - artifact: shield-vscode - displayName: Upload vscode shield json - - - publish: ext/vscode/build - condition: and(succeeded(), eq('true', variables['UploadArtifact'])) - artifact: vsix - - - stage: Sign - dependsOn: BuildAndTest - jobs: - - - job: Sign - pool: - name: azsdk-pool-mms-win-2022-general - vmImage: MMS2022 - - steps: - - checkout: self - - - task: DownloadPipelineArtifact@2 - inputs: - artifact: vsix - path: vsix - - - ${{ if in(variables['Build.Reason'], 'IndividualCI', 'BatchedCI', 'Manual') }}: - - template: pipelines/steps/azd-vscode-signing.yml@azure-sdk-build-tools - parameters: - VsixPath: vsix - - - ${{ else }}: - - pwsh: Write-Host "Skipping signing. Build reason - $(Build.Reason)" - displayName: Signing process skipped for non-release build - - - pwsh: | - New-Item -ItemType Directory -Path signed - Copy-Item vsix/ signed/ -Recurse - displayName: Copy signing outputs - condition: always() - - # TODO: Replace with https://github.com/Azure/azure-sdk-tools/blob/main/eng/common/pipelines/templates/steps/publish-artifact.yml - # when the common engsys is imported. - # https://github.com/Azure/azure-dev/issues/956 - - task: PublishPipelineArtifact@1 - condition: succeeded() - displayName: Publish Signed Artifacts - inputs: - artifactName: signed - path: signed/ - - - task: PublishPipelineArtifact@1 - condition: failed() - displayName: Publish failed Signed Artifacts - inputs: - artifactName: signed-FailedAttempt$(System.JobAttempt) - path: signed/ - - - stage: PublishManual - dependsOn: Sign - condition: >- - and( - succeeded(), - ne(variables['Skip.Release'], 'true'), - or( - eq('Manual', variables['BuildReasonOverride']), - and( - eq('', variables['BuildReasonOverride']), - eq(variables['Build.Reason'], 'Manual') - ) - ) - ) - jobs: - - deployment: Publish_Release - environment: azure-dev - pool: - name: azsdk-pool-mms-ubuntu-2004-general - OSVmImage: MMSUbuntu20.04 - strategy: - runOnce: - deploy: - steps: - - checkout: self - - - template: /eng/pipelines/templates/steps/set-vscode-version.yml - - - template: /eng/pipelines/templates/steps/publish-vscode.yml - parameters: - PublishLocations: vscode/release/$(VSIX_VERSION);vscode/release/latest - TagRepository: true - UpdateShield: true - - - deployment: Increment_Version - condition: >- - and( - succeeded(), - ne('true', variables['Skip.IncrementVersion']) - ) - dependsOn: Publish_Release - environment: azure-dev - - pool: - name: azsdk-pool-mms-ubuntu-2004-general - OSVmImage: MMSUbuntu20.04 - - strategy: - runOnce: - deploy: - steps: - - checkout: self - - - task: PowerShell@2 - inputs: - pwsh: true - targetType: filePath - filePath: eng/scripts/Update-VscodeExtensionVersion.ps1 - displayName: Increment VSCode Extension version - - - template: /eng/common/pipelines/templates/steps/create-pull-request.yml - parameters: - PRBranchName: vscode-version-increment-$(Build.BuildId) - CommitMsg: Increment VSCode Extension version after release - PRTitle: Increment VSCode Extension version after release - - - stage: PublishIntegration - dependsOn: Sign - jobs: - - job: Publish_Continuous_Deployment - condition: >- - and( - succeeded(), - ne(variables['Skip.Release'], 'true'), - or( - in(variables['BuildReasonOverride'], 'IndividualCI', 'BatchedCI'), - and( - eq('', variables['BuildReasonOverride']), - in(variables['Build.Reason'], 'IndividualCI', 'BatchedCI') - ) - ) - ) - - pool: - name: azsdk-pool-mms-ubuntu-2004-general - OSVmImage: MMSUbuntu20.04 - - steps: - - checkout: self - - - template: /eng/pipelines/templates/steps/set-vscode-version.yml - - - template: /eng/pipelines/templates/steps/publish-vscode.yml - parameters: - PublishLocations: vscode/release/daily;vscode/daily/archive/$(Build.BuildId)-$(Build.SourceVersion) - - - job: Publish_For_PR - condition: >- - and( - succeeded(), - ne(variables['Skip.Release'], 'true'), - or( - eq('PullRequest', variables['BuildReasonOverride']), - and( - eq('', variables['BuildReasonOverride']), - eq(variables['Build.Reason'], 'PullRequest') - ) - ) - ) - pool: - name: azsdk-pool-mms-ubuntu-2004-general - OSVmImage: MMSUbuntu20.04 - steps: - - checkout: self - - - pwsh: | - $PRNumber = '$(System.PullRequest.PullRequestNumber)' - if ($env:PRNUMBEROVERRIDE) { - Write-Host "PR Number override: $($env:PRNUMBEROVERRIDE)" - $PRNumber = $env:PRNUMBEROVERRIDE - } - Write-Host "##vso[task.setvariable variable=PRNumber]$PRNumber" - displayName: Set PR Number Variable - - - template: /eng/pipelines/templates/steps/set-vscode-version.yml - - - template: /eng/pipelines/templates/steps/publish-vscode.yml - parameters: - PublishLocations: vscode/pr/$(PRNumber) - - - pwsh: | - $downloadUrl = "https://$(azdev-storage-account-name).blob.core.windows.net/azd/vscode/pr/$(PRNumber)/azure-dev-$(VSIX_VERSION).vsix" +extends: + template: /eng/pipelines/templates/stages/1es-redirect.yml + parameters: + stages: + - template: /eng/pipelines/templates/stages/vscode-build-and-test.yml - $content = @" - - ## VSCode Extension Installation Instructions + - template: /eng/pipelines/templates/stages/vscode-sign.yml - 1. Download the extension at $downloadUrl - 2. Extract the extension from the compressed file - 3. In vscode - a. Open "Extensions" (Ctrl+Shift+X) - b. Click the \`...\` menu at top of Extensions sidebar - c. Click "Install from VSIX" - d. Select location of downloaded file - "@ - $file = New-TemporaryFile - Set-Content -Path $file -Value $content - Write-Host "##vso[task.setvariable variable=CommentBodyFile]$file" - displayName: Write body content to temporary file + - template: /eng/pipelines/templates/stages/vscode-publish-manual.yml - - task: PowerShell@2 - displayName: Add PR comment - inputs: - pwsh: true - targetType: filePath - filePath: ./eng/scripts/Update-PRComment.ps1 - arguments: >- - -Repo "azure/azure-dev" - -PrNumber $(PRNumber) - -Tag "" - -BodyFile $(CommentBodyFile) - env: - GH_TOKEN: $(azuresdk-github-pat) + - template: /eng/pipelines/templates/stages/vscode-publish-integration.yml diff --git a/eng/pipelines/repoman.yml b/eng/pipelines/repoman.yml index 7e28f2bac4b..001546d96db 100644 --- a/eng/pipelines/repoman.yml +++ b/eng/pipelines/repoman.yml @@ -15,168 +15,137 @@ pr: - templates/ - eng/pipelines/repoman.yml -variables: - - template: /eng/pipelines/templates/variables/globals.yml - - name: StagingRemoteName - value: azure-samples-staging - -stages: - - stage: Validation - jobs: - - job: Generate_Repos_For_PR - condition: >- - and( - succeeded(), - or( - eq(variables['BuildReasonOverride'], 'PullRequest'), +extends: + template: /eng/pipelines/templates/stages/1es-redirect.yml + parameters: + stages: + - stage: Validation + + variables: + - template: /eng/pipelines/templates/variables/globals.yml + - name: StagingRemoteName + value: azure-samples-staging + + jobs: + - job: Generate_Repos_For_PR + condition: >- and( - eq('', variables['BuildReasonOverride']), - eq(variables['Build.Reason'], 'PullRequest') + succeeded(), + or( + eq(variables['BuildReasonOverride'], 'PullRequest'), + and( + eq('', variables['BuildReasonOverride']), + eq(variables['Build.Reason'], 'PullRequest') + ) + ) ) - ) - ) - pool: - name: azsdk-pool-mms-ubuntu-2004-general - vmImage: MMSUbuntu20.04 + pool: + name: azsdk-pool-mms-ubuntu-2004-general + image: azsdk-pool-mms-ubuntu-2004-1espt + os: linux - variables: - RepoManResultsFile: $(Pipeline.Workspace)/repoman.md + variables: + RepoManResultsFile: $(Pipeline.Workspace)/repoman.md - steps: - - checkout: self + steps: + - checkout: self - - pwsh: | - $PRNumber = '$(System.PullRequest.PullRequestNumber)' - if ($env:PRNUMBEROVERRIDE) { - Write-Host "PR Number override: $($env:PRNUMBEROVERRIDE)" - $PRNumber = "$($env:PRNUMBEROVERRIDE)" - } - Write-Host "##vso[task.setvariable variable=PRNumber]$PRNumber" - displayName: Set PRNumber + - pwsh: | + $PRNumber = '$(System.PullRequest.PullRequestNumber)' + if ($env:PRNUMBEROVERRIDE) { + Write-Host "PR Number override: $($env:PRNUMBEROVERRIDE)" + $PRNumber = "$($env:PRNUMBEROVERRIDE)" + } + Write-Host "##vso[task.setvariable variable=PRNumber]$PRNumber" + displayName: Set PRNumber - - template: /eng/pipelines/templates/steps/repoman-generate.yml - parameters: - TargetBranchName: pr/$(PRNumber) - RemoteName: $(StagingRemoteName) - ResultsFileLocation: $(RepoManResultsFile) + - template: /eng/pipelines/templates/steps/repoman-generate.yml + parameters: + TargetBranchName: pr/$(PRNumber) + RemoteName: $(StagingRemoteName) + ResultsFileLocation: $(RepoManResultsFile) + + - task: PowerShell@2 + name: DetermineChanged + displayName: Set repoman changed templates + inputs: + pwsh: true + targetType: filePath + filePath: ./eng/scripts/Set-RepomanChangedRepositories.ps1 + arguments: >- + -ResultsFile $(RepoManResultsFile) + -OutputTemplatesVariable "TemplateList" + -OutputTemplateBranchVariable "TemplateBranch" - - task: PowerShell@2 - name: DetermineChanged - displayName: Set repoman changed templates - inputs: - pwsh: true - targetType: filePath - filePath: ./eng/scripts/Set-RepomanChangedRepositories.ps1 - arguments: >- - -ResultsFile $(RepoManResultsFile) - -OutputTemplatesVariable "TemplateList" - -OutputTemplateBranchVariable "TemplateBranch" - - - pwsh: | - $repomanContent = "No changes detected." - $repomanOutputFile = "$(RepoManResultsFile)" - if (Test-Path $repomanOutputFile) { - $repomanContent = Get-Content $repomanOutputFile -Raw - } - - $tag ='' - $content = @" - $tag - ## Repoman Generation Results - Repoman pushed changes to remotes for the following projects: - $repomanContent - "@ - $file = New-TemporaryFile - Set-Content -Path $file -Value $content - Write-Host "##vso[task.setvariable variable=CommentBodyFile]$file" - displayName: Set Repoman Content - - - task: PowerShell@2 - displayName: Post PR comment - inputs: - pwsh: true - targetType: filePath - filePath: ./eng/scripts/Update-PRComment.ps1 - arguments: >- - -Repo 'azure/azure-dev' - -PRNumber '$(PRNumber)' - -BodyFile '$(CommentBodyFile)' - -Tag '' - env: - GH_TOKEN: $(azuresdk-github-pat) - - - template: /eng/pipelines/templates/jobs/run-template-tests.yml - parameters: - TemplateList: $[ dependencies.Generate_Repos_For_PR.outputs['DetermineChanged.TemplateList'] ] - TemplateBranchName: $[ dependencies.Generate_Repos_For_PR.outputs['DetermineChanged.TemplateBranch'] ] - TemplateListFilter: '^Azure-Samples/todo-.*$' - JobCondition: >- - and( - succeeded(), - ne(dependencies.Generate_Repos_For_PR.outputs['DetermineChanged.TemplateList'] , '') - ) - JobDependsOn: Generate_Repos_For_PR + - pwsh: | + $repomanContent = "No changes detected." + $repomanOutputFile = "$(RepoManResultsFile)" + if (Test-Path $repomanOutputFile) { + $repomanContent = Get-Content $repomanOutputFile -Raw + } - - job: Publish_Staging - condition: >- - and( - succeeded(), - or( - in(variables['BuildReasonOverride'], 'IndividualCI', 'BatchedCI'), + $tag ='' + $content = @" + $tag + ## Repoman Generation Results + Repoman pushed changes to remotes for the following projects: + $repomanContent + "@ + $file = New-TemporaryFile + Set-Content -Path $file -Value $content + Write-Host "##vso[task.setvariable variable=CommentBodyFile]$file" + displayName: Set Repoman Content + + - task: PowerShell@2 + displayName: Post PR comment + inputs: + pwsh: true + targetType: filePath + filePath: ./eng/scripts/Update-PRComment.ps1 + arguments: >- + -Repo 'azure/azure-dev' + -PRNumber '$(PRNumber)' + -BodyFile '$(CommentBodyFile)' + -Tag '' + env: + GH_TOKEN: $(azuresdk-github-pat) + + - template: /eng/pipelines/templates/jobs/run-template-tests.yml + parameters: + TemplateList: $[ dependencies.Generate_Repos_For_PR.outputs['DetermineChanged.TemplateList'] ] + TemplateBranchName: $[ dependencies.Generate_Repos_For_PR.outputs['DetermineChanged.TemplateBranch'] ] + TemplateListFilter: '^Azure-Samples/todo-.*$' + JobCondition: >- + and( + succeeded(), + ne(dependencies.Generate_Repos_For_PR.outputs['DetermineChanged.TemplateList'] , '') + ) + JobDependsOn: Generate_Repos_For_PR + Pool: azsdk-pool-mms-ubuntu-2004-general + Image: azsdk-pool-mms-ubuntu-2004-1espt + + - job: Publish_Staging + condition: >- and( - eq('', variables['BuildReasonOverride']), - in(variables['Build.Reason'], 'IndividualCI', 'BatchedCI') + succeeded(), + or( + in(variables['BuildReasonOverride'], 'IndividualCI', 'BatchedCI'), + and( + eq('', variables['BuildReasonOverride']), + in(variables['Build.Reason'], 'IndividualCI', 'BatchedCI') + ) + ) ) - ) - ) - pool: - name: azsdk-pool-mms-ubuntu-2004-general - vmImage: MMSUbuntu20.04 - - steps: - - checkout: self - - - pwsh: | - $targetBranchName = 'staging' - if ($env:TARGETBRANCHNAMEOVERRIDE) { - Write-Host "Target branch override $($env:TARGETBRANCHNAMEOVERRIDE)" - $targetBranchName = $env:TARGETBRANCHNAMEOVERRIDE - } - Write-Host "##vso[task.setvariable variable=TargetBranchName]$targetBranchName" - displayName: Set TargetBranchName - - - template: /eng/pipelines/templates/steps/repoman-generate.yml - parameters: - TargetBranchName: $(TargetBranchName) - RemoteName: $(StagingRemoteName) - - - stage: Publish_Repos - condition: >- - and( - succeeded(), - or( - eq(variables['BuildReasonOverride'], 'Manual'), - and( - eq('', variables['BuildReasonOverride']), - eq(variables['Build.Reason'], 'Manual') - ) - ) - ) - jobs: - - deployment: Publish_Repos - environment: azure-dev - pool: - name: azsdk-pool-mms-ubuntu-2004-general - vmImage: MMSUbuntu20.04 - - strategy: - runOnce: - deploy: + pool: + name: azsdk-pool-mms-ubuntu-2004-general + image: azsdk-pool-mms-ubuntu-2004-1espt + os: linux + steps: - checkout: self - pwsh: | - $targetBranchName = '' + $targetBranchName = 'staging' if ($env:TARGETBRANCHNAMEOVERRIDE) { Write-Host "Target branch override $($env:TARGETBRANCHNAMEOVERRIDE)" $targetBranchName = $env:TARGETBRANCHNAMEOVERRIDE @@ -187,4 +156,52 @@ stages: - template: /eng/pipelines/templates/steps/repoman-generate.yml parameters: TargetBranchName: $(TargetBranchName) - RemoteName: azure-samples-main + RemoteName: $(StagingRemoteName) + + - stage: Publish_Repos + condition: >- + and( + succeeded(), + or( + eq(variables['BuildReasonOverride'], 'Manual'), + and( + eq('', variables['BuildReasonOverride']), + eq(variables['Build.Reason'], 'Manual') + ) + ) + ) + + variables: + - template: /eng/pipelines/templates/variables/globals.yml + + jobs: + - deployment: Publish_Repos + environment: azure-dev + + pool: + name: azsdk-pool-mms-ubuntu-2004-general + image: azsdk-pool-mms-ubuntu-2004-1espt + os: linux + + templateContext: + inputs: + - input: checkout + repository: self + + strategy: + runOnce: + deploy: + steps: + - pwsh: | + $targetBranchName = '' + if ($env:TARGETBRANCHNAMEOVERRIDE) { + Write-Host "Target branch override $($env:TARGETBRANCHNAMEOVERRIDE)" + $targetBranchName = $env:TARGETBRANCHNAMEOVERRIDE + } + Write-Host "##vso[task.setvariable variable=TargetBranchName]$targetBranchName" + displayName: Set TargetBranchName + + - template: /eng/pipelines/templates/steps/repoman-generate.yml + parameters: + TargetBranchName: $(TargetBranchName) + RemoteName: azure-samples-main diff --git a/eng/pipelines/templates/jobs/build-cli.yml b/eng/pipelines/templates/jobs/build-cli.yml new file mode 100644 index 00000000000..a4cf355f34f --- /dev/null +++ b/eng/pipelines/templates/jobs/build-cli.yml @@ -0,0 +1,217 @@ +parameters: + - name: NameSuffix + type: string + - name: Pool + type: string + - name: ImageKey + type: string + default: image + - name: OSVmImage + type: string + - name: OS + type: string + - name: Variables + type: object + default: {} + +jobs: + - job: BuildCLI_${{ parameters.NameSuffix }} + displayName: BuildCLI ${{ parameters.NameSuffix }} + + variables: + ${{ insert }}: ${{ parameters.Variables }} + + pool: + name: ${{ parameters.Pool }} + ${{ parameters.ImageKey }}: ${{ parameters.OSVmImage }} + os: ${{ parameters.OS }} + + timeoutInMinutes: 180 + steps: + - checkout: self + - template: /eng/pipelines/templates/steps/setup-go.yml + parameters: + Condition: and(succeeded(), ne(variables['Skip.LiveTest'], 'true')) + + - template: /eng/pipelines/templates/steps/set-cli-version-cd.yml + + - task: PowerShell@2 + inputs: + pwsh: true + targetType: filePath + filePath: eng/scripts/Set-CliVersionVariable.ps1 + displayName: Set CLI_VERSION + + - task: PowerShell@2 + inputs: + pwsh: true + targetType: filePath + filePath: eng/scripts/Set-CliBuildVariables.ps1 + arguments: -BuildReason $(Build.Reason) + displayName: Set CLI build run variables + + - task: PowerShell@2 + inputs: + pwsh: true + targetType: filePath + filePath: cli/azd/ci-build.ps1 + arguments: >- + -Version $(CLI_VERSION) + -SourceVersion $(Build.SourceVersion) + -CodeCoverageEnabled + -BuildRecordMode + workingDirectory: cli/azd + displayName: Build Go Binary (For tests) + + - template: /eng/pipelines/templates/steps/build-msi.yml + parameters: + Title: Build Test MSI + Condition: and(succeeded(), eq(variables['BuildTestMsi'], 'true')) + # Build the test MSI with the same configuration as the + # release MSI (no special upgrade behavior) + ShouldBuildForRelease: true + + - template: /eng/pipelines/templates/steps/install-terraform.yml + - template: /eng/pipelines/templates/steps/install-kubectl.yml + + - task: DockerInstaller@0 + displayName: Docker Installer + condition: and(succeeded(), contains('${{ parameters.OS }}', 'macOS')) + inputs: + dockerVersion: 17.09.0-ce + releaseType: stable + + # Live testing uses dotnet 8.0.x in the WebApp project deployment + - task: UseDotNet@2 + condition: and(succeeded(), ne(variables['Skip.LiveTest'], 'true')) + inputs: + version: 8.0.x + + - bash: dotnet nuget add source --name dotnet8 https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet8/nuget/v3/index.json + displayName: Add internal dotnet nuget feed + + - template: /eng/pipelines/templates/steps/az-login.yml + parameters: + Condition: and(succeeded(), ne(variables['Skip.LiveTest'], 'true')) + + - template: /eng/pipelines/templates/steps/azd-login.yml + parameters: + AzdDirectory: cli/azd + + - task: PowerShell@2 + condition: and(succeeded(), ne(variables['Skip.LiveTest'], 'true')) + inputs: + pwsh: true + targetType: filePath + filePath: cli/azd/ci-test.ps1 + arguments: >- + -UnitTestCoverageDir './cover-$(AZURE_DEV_CI_OS)/unit' + -IntegrationTestCoverageDir './cover-$(AZURE_DEV_CI_OS)/int' + workingDirectory: cli/azd + displayName: Test Go Binary + env: + # AZD live test setup variables + CI: true + AZD_TEST_CLI_VERSION: $(CLI_VERSION) + AZD_TEST_CLIENT_ID: $(arm-client-id) + AZD_TEST_CLIENT_SECRET: $(arm-client-secret) + AZD_TEST_TENANT_ID: $(arm-tenant-id) + AZD_TEST_AZURE_SUBSCRIPTION_ID: $(SubscriptionId) + AZD_TEST_AZURE_LOCATION: eastus2 + AZURE_RECORD_MODE: $(AZURE_RECORD_MODE) + # AZD Live Test: Terraform service principal authentication + ARM_CLIENT_ID: $(arm-client-id) + ARM_CLIENT_SECRET: $(arm-client-secret) + ARM_TENANT_ID: $(arm-tenant-id) + # Code Coverage: Generate junit report to publish results + GOTESTSUM_JUNITFILE: junitTestReport.xml + + - task: PublishTestResults@2 + inputs: + testResultsFormat: JUnit + testResultsFiles: '**/junitTestReport.xml' + testRunTitle: $(Agent.JobName) + searchFolder: cli/azd + publishRunAttachments: true + displayName: Publish test results + condition: succeededOrFailed() + + - task: PowerShell@2 + inputs: + pwsh: true + targetType: filePath + filePath: cli/azd/ci-build.ps1 + arguments: >- + -Version $(CLI_VERSION) + -SourceVersion $(Build.SourceVersion) + workingDirectory: cli/azd + displayName: Build Go Binary + + - pwsh: | + Write-Host "Move-Item $(BuildOutputName) $(BuildTarget)" + Move-Item $(BuildOutputName) $(BuildTarget) + workingDirectory: cli/azd + displayName: Rename binaries + + - bash: chmod +x $(BuildTarget) + condition: and(succeeded(), eq(variables['SetExecutableBit'], 'true')) + workingDirectory: cli/azd + displayName: Set executable bit for non-Windows binaries + + - pwsh: | + New-Item -ItemType Directory -Path $(Build.ArtifactStagingDirectory)/build-output -Force + Copy-Item $(BuildTarget) $(Build.ArtifactStagingDirectory)/build-output + workingDirectory: cli/azd + displayName: Copy binary to artifact staging directory + + - template: /eng/pipelines/templates/steps/build-linux-packages.yml + parameters: + Condition: and(succeeded(), eq(variables['BuildLinuxPackages'], 'true')) + + - pwsh: New-Item -ItemType Directory -Path $(Build.ArtifactStagingDirectory)/shield -Force + condition: and(succeeded(), eq(variables['SetShieldInfo'], 'true')) + displayName: Create shield artifact directory + + - task: PowerShell@2 + condition: and(succeeded(), eq(variables['SetShieldInfo'], 'true')) + inputs: + pwsh: true + targetType: filePath + filePath: eng/scripts/Set-ShieldInfo.ps1 + arguments: >- + -TemplatePath eng/shields/standalone.json + -OutputPath $(Build.ArtifactStagingDirectory)/shield/standalone.json + -Version "$(CLI_VERSION)" + displayName: Set shield info + + templateContext: + outputs: + - output: pipelineArtifact + path: cli/azd/cover-$(AZURE_DEV_CI_OS) + condition: and(succeeded(), ne(variables['Skip.LiveTest'], 'true')) + artifact: cover-$(AZURE_DEV_CI_OS) + displayName: Upload code coverage + + - output: pipelineArtifact + path: $(Build.ArtifactStagingDirectory)/shield + condition: and(succeeded(), eq(variables['SetShieldInfo'], 'true')) + artifact: shield-standalone + displayName: Upload standalone shield json + + - output: pipelineArtifact + path: $(Build.ArtifactStagingDirectory)/build-output + artifact: $(BuildTarget) + condition: always() + displayName: Upload azd binary to artifact store + + - output: pipelineArtifact + path: cli/installer/windows/bin/Release + artifact: test-msi + condition: and(succeeded(), eq(variables['BuildTestMsi'], 'true')) + displayName: Upload test MSI + + - output: pipelineArtifact + path: cli/installer/fpm/artifact + artifact: linux-packages-amd64 + condition: and(succeeded(), eq(variables['BuildLinuxPackages'], 'true')) + displayName: Upload linux packages to artifact store diff --git a/eng/pipelines/templates/jobs/cross-build-cli.yml b/eng/pipelines/templates/jobs/cross-build-cli.yml new file mode 100644 index 00000000000..7c56719a4d3 --- /dev/null +++ b/eng/pipelines/templates/jobs/cross-build-cli.yml @@ -0,0 +1,102 @@ +parameters: + - name: NameSuffix + type: string + - name: Pool + type: string + - name: ImageKey + type: string + default: image + - name: OSVmImage + type: string + - name: OS + type: string + - name: Variables + type: object + default: {} + - name: PreBuildSteps + type: stepList + default: [] + - name: HostArchitecture + type: string + +jobs: + - job: CrossBuildCLI_${{ parameters.NameSuffix }} + displayName: CrossBuildCLI ${{ parameters.NameSuffix }} + + variables: + ${{ insert }}: ${{ parameters.Variables }} + + pool: + name: ${{ parameters.Pool }} + ${{ parameters.ImageKey }}: ${{ parameters.OSVmImage }} + os: ${{ parameters.OS }} + hostArchitecture: ${{ parameters.HostArchitecture }} + + timeoutInMinutes: 20 + + steps: + - checkout: self + + - template: /eng/pipelines/templates/steps/setup-go.yml + parameters: + Condition: false + + - template: /eng/pipelines/templates/steps/set-cli-version-cd.yml + + - task: PowerShell@2 + inputs: + pwsh: true + targetType: filePath + filePath: eng/scripts/Set-CliVersionVariable.ps1 + displayName: Set CLI_VERSION + + - ${{ parameters.PreBuildSteps }} + + - task: PowerShell@2 + inputs: + pwsh: true + targetType: filePath + filePath: cli/azd/ci-build.ps1 + arguments: >- + -Version $(CLI_VERSION) + -SourceVersion $(Build.SourceVersion) + workingDirectory: cli/azd + displayName: Build Go Binary (cross compile) + + - pwsh: file azd + workingDirectory: cli/azd + displayName: Get file info + + - pwsh: Move-Item $(BuildOutputName) $(BuildTarget) + workingDirectory: cli/azd + displayName: Rename binaries + + - bash: chmod +x $(BuildTarget) + condition: and(succeeded(), eq(variables['SetExecutableBit'], 'true')) + workingDirectory: cli/azd + displayName: Set executable bit for non-Windows binaries + + - pwsh: | + New-Item -ItemType Directory -Path $(Build.ArtifactStagingDirectory)/build-output -Force + Copy-Item $(BuildTarget) $(Build.ArtifactStagingDirectory)/build-output + workingDirectory: cli/azd + displayName: Copy binary to artifact staging directory + + - template: /eng/pipelines/templates/steps/build-linux-packages.yml + parameters: + Architecture: arm64 + Condition: and(succeeded(), eq(variables['BuildLinuxPackages'], 'true')) + + templateContext: + outputs: + - output: pipelineArtifact + path: $(Build.ArtifactStagingDirectory)/build-output + artifact: $(BuildTarget) + condition: always() + displayName: Upload azd binary to artifact store + + - output: pipelineArtifact + path: cli/installer/fpm/artifact + artifact: linux-packages-arm64 + condition: and(succeeded(), eq(variables['BuildLinuxPackages'], 'true')) + displayName: Upload linux packages to artifact store diff --git a/eng/pipelines/templates/jobs/run-template-tests.yml b/eng/pipelines/templates/jobs/run-template-tests.yml index 3147b87b3d6..cb5bfed4497 100644 --- a/eng/pipelines/templates/jobs/run-template-tests.yml +++ b/eng/pipelines/templates/jobs/run-template-tests.yml @@ -53,13 +53,23 @@ parameters: type: boolean default: false +- name: Pool + type: string + default: azsdk-pool-mms-ubuntu-2004-general + +# Image name (compliant image required for 1ES pipelines that release) +- name: Image + type: string + default: MMSUbuntu20.04 + jobs: - job: TemplateTest_CreateMatrix condition: ${{ parameters.JobCondition }} dependsOn: ${{ parameters.JobDependsOn }} pool: - name: azsdk-pool-mms-ubuntu-2004-general - vmImage: MMSUbuntu20.04 + name: ${{ parameters.Pool }} + image: ${{ parameters.Image }} + os: linux variables: - name: AzdVersion @@ -109,8 +119,9 @@ jobs: maxParallel: 10 pool: - name: azsdk-pool-mms-ubuntu-2004-general - vmImage: MMSUbuntu20.04 + name: ${{ parameters.Pool }} + image: ${{ parameters.Image }} + os: linux steps: - checkout: self diff --git a/eng/pipelines/templates/jobs/verify-installers.yml b/eng/pipelines/templates/jobs/verify-installers.yml new file mode 100644 index 00000000000..b9b14bacc00 --- /dev/null +++ b/eng/pipelines/templates/jobs/verify-installers.yml @@ -0,0 +1,170 @@ +parameters: + - name: NameSuffix + type: string + - name: Pool + type: string + - name: ImageKey + type: string + default: image + - name: OSVmImage + type: string + - name: OS + type: string + - name: Variables + type: object + default: {} + +jobs: + - job: Verify_Installers_${{ parameters.NameSuffix }} + displayName: Verify_Installers ${{ parameters.NameSuffix }} + + dependsOn: Compress_For_Hosting + + pool: + name: ${{ parameters.Pool }} + ${{ parameters.ImageKey }}: ${{ parameters.OSVmImage }} + os: ${{ parameters.OS }} + + variables: + ${{ insert }}: ${{ parameters.Variables }} + BaseUrl: http://127.0.0.1:8080 + + timeoutInMinutes: 10 + + steps: + - checkout: self + + - task: DownloadPipelineArtifact@2 + inputs: + artifact: test-hosting + path: hosting + + - bash: ls + workingDirectory: hosting + + - bash: | + unzip ./azd-darwin-amd64.zip -d ./tmp + + # Ad-hoc signing with "-" identity + codesign -s - tmp/azd-darwin-amd64 + + zip azd-darwin-amd64.zip -j tmp/azd-darwin-amd64 + displayName: Self-sign (Darwin) + condition: and(succeeded(), contains(variables['Agent.OS'], 'Darwin')) + workingDirectory: hosting + + - pwsh: | + $ErrorActionPreference = 'Stop' + + # Generate self-sign cert + $cert = New-SelfSignedCertificate -CertStoreLocation Cert:\LocalMachine\My -Type CodeSigningCert -Subject "azd installer tests code signing" + + # Add as temporary trusted root CA + try { + Export-Certificate -Cert $cert -FilePath code_signing.crt + Import-Certificate -FilePath .\code_signing.crt -Cert Cert:\LocalMachine\Root + } + finally { + Remove-Item -Force .\code_signing.crt -ErrorAction SilentlyContinue + } + + # Sign the windows binary + Set-AuthenticodeSignature .\azd-windows-amd64.msi -Certificate $cert + displayName: Self-sign (Windows) + condition: and(succeeded(), contains(variables['Agent.OS'], 'Windows')) + workingDirectory: hosting + + - bash: nohup npx -y http-server & + displayName: Start server in hosting/ (bash) + condition: and(succeeded(), not(contains(variables['Agent.OS'], 'Windows'))) + workingDirectory: hosting + + - pwsh: | + Start-Process npx.cmd ` + -ArgumentList @('-y', 'http-server') ` + -NoNewWindow ` + -PassThru ` + -RedirectStandardOutput ../server.log + Write-Host "Server started, waiting for server to initialize" + Start-Sleep -Seconds 15 + displayName: Start server in hosting/ (pwsh) + condition: and(succeeded(), contains(variables['Agent.OS'], 'Windows')) + workingDirectory: hosting + + - pwsh: | + $tmpFile = New-TemporaryFile + $timer = [Diagnostics.Stopwatch]::StartNew() + $MAX_ELAPSED_SECONDS = 120 + $TIMEOUT_SECONDS = 12 + $SLEEP_SECONDS = 1 + + while ($timer.Elapsed.TotalSeconds -lt $MAX_ELAPSED_SECONDS) { + try { + Write-Host "Downloading file..." + Invoke-WebRequest ` + $(BaseUrl)/azd-windows-amd64.zip ` + -OutFile $tmpFile ` + -TimeoutSec $TIMEOUT_SECONDS + + if ($LASTEXITCODE) { + throw "Failed downloading file" + } + } catch { + Write-Host "Error downloading file." + Write-Host $_ + Start-Sleep -Seconds $SLEEP_SECONDS + continue + } + + # Exit if the downloaded file size is less than a small threshold + # this could mean an error in how the files are being served. + if ((Get-Item $tmpFile).Length -le 100000) { + Get-Content $tmpFile + exit 1 + } + + break + } + + Get-Item $tmpFile | Select-Object -Property Name,Length + displayName: Verify installer hosting + + - pwsh: $(TestInstallCommand) + condition: and(succeeded(), eq('pwsh', variables['TestShell'])) + workingDirectory: cli/installer/ + displayName: Test install script (pwsh) + + - powershell: $(TestInstallCommand) + condition: and(succeeded(), eq('powershell', variables['TestShell'])) + workingDirectory: cli/installer/ + displayName: Test install script (PowerShell) + + - bash: $(TestInstallCommand) + condition: and(succeeded(), eq('bash', variables['TestShell'])) + workingDirectory: cli/installer/ + displayName: Test install script (bash) + + - task: CmdLine@2 + condition: and(succeeded(), eq('cmd', variables['TestShell'])) + inputs: + script: $(TestInstallCommand) + workingDirectory: cli/installer/ + displayName: Test install script (cmd) + + - pwsh: | + Get-ChildItem Cert:\LocalMachine\My | ForEach-Object { + if ($_.Subject -match "azd installer tests code signing") { + Write-Host "Deleting $($_.PSPath) - $($_.Subject)" + Remove-Item -Force $_.PSPath + } + } + + Get-ChildItem Cert:\LocalMachine\Root | ForEach-Object { + if ($_.Subject -match "azd installer tests code signing") { + Write-Host "Deleting $($_.PSPath) - $($_.Subject)" + Remove-Item -Force $_.PSPath + } + } + displayName: Clean up self-signed certificates (Windows) + condition: contains(variables['Agent.OS'], 'Windows') + workingDirectory: hosting diff --git a/eng/pipelines/templates/jobs/vscode-build.yml b/eng/pipelines/templates/jobs/vscode-build.yml new file mode 100644 index 00000000000..1e5f29e097b --- /dev/null +++ b/eng/pipelines/templates/jobs/vscode-build.yml @@ -0,0 +1,107 @@ +parameters: + - name: NameSuffix + type: string + - name: Pool + type: string + - name: ImageKey + type: string + default: image + - name: OSVmImage + type: string + - name: OS + type: string + - name: Variables + type: object + default: {} + +jobs: + - job: BuildVscode_${{ parameters.NameSuffix }} + displayName: BuildVscode ${{ parameters.NameSuffix }} + + pool: + name: ${{ parameters.Pool }} + ${{ parameters.ImageKey }}: ${{ parameters.OSVmImage }} + os: ${{ parameters.OS }} + + variables: + NodeVersion: 18.x + ${{ insert }}: ${{ parameters.Variables }} + + steps: + - checkout: self + - task: NodeTool@0 + inputs: + versionSpec: $(NodeVersion) + + - pwsh: | + npm i -g npm vsce + npm ci --no-optional + workingDirectory: ext/vscode + displayName: Install dependencies + + - pwsh: ./ci-test.ps1 + workingDirectory: ext/vscode + displayName: Test + + # Sets the version in package.json if this is a Continuous Deployment + # build. + - template: /eng/pipelines/templates/steps/set-vscode-version.yml + + # Set PACKAGE_ARGS to an empty string so the version number is + # included in the filename (default behavior) + - pwsh: | + $buildReason = '$(Build.Reason)' + if ($env:BUILDREASONOVERRIDE) { + Write-Host "Build reason override: $($env:BUILDREASONOVERRIDE)" + $buildReason = $env:BUILDREASONOVERRIDE + } + + $packageArgs = '' + if ($buildReason -in @('IndividualCI', 'BatchedCI')) { + Write-Host "CD build detected, using latest configuration for PACKAGE_ARGS" + $packageArgs = '--out azure-dev-latest.vsix' + } + Write-Host "##vso[task.setvariable variable=PACKAGE_ARGS;]$packageArgs" + displayName: Set PACKAGE_ARGS + condition: and(succeeded(), eq('true', variables['UploadArtifact'])) + + - pwsh: ./ci-package.ps1 -PackageArguments '$(PACKAGE_ARGS)' + condition: and(succeeded(), eq('true', variables['UploadArtifact'])) + workingDirectory: ext/vscode + displayName: Package + + - pwsh: New-Item -ItemType Directory -Path $(Build.ArtifactStagingDirectory)/shield -Force + condition: and(succeeded(), eq('true', variables['UploadArtifact'])) + displayName: Create shield artifact directory + + - task: PowerShell@2 + condition: and(succeeded(), eq('true', variables['UploadArtifact'])) + inputs: + pwsh: true + targetType: filePath + filePath: eng/scripts/Set-ShieldInfo.ps1 + arguments: >- + -TemplatePath eng/shields/vscode.json + -OutputPath $(Build.ArtifactStagingDirectory)/shield/standalone.json + -Version "$(VSIX_VERSION)" + displayName: Set shield info + + - pwsh: | + New-Item -ItemType Directory -Force -Path build + Copy-Item *.vsix build/ + workingDirectory: ext/vscode + condition: and(succeeded(), eq('true', variables['UploadArtifact'])) + displayName: Copy *.vsix to build for upload + + templateContext: + outputs: + - output: pipelineArtifact + path: $(Build.ArtifactStagingDirectory)/shield + condition: and(succeeded(), eq('true', variables['UploadArtifact'])) + artifact: shield-vscode + displayName: Upload vscode shield json + + - output: pipelineArtifact + path: ext/vscode/build + condition: and(succeeded(), eq('true', variables['UploadArtifact'])) + artifact: vsix diff --git a/eng/pipelines/templates/stages/1es-redirect.yml b/eng/pipelines/templates/stages/1es-redirect.yml new file mode 100644 index 00000000000..745aa0e8cdb --- /dev/null +++ b/eng/pipelines/templates/stages/1es-redirect.yml @@ -0,0 +1,44 @@ +resources: + repositories: + - repository: 1ESPipelineTemplates + type: git + name: 1ESPipelineTemplates/1ESPipelineTemplates + ref: refs/tags/release + - repository: azure-sdk-build-tools + type: git + name: internal/azure-sdk-build-tools + ref: refs/tags/azure-sdk-build-tools_20230829.1 + +parameters: +- name: stages + type: stageList + default: [] +- name: Use1ESOfficial + type: boolean + default: true + +extends: + ${{ if and(parameters.Use1ESOfficial, eq(variables['System.TeamProject'], 'internal')) }}: + template: v1/1ES.Official.PipelineTemplate.yml@1ESPipelineTemplates + ${{ else }}: + template: v1/1ES.Unofficial.PipelineTemplate.yml@1ESPipelineTemplates + parameters: + settings: + skipBuildTagsForGitHubPullRequests: true + sdl: + credscan: + suppressionsFile: $(Build.SourcesDirectory)/eng/CredScanSuppression.json + sourceRepositoriesToScan: + exclude: + - repository: azure-sdk-build-tools + sourceAnalysisPool: + name: azsdk-pool-mms-win-2022-general + image: azsdk-pool-mms-win-2022-1espt + os: windows + psscriptanalyzer: + compiled: true + break: true + policy: M365 + + + stages: ${{ parameters.stages }} diff --git a/eng/pipelines/templates/stages/build-and-test.yml b/eng/pipelines/templates/stages/build-and-test.yml new file mode 100644 index 00000000000..9c8de745b4a --- /dev/null +++ b/eng/pipelines/templates/stages/build-and-test.yml @@ -0,0 +1,219 @@ +parameters: + - name: BuildMatrix + type: object + default: + Windows: + Pool: $(WINDOWSPOOL) + OSVmImage: $(WINDOWSVMIMAGE) + OS: windows + ImageKey: image + Variables: + BuildTarget: azd-windows-amd64.exe + BuildOutputName: azd.exe + BuildTestMsi: true + AZURE_DEV_CI_OS: win + Codeql.Enabled: true + Codeql.SkipTaskAutoInjection: false + Codeql.BuildIdentifier: cli_windows + Linux: + Pool: $(LINUXPOOL) + OSVmImage: $(LINUXVMIMAGE) + OS: linux + ImageKey: image + Variables: + BuildTarget: azd-linux-amd64 + BuildOutputName: azd + SetExecutableBit: true + SetShieldInfo: true + BuildLinuxPackages: true + AZURE_DEV_CI_OS: lin + Codeql.Enabled: true + Codeql.SkipTaskAutoInjection: false + Codeql.BuildIdentifier: cli_linux + Mac: + Pool: Azure Pipelines + OSVmImage: $(MACVMIMAGE) + OS: macOS + ImageKey: vmImage + Variables: + BuildTarget: azd-darwin-amd64 + BuildOutputName: azd + MacLocalSign: false + SetExecutableBit: true + AZURE_DEV_CI_OS: mac + # CodeQL on macOS not supported by the Azure DevOps task as-of current. + # Codeql.BuildIdentifier: cli_darwin + - name: CrossBuildMatrix + type: object + default: + # Compliant image name required + LinuxARM64: + Pool: $(LINUXARMPOOL) + OSVmImage: $(LINUXARMVMIMAGE) + OS: linux + ImageKey: image + HostArchitecture: Arm64 + PreBuildSteps: + - pwsh: sudo tdnf install -y build-essential + displayName: Install build-essential + Variables: + BuildTarget: azd-linux-arm64 + BuildOutputName: azd + SetExecutableBit: true + GOOS: linux + GOARCH: arm64 + BuildLinuxPackages: true + MacARM64: + Pool: Azure Pipelines + OSVmImage: $(MACVMIMAGE) + OS: macOS + ImageKey: vmImage + HostArchitecture: x86_64 + PreBuildSteps: [] + Variables: + BuildTarget: azd-darwin-arm64 + BuildOutputName: azd + SetExecutableBit: true + GOOS: darwin + GOARCH: arm64 + # CGO_ENABLED is required on MacOS to cross-compile pkg/outil/osversion + CGO_ENABLED: 1 + +stages: + - stage: BuildAndTest + variables: + - template: /eng/pipelines/templates/variables/globals.yml + - template: /eng/pipelines/templates/variables/image.yml + jobs: + - ${{ each build in parameters.BuildMatrix }}: + - template: /eng/pipelines/templates/jobs/build-cli.yml + parameters: + NameSuffix: ${{ build.key}} + Pool: ${{ build.value.Pool }} + ImageKey: ${{ build.value.ImageKey }} + OSVmImage: ${{ build.value.OSVmImage }} + OS: ${{ build.value.OS }} + Variables: ${{ build.value.Variables }} + + # This is separated today because Skip.LiveTest is a queue-time variable + # and cannot be set in a matrix entry. + - ${{ each build in parameters.CrossBuildMatrix }}: + - template: /eng/pipelines/templates/jobs/cross-build-cli.yml + parameters: + NameSuffix: ${{ build.key}} + Pool: ${{ build.value.Pool }} + ImageKey: ${{ build.value.ImageKey }} + OSVmImage: ${{ build.value.OSVmImage }} + OS: ${{ build.value.OS }} + PreBuildSteps: ${{ build.value.PreBuildSteps }} + HostArchitecture: ${{ build.value.HostArchitecture }} + Variables: ${{ build.value.Variables }} + + - job: MergeLinuxPackages + pool: + name: $(LINUXPOOL) + image: $(LINUXVMIMAGE) + os: linux + dependsOn: + - ${{ each build in parameters.CrossBuildMatrix }}: + - CrossBuildCLI_${{ build.key }} + - ${{ each build in parameters.BuildMatrix }}: + - BuildCLI_${{ build.key }} + steps: + - download: current + artifact: linux-packages-amd64 + displayName: Download linux-packages-amd64 + + - download: current + artifact: linux-packages-arm64 + displayName: Download linux-packages-arm64 + + # Merge the folders + - pwsh: | + New-Item -ItemType Directory -Path linux-packages + Get-ChildItem $(Pipeline.Workspace)/linux-packages-amd64 -Exclude '_manifest' | ForEach-Object { Copy-Item $_ linux-packages } + Get-ChildItem $(Pipeline.Workspace)/linux-packages-arm64 -Exclude '_manifest' | ForEach-Object { Copy-Item $_ linux-packages } + displayName: Merge linux packages + templateContext: + outputs: + - output: pipelineArtifact + path: linux-packages + artifact: linux-packages + displayName: Publish merged linux packages + + - job: ValidateCrossCompile + dependsOn: + - ${{ each build in parameters.CrossBuildMatrix }}: + - CrossBuildCLI_${{ build.key }} + pool: + name: $(LINUXARMPOOL) + image: $(LINUXARMVMIMAGE) + os: linux + timeoutInMinutes: 5 + steps: + - checkout: none + + - task: DownloadPipelineArtifact@2 + inputs: + artifact: azd-linux-arm64 + targetPath: $(Build.SourcesDirectory) + + - bash: pwd && ls && chmod +x ./azd-linux-arm64 && ./azd-linux-arm64 version + displayName: azd version + + - job: GenerateReleaseArtifacts + pool: + name: $(LINUXPOOL) + image: $(LINUXVMIMAGE) + os: linux + + steps: + - checkout: self + + - template: /eng/pipelines/templates/steps/setup-go.yml + + # Install scripts + - pwsh: | + New-Item -ItemType Directory -Path installer + Copy-Item cli/installer/*install-azd.ps1 installer/ + displayName: Copy installer scripts (*.ps1) for artifact upload + + # CLI ref docs + - pwsh: New-Item -ItemType Directory -Path docs + workingDirectory: $(Pipeline.Workspace) + displayName: Create docs artifact folder + + - pwsh: go run docgen.go + workingDirectory: cli/azd/docs + displayName: Generate CLI documentation + + - pwsh: Copy-Item $(Build.SourcesDirectory)/cli/azd/docs/md/* docs/ -Recurse + workingDirectory: $(Pipeline.Workspace) + displayName: Copy CLI docs for pipeline artifact staging + + # azure.yaml.json schema docs + - task: UsePythonVersion@0 + inputs: + versionSpec: 3.x + + - pwsh: pip install jsonschema2md + displayName: Install jsonschema2md + + - pwsh: jsonschema2md schemas/v1.0/azure.yaml.json $(Pipeline.Workspace)/docs/azure.yaml.schema.md + displayName: Generate azure.yaml schema + + # Upload docs for CLI ref and azure.yaml schema + - pwsh: Get-ChildItem . + workingDirectory: $(Pipeline.Workspace)/docs + displayName: Show doc artifacts to publish + + templateContext: + outputs: + - output: pipelineArtifact + path: installer + artifact: install-pwsh + + - output: pipelineArtifact + path: $(Pipeline.Workspace)/docs/ + artifact: docs + displayName: Upload generated documentation diff --git a/eng/pipelines/templates/stages/code-coverage-upload.yml b/eng/pipelines/templates/stages/code-coverage-upload.yml new file mode 100644 index 00000000000..bd83748fc68 --- /dev/null +++ b/eng/pipelines/templates/stages/code-coverage-upload.yml @@ -0,0 +1,73 @@ +stages: +- stage: CodeCoverage_Upload + condition: and(succeeded(), ne(variables['Skip.LiveTest'], 'true')) + dependsOn: BuildAndTest + + variables: + - template: /eng/pipelines/templates/variables/globals.yml + - template: /eng/pipelines/templates/variables/image.yml + + jobs: + - job: Upload + pool: + name: $(LINUXPOOL) + image: $(LINUXVMIMAGE) + os: linux + steps: + - template: /eng/pipelines/templates/steps/setup-go.yml + - template: /eng/pipelines/templates/steps/download-artifacts.yml + parameters: + Artifacts: + - cover-win + - cover-lin + - cover-mac + - pwsh: | + New-Item -ItemType Directory -Force -Path cover + New-Item -ItemType Directory -Force -Path cover-int + New-Item -ItemType Directory -Force -Path cover-unit + + $unitCoverage = (Get-ChildItem cover-*/unit).FullName -join "," + $integrationCoverage = (Get-ChildItem cover-*/int).FullName -join "," + + # Merge unit test coverage across platforms + go tool covdata merge -i="$unitCoverage" -o cover-unit + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + + # Merge integration test coverage across platforms + go tool covdata merge -i="$integrationCoverage" -o cover-int + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + + # Merge unit and integration code coverage + go tool covdata merge -i="cover-unit,cover-int" -o cover + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + + # Convert to text format + go tool covdata textfmt -i=cover -o cover.out + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + + go install github.com/axw/gocov/gocov@latest + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + go install github.com/AlekSi/gocov-xml@latest + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + + ~/go/bin/gocov convert cover.out | ~/go/bin/gocov-xml > coverage.xml + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + displayName: Merge code coverage files + + - task: PublishCodeCoverageResults@1 + inputs: + codeCoverageTool: Cobertura + summaryFileLocation: '$(Build.SourcesDirectory)/**/coverage.xml' + displayName: Publish Code Coverage to DevOps + + templateContext: + outputs: + - output: pipelineArtifact + path: cover-unit + artifact: cover-unit + displayName: Upload unit test code coverage + + - output: pipelineArtifact + path: cover-int + artifact: cover-int + displayName: Upload integration test code coverage diff --git a/eng/pipelines/templates/stages/publish.yml b/eng/pipelines/templates/stages/publish.yml new file mode 100644 index 00000000000..c8ac132452a --- /dev/null +++ b/eng/pipelines/templates/stages/publish.yml @@ -0,0 +1,579 @@ +stages: + - ${{ if eq(variables['Build.Repository.Name'], 'Azure/azure-dev') }}: + - stage: PublishCLI + dependsOn: Sign + condition: >- + and( + succeeded(), + ne(variables['Skip.Release'], 'true'), + or( + eq('Manual', variables['BuildReasonOverride']), + and( + eq('', variables['BuildReasonOverride']), + eq('Manual', variables['Build.Reason']) + ) + ) + ) + + variables: + - template: /eng/pipelines/templates/variables/image.yml + - template: /eng/pipelines/templates/variables/globals.yml + + jobs: + - deployment: Publish_Release + condition: >- + and( + succeeded(), + ne('true', variables['Skip.Publish']) + ) + environment: azure-dev + + pool: + name: azsdk-pool-mms-ubuntu-2004-general + image: azsdk-pool-mms-ubuntu-2004-1espt + os: linux + + templateContext: + inputs: + - input: checkout + repository: self + + strategy: + runOnce: + deploy: + steps: + - task: PowerShell@2 + inputs: + pwsh: true + targetType: filePath + filePath: eng/scripts/Set-CliVersionVariable.ps1 + displayName: Set CLI_VERSION + + - pwsh: | + # Initial upload locations + $publishUploadLocations = 'release/$(CLI_VERSION);release/latest' + + $isPublishingGa = eng/scripts/Test-ShouldReleasePackageVersion.ps1 ` + -CliVersion '$(CLI_VERSION)' + + if ($isPublishingGa) { + $publishUploadLocations += ";release/stable" + } + + Write-Host "Setting StorageUploadLocations to $publishUploadLocations" + Write-Host "###vso[task.setvariable variable=StorageUploadLocations]$publishUploadLocations" + displayName: Set StorageUploadLocations + + - pwsh: | + # Initial tag + $dockerTags = '$(CLI_VERSION)' + + $isPublishingGa = eng/scripts/Test-ShouldReleasePackageVersion.ps1 ` + -CliVersion '$(CLI_VERSION)' + + if ($isPublishingGa) { + $dockerTags += ";latest" + } + + Write-Host "Setting DockerImageTags to $dockerTags" + Write-Host "###vso[task.setvariable variable=DockerImageTags]$dockerTags" + displayName: Set DockerImageTags + + - template: /eng/pipelines/templates/steps/publish-cli.yml + parameters: + CreateGitHubRelease: true + PublishUploadLocations: $(StorageUploadLocations) + PublishShield: true + DockerImageTags: $(DockerImageTags) + ReleaseSyndicatedDockerContainer: true + PublishUpdatedDocs: true + UploadMsi: true + PublishBrewFormula: true + PublishArm64Binaries: true + + - deployment: Publish_Choco + dependsOn: Publish_Release + condition: >- + and( + succeeded(), + ne('true', variables['Skip.Publish']) + ) + environment: azure-dev + + pool: + name: azsdk-pool-mms-win-2022-general + image: azsdk-pool-mms-win-2022-1espt + os: windows + + templateContext: + inputs: + - input: checkout + repository: self + + strategy: + runOnce: + deploy: + steps: + - task: PowerShell@2 + inputs: + pwsh: true + targetType: filePath + filePath: eng/scripts/Set-CliVersionVariable.ps1 + displayName: Set CLI_VERSION + + - template: /eng/pipelines/templates/steps/publish-cli-choco.yml + parameters: + CliVersion: $(CLI_VERSION) + + - deployment: Publish_WinGet + dependsOn: Publish_Release + condition: >- + and( + succeeded(), + ne('true', variables['Skip.Publish']) + ) + environment: azure-dev + + pool: + name: azsdk-pool-mms-win-2022-general + image: azsdk-pool-mms-win-2022-1espt + os: windows + + templateContext: + inputs: + - input: checkout + repository: self + + strategy: + runOnce: + deploy: + steps: + - task: PowerShell@2 + inputs: + pwsh: true + targetType: filePath + filePath: eng/scripts/Set-CliVersionVariable.ps1 + displayName: Set CLI_VERSION + + - template: /eng/pipelines/templates/steps/publish-cli-winget.yml + parameters: + CliVersion: $(CLI_VERSION) + + - deployment: Increment_Version + condition: >- + and( + succeeded(), + ne('true', variables['Skip.IncrementVersion']) + ) + dependsOn: Publish_Release + environment: azure-dev + + pool: + name: azsdk-pool-mms-ubuntu-2004-general + image: azsdk-pool-mms-ubuntu-2004-1espt + os: linux + + templateContext: + inputs: + - input: checkout + repository: self + + strategy: + runOnce: + deploy: + steps: + - task: PowerShell@2 + inputs: + pwsh: true + targetType: filePath + filePath: eng/scripts/Update-CliVersion.ps1 + displayName: Increment CLI version + + - template: /eng/common/pipelines/templates/steps/create-pull-request.yml + parameters: + PRBranchName: cli-version-increment-$(Build.BuildId) + CommitMsg: Increment CLI version after release + PRTitle: Increment CLI version after release + + - stage: PublishVersionTxt + dependsOn: PublishCLI + + condition: >- + and( + succeeded(), + ne(variables['Skip.Release'], 'true'), + or( + eq('Manual', variables['BuildReasonOverride']), + and( + eq('', variables['BuildReasonOverride']), + eq('Manual', variables['Build.Reason']) + ) + ) + ) + + variables: + - template: /eng/pipelines/templates/variables/image.yml + - template: /eng/pipelines/templates/variables/globals.yml + + jobs: + - deployment: Upload_Version_Txt + condition: >- + and( + succeeded(), + ne('true', variables['Skip.Publish']) + ) + environment: azure-dev + + pool: + name: azsdk-pool-mms-win-2022-general + image: azsdk-pool-mms-win-2022-1espt + os: windows + + templateContext: + inputs: + - input: checkout + repository: self + + strategy: + runOnce: + deploy: + steps: + - task: PowerShell@2 + inputs: + pwsh: true + targetType: filePath + filePath: eng/scripts/Set-CliVersionVariable.ps1 + displayName: Set CLI_VERSION + + - task: PowerShell@2 + displayName: Set MSI_VERSION + inputs: + pwsh: true + targetType: filePath + filePath: eng/scripts/Get-MsiVersion.ps1 + arguments: >- + -CliVersion '$(CLI_VERSION)' + -DevOpsOutput + + - task: PowerShell@2 + displayName: Wait for WinGet package + inputs: + pwsh: true + targetType: filePath + filePath: eng/scripts/Wait-WinGetPackage.ps1 + arguments: >- + -PackageName 'Microsoft.Azd' + -PackageVersion '$(MSI_VERSION)' + + - task: PowerShell@2 + displayName: Wait for Choco package + inputs: + pwsh: true + targetType: filePath + filePath: eng/scripts/Wait-ChocoPackage.ps1 + arguments: >- + -PackageName 'azd' + -PackageVersion '$(MSI_VERSION)' + + - pwsh: | + New-Item -ItemType Directory -Path release + Write-Output $(CLI_VERSION) | Out-File -Encoding utf8 -FilePath ./release/version.txt + displayName: Write version.txt file for release + + - pwsh: | + $isPublishingGa = eng/scripts/Test-ShouldReleasePackageVersion.ps1 ` + -CliVersion '$(CLI_VERSION)' + + $publishUploadLocations = @('release/latest') + if ($isPublishingGa) { + $publishUploadLocations += @('release/stable') + } + + Get-ChildItem release/ + + foreach ($folder in $publishUploadLocations) { + Write-Host "Upload to azd/standalone/$folder" + az storage blob upload-batch ` + --account-name '$(azdev-storage-account-name)' ` + --account-key '$(azdev-storage-account-key)' ` + --auth-mode key ` + -s release/ ` + -d "azd/standalone/$folder" ` + --overwrite + + if ($LASTEXITCODE) { + Write-Error "Upload failed" + exit 1 + } + } + displayName: Upload version.txt to storage account + + - stage: Publish_Integration + dependsOn: Sign + + variables: + - template: /eng/pipelines/templates/variables/image.yml + - template: /eng/pipelines/templates/variables/globals.yml + + jobs: + # Only publish Continuous Deployment if this is the public repo + - ${{ if eq(variables['Build.Repository.Name'], 'Azure/azure-dev') }}: + - job: Publish_Continuous_Deployment + condition: >- + and( + succeeded(), + ne(variables['Skip.Release'], 'true'), + or( + in(variables['BuildReasonOverride'], 'IndividualCI', 'BatchedCI'), + and( + eq('', variables['BuildReasonOverride']), + in(variables['Build.Reason'], 'IndividualCI', 'BatchedCI') + ) + ) + ) + + pool: + name: $(LINUXPOOL) + image: $(LINUXVMIMAGE) + os: linux + + steps: + - checkout: self + - template: /eng/pipelines/templates/steps/set-cli-version-cd.yml + + - task: PowerShell@2 + inputs: + pwsh: true + targetType: filePath + filePath: eng/scripts/Set-CliVersionVariable.ps1 + displayName: Set CLI_VERSION + + - template: /eng/pipelines/templates/steps/publish-cli.yml + parameters: + CreateGitHubRelease: false + PublishUploadLocations: release/daily;daily/archive/$(Build.BuildId)-$(Build.SourceVersion) + PublishShield: false + DockerImageTags: daily;$(CLI_VERSION) + UploadMsi: true + PublishArm64Binaries: true + + - job: Publish_For_PR + condition: >- + and( + succeeded(), + ne(variables['Skip.Release'], 'true'), + or( + eq('PullRequest', variables['BuildReasonOverride']), + and( + eq('', variables['BuildReasonOverride']), + eq(variables['Build.Reason'], 'PullRequest') + ) + ) + ) + pool: + name: $(LINUXPOOL) + image: $(LINUXVMIMAGE) + os: linux + + variables: + ${{ if eq(variables['Build.Repository.Name'], 'Azure/azure-dev') }}: + storage-account-name: $(azdev-storage-account-name) + ${{ else }}: + storage-account-name: $(azdev-storage-account-name-pr) + + + steps: + - checkout: self + - pwsh: | + $PRNumber = '$(System.PullRequest.PullRequestNumber)' + if ($env:PRNUMBEROVERRIDE) { + Write-Host "PR Number override: $($env:PRNUMBEROVERRIDE)" + $PRNumber = "$($env:PRNUMBEROVERRIDE)" + } + Write-Host "##vso[task.setvariable variable=PRNumber]$PRNumber" + displayName: Set PR Number Variable + + - task: PowerShell@2 + inputs: + pwsh: true + targetType: filePath + filePath: eng/scripts/Set-CliVersionVariable.ps1 + displayName: Set CLI_VERSION + + - template: /eng/pipelines/templates/steps/publish-cli.yml + parameters: + CreateGitHubRelease: false + PublishUploadLocations: pr/$(PRNumber) + UploadInstaller: true + UploadMsi: true + PublishArm64Binaries: true + + ${{ if eq(variables['Build.Repository.Name'], 'Azure/azure-dev') }}: + PublishContainer: true + DockerImageTags: pr-$(PRNumber) + StorageAccountName: $(azdev-storage-account-name) + StorageAccountKey: $(azdev-storage-account-key) + ${{ else }}: + PublishContainer: false + StorageAccountName: $(azdev-storage-account-name-pr) + StorageAccountKey: $(azdev-storage-account-key-pr) + + + - pwsh: | + $urlBase = "https://$(storage-account-name).blob.core.windows.net/azd/standalone/pr/$(PRNumber)" + Write-Host "##vso[task.setvariable variable=UrlBase;isOutput=true]$urlBase" + name: GenerateUrlBase + displayName: Set UrlBase + + - task: DownloadPipelineArtifact@2 + inputs: + artifact: docs + path: docs + + - pwsh: | + $urlBase = "$(GenerateUrlBase.UrlBase)" + $linuxReleaseUrl = "$urlBase/azd-linux-amd64.tar.gz" + $linuxReleaseUrlArm64 = "$urlBase/azd-linux-arm64.tar.gz" + $macosReleaseUrl = "$urlBase/azd-darwin-amd64.zip" + $macosReleaseUrlArm64 = "$urlBase/azd-darwin-arm64.zip" + $windowsReleaseUrl = "$urlBase/azd-windows-amd64.zip" + $msiReleaseUrl = "$urlBase/azd-windows-amd64.msi" + + $refDocContent = Get-Content docs/azd.md -Raw + + $content = @" + + ## Azure Dev CLI Install Instructions + + ### Install scripts + + #### MacOS/Linux + + > May elevate using ``sudo`` on some platforms and configurations + + bash: + `````` + curl -fsSL $urlBase/uninstall-azd.sh | bash; + curl -fsSL $urlBase/install-azd.sh | bash -s -- --base-url $urlBase --version '' --verbose --skip-verify + `````` + + pwsh: + `````` + Invoke-RestMethod '$urlBase/uninstall-azd.ps1' -OutFile uninstall-azd.ps1; ./uninstall-azd.ps1 + Invoke-RestMethod '$urlBase/install-azd.ps1' -OutFile install-azd.ps1; ./install-azd.ps1 -BaseUrl '$urlBase' -Version '' -SkipVerify -Verbose + `````` + + + #### Windows + + PowerShell install + + `````` + powershell -c "Set-ExecutionPolicy Bypass Process; irm '$urlBase/uninstall-azd.ps1' > uninstall-azd.ps1; ./uninstall-azd.ps1;" + powershell -c "Set-ExecutionPolicy Bypass Process; irm '$urlBase/install-azd.ps1' > install-azd.ps1; ./install-azd.ps1 -BaseUrl '$urlBase' -Version '' -SkipVerify -Verbose;" + `````` + + MSI install + `````` + powershell -c "irm '$msiReleaseUrl' -OutFile azd-windows-amd64.msi; msiexec /i azd-windows-amd64.msi /qn" + `````` + + ### Standalone Binary + + * Linux - + * x86_64 - $linuxReleaseUrl + * ARM64 - $linuxReleaseUrlArm64 + * MacOS - + * x86_64 - $macosReleaseUrl + * ARM64 - $macosReleaseUrlArm64 + * Windows - $windowsReleaseUrl + + ### MSI + + * $msiReleaseUrl + + ## Documentation + +
+ learn.microsoft.com documentation + + $refDocContent + +
+ "@ + $file = New-TemporaryFile + Set-Content -Path $file -Value $content + Write-Host "##vso[task.setvariable variable=CommentBodyFile]$file" + displayName: Write body content to temporary file + + - task: PowerShell@2 + displayName: Add PR comment + inputs: + pwsh: true + targetType: filePath + filePath: ./eng/scripts/Update-PRComment.ps1 + arguments: >- + -Repo "$(Build.Repository.Name)" + -PrNumber $(PRNumber) + -Tag "" + -BodyFile $(CommentBodyFile) + env: + GH_TOKEN: $(azuresdk-github-pat) + + - ${{ if eq(variables['Build.Repository.Name'], 'Azure/azure-dev') }}: + - stage: PublishInstallers + dependsOn: Sign + condition: >- + and( + succeeded(), + ne(variables['Skip.Release'], 'true'), + or( + eq('Manual', variables['BuildReasonOverride']), + and( + eq('', variables['BuildReasonOverride']), + eq('Manual', variables['Build.Reason']) + ) + ) + ) + + variables: + - template: /eng/pipelines/templates/variables/image.yml + - template: /eng/pipelines/templates/variables/globals.yml + + jobs: + - deployment: PublishInstallers + environment: azure-dev + pool: + name: azsdk-pool-mms-ubuntu-2004-general + image: azsdk-pool-mms-ubuntu-2004-1espt + os: linux + + templateContext: + inputs: + - input: checkout + repository: self + + strategy: + runOnce: + deploy: + steps: + - task: DownloadPipelineArtifact@2 + inputs: + artifact: signed-win + path: signed-win + + - pwsh: | + New-Item -ItemType Directory -Path script-release + Copy-Item signed-win/*.ps1 script-release/ + Copy-Item cli/installer/*.sh script-release/ + displayName: Copy scripts for release upload + + - pwsh: | + az storage blob upload-batch ` + --account-name '$(azdev-storage-account-name)' ` + --account-key '$(azdev-storage-account-key)' ` + --auth-mode key ` + -s script-release/ ` + -d "azd/standalone/installer" ` + --overwrite + displayName: Upload installer to storage location diff --git a/eng/pipelines/templates/stages/sign.yml b/eng/pipelines/templates/stages/sign.yml new file mode 100644 index 00000000000..4c866909e95 --- /dev/null +++ b/eng/pipelines/templates/stages/sign.yml @@ -0,0 +1,204 @@ + +stages: + - stage: Sign + dependsOn: BuildAndTest + + variables: + - template: /eng/pipelines/templates/variables/globals.yml + - template: /eng/pipelines/templates/variables/image.yml + + jobs: + - job: SignMac + pool: + name: $(WINDOWSPOOL) + image: $(WINDOWSVMIMAGE) + os: windows + + steps: + - task: DownloadPipelineArtifact@2 + inputs: + artifact: azd-darwin-amd64 + path: mac-artifacts + + - task: DownloadPipelineArtifact@2 + inputs: + artifact: azd-darwin-arm64 + path: mac-artifacts + + - pwsh: | + New-Item -ItemType Directory -Path mac + + Compress-Archive ` + -Path mac-artifacts/azd-darwin-amd64 ` + -DestinationPath mac/azd-darwin-amd64.zip + + Compress-Archive ` + -Path mac-artifacts/azd-darwin-arm64 ` + -DestinationPath mac/azd-darwin-arm64.zip + displayName: Package mac binary for signing + + - ${{ if and(in(variables['Build.Reason'], 'IndividualCI', 'BatchedCI', 'Manual'), eq(variables['Build.Repository.Name'], 'Azure/azure-dev')) }}: + - template: pipelines/steps/azd-cli-mac-signing.yml@azure-sdk-build-tools + parameters: + MacPath: mac + + - ${{ else }}: + - pwsh: Write-Host "Skipping signing. Build reason - $(Build.Reason)" + displayName: Signing process skipped for non-release build + + - pwsh: | + Expand-Archive -Path mac/azd-darwin-amd64.zip -DestinationPath mac/ + Expand-Archive -Path mac/azd-darwin-arm64.zip -DestinationPath mac/ + + Remove-Item mac/azd-darwin-amd64.zip + Remove-Item mac/azd-darwin-arm64.zip + displayName: Extract azd-darwin-amd64 from zip and remove zip + + - pwsh: | + New-Item -ItemType Directory -Path signed-mac + Copy-Item mac/* signed-mac/ -Recurse + displayName: Copy signing outputs + condition: always() + + # TODO: Replace with https://github.com/Azure/azure-sdk-tools/blob/main/eng/common/pipelines/templates/steps/publish-artifact.yml + # when the common engsys is imported. + # https://github.com/Azure/azure-dev/issues/956 + - task: 1ES.PublishPipelineArtifact@1 + condition: succeeded() + displayName: Publish Signed Artifacts + inputs: + artifactName: signed-mac + path: signed-mac/ + + - task: 1ES.PublishPipelineArtifact@1 + condition: failed() + displayName: Publish failed Signed Artifacts + inputs: + artifactName: signed-mac-FailedAttempt$(System.JobAttempt) + path: signed-mac/ + + - job: SignWindows + pool: + name: $(WINDOWSPOOL) + image: $(WINDOWSVMIMAGE) + os: windows + + steps: + # Checkout required to build MSI + - checkout: self + + - task: DownloadPipelineArtifact@2 + inputs: + artifact: azd-windows-amd64.exe + path: win + + - task: DownloadPipelineArtifact@2 + inputs: + artifact: install-pwsh + path: installer + + - pwsh: Copy-Item installer/*.ps1 win + displayName: Copy install scripts to win/ + + - ${{ if and(in(variables['Build.Reason'], 'IndividualCI', 'BatchedCI', 'Manual'), eq(variables['Build.Repository.Name'], 'Azure/azure-dev')) }}: + - template: pipelines/steps/azd-cli-win-signing.yml@azure-sdk-build-tools + parameters: + WinPath: win + WinPattern: '**' + + - ${{ else }}: + - pwsh: Write-Host "Skipping signing. Build reason - $(Build.Reason)" + displayName: Signing process skipped for non-release build + + - pwsh: | + New-Item -ItemType Directory -Path signed-win + Copy-Item win/* signed-win/ -Recurse + Copy-Item win/azd-windows-amd64.exe cli/azd/azd.exe + displayName: Copy signing outputs for publishing and MSI build + condition: always() + + - task: PowerShell@2 + inputs: + pwsh: true + targetType: filePath + filePath: eng/scripts/Set-CliVersionVariable.ps1 + displayName: Set CLI_VERSION for MSI build + + - template: /eng/pipelines/templates/steps/build-msi.yml + parameters: + Title: Build Release MSI + # Only build for release in a manual (releasing) build. Otherwise + # the package version will be 0.1.0 with upgrade logic that allows + # it to be installed over any previously installed version. + ShouldBuildForRelease: ${{ eq(variables['Build.Reason'], 'Manual') }} + + - ${{ if and(in(variables['Build.Reason'], 'IndividualCI', 'BatchedCI', 'Manual'), eq(variables['Build.Repository.Name'], 'Azure/azure-dev')) }}: + - template: pipelines/steps/azd-cli-win-signing.yml@azure-sdk-build-tools + parameters: + WinPath: cli/installer/windows/bin/Release + WinPattern: '*.msi' + + - ${{ else }}: + - pwsh: Write-Host "Skipping signing. Build reason - $(Build.Reason)" + displayName: Signing process skipped for non-release build + + - pwsh: Copy-Item cli/installer/windows/bin/Release/* signed-win/ + displayName: Copy MSI for publishing + + # TODO: Replace with https://github.com/Azure/azure-sdk-tools/blob/main/eng/common/pipelines/templates/steps/publish-artifact.yml + # when the common engsys is imported. + # https://github.com/Azure/azure-dev/issues/956 + - task: 1ES.PublishPipelineArtifact@1 + condition: succeeded() + displayName: Publish Signed Artifacts + inputs: + artifactName: signed-win + path: signed-win/ + + - task: 1ES.PublishPipelineArtifact@1 + condition: failed() + displayName: Publish failed Signed Artifacts + inputs: + artifactName: signed-win-FailedAttempt$(System.JobAttempt) + path: signed-win/ + + - job: SignLinux + pool: + name: $(WINDOWSPOOL) + image: $(WINDOWSVMIMAGE) + os: windows + + steps: + - task: DownloadPipelineArtifact@2 + inputs: + artifact: linux-packages + path: linux + + - ${{ if and(in(variables['Build.Reason'], 'IndividualCI', 'BatchedCI', 'Manual'), eq(variables['Build.Repository.Name'], 'Azure/azure-dev')) }}: + - template: pipelines/steps/azd-cli-linux-signing.yml@azure-sdk-build-tools + parameters: + LinuxPath: linux + + - ${{ else }}: + - pwsh: Write-Host "Skipping signing. Build reason - $(Build.Reason)" + displayName: Signing process skipped for non-release build + + - pwsh: | + New-Item -ItemType Directory -Path signed-linux + Copy-Item linux/* signed-linux/ -Recurse + displayName: Copy signing outputs + condition: always() + + - task: 1ES.PublishPipelineArtifact@1 + condition: succeeded() + displayName: Publish Signed Artifacts + inputs: + artifactName: signed-linux + path: signed-linux/ + + - task: 1ES.PublishPipelineArtifact@1 + condition: failed() + displayName: Publish failed Signed Artifacts + inputs: + artifactName: signed-linux-FailedAttempt$(System.JobAttempt) + path: signed-linux/ \ No newline at end of file diff --git a/eng/pipelines/templates/stages/verify-installers.yml b/eng/pipelines/templates/stages/verify-installers.yml new file mode 100644 index 00000000000..b4b8d232e68 --- /dev/null +++ b/eng/pipelines/templates/stages/verify-installers.yml @@ -0,0 +1,322 @@ +parameters: +- name: VerifyMatrix + type: object + default: + LinuxDockerSh: + Pool: $(LINUXPOOL) + OSVmImage: $(LINUXVMIMAGE) + ImageKey: image + OS: linux + Variables: + TestShell: pwsh + TestInstallCommand: >- + ./test-installer-containers.ps1 + -BaseUrl "http://host.docker.internal:8080" + -Version '' + -ContainerPrefix '$(docker-mirror-tag-prefix)/' + -AdditionalRunArgs '--add-host=host.docker.internal:host-gateway' + LinuxSh: + Pool: $(LINUXPOOL) + OSVmImage: $(LINUXVMIMAGE) + ImageKey: image + OS: linux + Variables: + TestShell: bash + TestInstallCommand: >- + ./test-sh-install.sh "bash" "$BASEURL" "" && + ./test-telemetry-functions.sh "telemetry/linux.sh.telemetry.csv" && + ./test-sh-install-errors.sh "bash" "$BASEURL" "" + + LinuxPwsh: + Pool: $(LINUXPOOL) + OSVmImage: $(LINUXVMIMAGE) + ImageKey: image + OS: linux + Variables: + TestShell: pwsh + TestInstallCommand: >- + ./test-pwsh-xplat-install.ps1 + -BaseUrl $env:BASEURL + -Version '' + -InstallShScriptUrl "$($env:BASEURL)/install-azd.sh" + -UninstallShScriptUrl "$($env:BASEURL)/uninstall-azd.sh"; + ./test-telemetry-functions.ps1 -NonInteractive -Shell pwsh -ExpectedFieldMap telemetry/linux.telemetry.json + + Mac11Sh: + Pool: Azure Pipelines + OSVmImage: $(MACVMIMAGE) + ImageKey: vmImage + OS: macOS + Variables: + TestShell: bash + TestInstallCommand: >- + ./test-sh-install.sh "bash" "$BASEURL" "" && + ./test-telemetry-functions.sh "telemetry/macos11.sh.telemetry.csv" && + ./test-sh-install-errors.sh "bash" "$BASEURL" "" + + Mac12Sh: + Pool: Azure Pipelines + OSVmImage: $(MACVMIMAGE12) + ImageKey: vmImage + OS: macOS + Variables: + TestShell: bash + TestInstallCommand: >- + ./test-sh-install.sh "bash" "$BASEURL" "" && + ./test-telemetry-functions.sh "telemetry/macos12.sh.telemetry.csv" && + ./test-sh-install-errors.sh "bash" "$BASEURL" "" + + Mac12Pwsh: + Pool: Azure Pipelines + OSVmImage: $(MACVMIMAGE12) + ImageKey: vmImage + OS: macOS + Variables: + TestShell: pwsh + # Should also test telemetry functions but cannot because of macOS + # host limitations in DevOps which do not reproduce on non-DevOps + # macs. Disabled for now. + # ./test-telemetry-functions.ps1 -Shell pwsh -ExpectedFieldMap telemetry/macos.telemetry.json + TestInstallCommand: >- + ./test-pwsh-xplat-install.ps1 + -BaseUrl $env:BASEURL + -Version '' + -InstallShScriptUrl "$($env:BASEURL)/install-azd.sh" + -UninstallShScriptUrl "$($env:BASEURL)/uninstall-azd.sh" + + Mac11Pwsh: + Pool: Azure Pipelines + OSVmImage: $(MACVMIMAGE) + ImageKey: vmImage + OS: macOS + Variables: + TestShell: pwsh + # Should also test telemetry functions but cannot because of macOS + # host limitations in DevOps which do not reproduce on non-DevOps + # macs. Disabled for now. + # ./test-telemetry-functions.ps1 -Shell pwsh -ExpectedFieldMap telemetry/macos.telemetry.json + TestInstallCommand: >- + ./test-pwsh-xplat-install.ps1 + -BaseUrl $env:BASEURL + -Version '' + -InstallShScriptUrl "$($env:BASEURL)/install-azd.sh" + -UninstallShScriptUrl "$($env:BASEURL)/uninstall-azd.sh" + + WindowsCmd: + Pool: $(WINDOWSPOOL) + OSVmImage: $(WINDOWSVMIMAGE) + ImageKey: image + OS: windows + Variables: + TestShell: cmd + TestInstallCommand: cmd /c test-windows-install.cmd %BASEURL% + + WindowsPwsh: + Pool: $(WINDOWSPOOL) + OSVmImage: $(WINDOWSVMIMAGE) + ImageKey: image + OS: + Variables: + TestShell: pwsh + TestInstallCommand: >- + $ErrorActionPreference = 'Stop'; + ./test-win-install.ps1 -BaseUrl $env:BASEURL -Version ''; + ./test-telemetry-functions.ps1 -Shell pwsh -ExpectedFieldMap telemetry/windows.pwsh.telemetry.json + + WindowsPowerShell: + Pool: $(WINDOWSPOOL) + OSVmImage: $(WINDOWSVMIMAGE) + ImageKey: image + OS: windows + Variables: + TestShell: powershell + TestInstallCommand: >- + $ErrorActionPreference = 'Stop'; + ./test-win-install.ps1 -BaseUrl $env:BASEURL -Version ''; + ./test-telemetry-functions.ps1 -Shell powershell -ExpectedFieldMap telemetry/windows.powershell.telemetry.json + + +- name: LinuxPackageMatrix + type: object + default: + LinuxAMD64: + Pool: $(LINUXPOOL) + OSVmImage: $(LINUXVMIMAGE) + HostArchitecture: amd64 + OS: linux + Variables: + Architecture: amd64 + # TODO: When Docker can be installed and run properly on the ARM + # host this can be used to validate the ARM64 Linux packages. + # https://github.com/Azure/azure-dev/issues/2617 + # LinuxARM64: + # Pool: $(LINUXARMPOOL) + # OSVmImage: $(LINUXARMVMIMAGE) + # HostArchitecture: arm64 + # OS: linux + # Variables: + # Architecture: arm64 + +stages: + - stage: Verify_Installers + condition: and(succeeded(), ne(variables['Skip.VerifyInstallers'], 'true')) + dependsOn: BuildAndTest + + variables: + - template: /eng/pipelines/templates/variables/globals.yml + - template: /eng/pipelines/templates/variables/image.yml + + jobs: + - job: Compress_For_Hosting + pool: + name: $(LINUXPOOL) + image: $(LINUXVMIMAGE) + os: linux + + steps: + - checkout: self + + - task: DownloadPipelineArtifact@2 + inputs: + artifact: azd-windows-amd64.exe + path: azd-windows-amd64.exe + + - task: DownloadPipelineArtifact@2 + inputs: + artifact: azd-linux-amd64 + path: azd-linux-amd64 + + - task: DownloadPipelineArtifact@2 + inputs: + artifact: azd-darwin-amd64 + path: azd-darwin-amd64 + + - task: DownloadPipelineArtifact@2 + inputs: + artifact: test-msi + path: msi + + - pwsh: | + Write-Host "Moving downloaded files to hosting folder" + New-Item -ItemType Directory -Path hosting + + Write-Host "Compressing artifacts as if publishing" + zip hosting/azd-windows-amd64.zip -j azd-windows-amd64.exe/azd-windows-amd64.exe + + chmod +x azd-darwin-amd64/azd-darwin-amd64 + zip hosting/azd-darwin-amd64.zip -j azd-darwin-amd64/azd-darwin-amd64 + + chmod +x azd-linux-amd64/azd-linux-amd64 + tar -C azd-linux-amd64 -cvzf hosting/azd-linux-amd64.tar.gz azd-linux-amd64 + + Copy-Item msi/azd-windows-amd64.msi hosting/ + + Copy-Item cli/installer/*stall-azd.* hosting/ + + Get-ChildItem hosting/ -Recurse | Select-Object -Property Name,Size + displayName: Move folders to hosting location + + - task: 1ES.PublishPipelineArtifact@1 + inputs: + targetPath: hosting + artifact: test-hosting + + - job: Verify_MSI + dependsOn: Compress_For_Hosting + + pool: + name: $(WINDOWSPOOL) + image: $(WINDOWSVMIMAGE) + os: windows + + variables: + AZURE_DEV_COLLECT_TELEMETRY: no + strategy: + matrix: + PerUser: + PerMachine: $false + AllUsers: + PerMachine: $true + steps: + - checkout: self + + - task: DownloadPipelineArtifact@2 + inputs: + artifact: test-msi + path: msi + + - task: PowerShell@2 + inputs: + pwsh: true + targetType: filePath + filePath: cli/installer/windows/test-win-msi.ps1 + arguments: >- + -PerMachine:$(PerMachine) + -MsiPath msi/azd-windows-amd64.msi + # Do not exit on first Write-Error, write all messages and let the + # script handle exiting with an error status. + errorActionPreference: continue + displayName: Test MSI + + - ${{ each build in parameters.VerifyMatrix }}: + - template: /eng/pipelines/templates/jobs/verify-installers.yml + parameters: + NameSuffix: ${{ build.key}} + Pool: ${{ build.value.Pool }} + ImageKey: ${{ build.value.ImageKey }} + OSVmImage: ${{ build.value.OSVmImage }} + OS: ${{ build.value.OS }} + Variables: ${{ build.value.Variables }} + + - job: Verify_Mac_InstallOver + dependsOn: Compress_For_Hosting + pool: + name: Azure Pipelines + vmImage: $(MACVMIMAGE12) + os: macOS + + steps: + - checkout: self + + - bash: ./install-azd.sh --version daily --verbose + displayName: Install "daily" version + workingDirectory: cli/installer/ + + - pwsh: azd version + displayName: Run azd version + + - bash: ./install-azd.sh --version latest --verbose + displayName: Install "latest" version + workingDirectory: cli/installer/ + + - pwsh: azd version + displayName: Run azd version (expect no failure) + + - ${{ each build in parameters.LinuxPackageMatrix }}: + - job: Verify_LinuxPackages_${{ build.key }} + displayName: Verify_LinuxPackages ${{ build.key }} + + pool: + name: ${{ build.value.Pool}} + image: ${{ build.value.OSVmImage }} + os: ${{ build.value.OS }} + hostArchitecture: ${{ build.value.HostArchitecture }} + + variables: + ${{ insert }}: ${{ build.value.Variables }} + + steps: + - checkout: self + + - task: DownloadPipelineArtifact@2 + inputs: + artifact: linux-packages-$(Architecture) + path: cli/installer/fpm + + - task: PowerShell@2 + displayName: Verify Linux Packages + inputs: + pwsh: true + workingDirectory: cli/installer/fpm + filePath: eng/scripts/Test-LinuxPackages.ps1 + arguments: -DockerImagePrefix "$(docker-mirror-tag-prefix)/" diff --git a/eng/pipelines/templates/stages/vscode-build-and-test.yml b/eng/pipelines/templates/stages/vscode-build-and-test.yml new file mode 100644 index 00000000000..89bcd8bc164 --- /dev/null +++ b/eng/pipelines/templates/stages/vscode-build-and-test.yml @@ -0,0 +1,45 @@ +parameters: + - name: BuildMatrix + type: object + default: + Windows: + Pool: $(WINDOWSPOOL) + ImageKey: image + OSVmImage: $(WINDOWSVMIMAGE) + OS: windows + Variables: {} + + Linux: + Pool: $(LINUXPOOL) + ImageKey: image + OSVmImage: $(LINUXVMIMAGE) + OS: linux + Variables: + UploadArtifact: 'true' + Codeql.Enabled: true + Codeql.SkipTaskAutoInjection: false + Codeql.BuildIdentifier: vscode_linux + + Mac: + Pool: Azure Pipelines + ImageKey: vmImage + OSVmImage: $(MACVMIMAGE) + OS: macOS + Variables: {} + +stages: + - stage: BuildAndTest + variables: + - template: /eng/pipelines/templates/variables/globals.yml + - template: /eng/pipelines/templates/variables/image.yml + + jobs: + - ${{ each build in parameters.BuildMatrix }}: + - template: /eng/pipelines/templates/jobs/vscode-build.yml + parameters: + NameSuffix: ${{ build.key }} + Pool: ${{ build.value.Pool }} + ImageKey: ${{ build.value.ImageKey }} + OSVmImage: ${{ build.value.OSVmImage }} + OS: ${{ build.value.OS }} + Variables: ${{ build.value.Variables }} diff --git a/eng/pipelines/templates/stages/vscode-publish-integration.yml b/eng/pipelines/templates/stages/vscode-publish-integration.yml new file mode 100644 index 00000000000..c2a42eef190 --- /dev/null +++ b/eng/pipelines/templates/stages/vscode-publish-integration.yml @@ -0,0 +1,106 @@ +stages: + - stage: PublishIntegration + dependsOn: Sign + + variables: + - template: /eng/pipelines/templates/variables/globals.yml + - template: /eng/pipelines/templates/variables/image.yml + + jobs: + - job: Publish_Continuous_Deployment + condition: >- + and( + succeeded(), + ne(variables['Skip.Release'], 'true'), + or( + in(variables['BuildReasonOverride'], 'IndividualCI', 'BatchedCI'), + and( + eq('', variables['BuildReasonOverride']), + in(variables['Build.Reason'], 'IndividualCI', 'BatchedCI') + ) + ) + ) + + pool: + name: $(LINUXPOOL) + image: $(LINUXVMIMAGE) + os: linux + + steps: + - checkout: self + + - template: /eng/pipelines/templates/steps/set-vscode-version.yml + + - template: /eng/pipelines/templates/steps/publish-vscode.yml + parameters: + PublishLocations: vscode/release/daily;vscode/daily/archive/$(Build.BuildId)-$(Build.SourceVersion) + + - job: Publish_For_PR + condition: >- + and( + succeeded(), + ne(variables['Skip.Release'], 'true'), + or( + eq('PullRequest', variables['BuildReasonOverride']), + and( + eq('', variables['BuildReasonOverride']), + eq(variables['Build.Reason'], 'PullRequest') + ) + ) + ) + pool: + name: $(LINUXPOOL) + image: $(LINUXVMIMAGE) + os: linux + + steps: + - checkout: self + + - pwsh: | + $PRNumber = '$(System.PullRequest.PullRequestNumber)' + if ($env:PRNUMBEROVERRIDE) { + Write-Host "PR Number override: $($env:PRNUMBEROVERRIDE)" + $PRNumber = $env:PRNUMBEROVERRIDE + } + Write-Host "##vso[task.setvariable variable=PRNumber]$PRNumber" + displayName: Set PR Number Variable + + - template: /eng/pipelines/templates/steps/set-vscode-version.yml + + - template: /eng/pipelines/templates/steps/publish-vscode.yml + parameters: + PublishLocations: vscode/pr/$(PRNumber) + + - pwsh: | + $downloadUrl = "https://$(azdev-storage-account-name).blob.core.windows.net/azd/vscode/pr/$(PRNumber)/azure-dev-$(VSIX_VERSION).vsix" + + $content = @" + + ## VSCode Extension Installation Instructions + + 1. Download the extension at $downloadUrl + 2. Extract the extension from the compressed file + 3. In vscode + a. Open "Extensions" (Ctrl+Shift+X) + b. Click the \`...\` menu at top of Extensions sidebar + c. Click "Install from VSIX" + d. Select location of downloaded file + "@ + $file = New-TemporaryFile + Set-Content -Path $file -Value $content + Write-Host "##vso[task.setvariable variable=CommentBodyFile]$file" + displayName: Write body content to temporary file + + - task: PowerShell@2 + displayName: Add PR comment + inputs: + pwsh: true + targetType: filePath + filePath: ./eng/scripts/Update-PRComment.ps1 + arguments: >- + -Repo "azure/azure-dev" + -PrNumber $(PRNumber) + -Tag "" + -BodyFile $(CommentBodyFile) + env: + GH_TOKEN: $(azuresdk-github-pat) diff --git a/eng/pipelines/templates/stages/vscode-publish-manual.yml b/eng/pipelines/templates/stages/vscode-publish-manual.yml new file mode 100644 index 00000000000..866dbb9e13f --- /dev/null +++ b/eng/pipelines/templates/stages/vscode-publish-manual.yml @@ -0,0 +1,80 @@ +stages: + - stage: PublishManual + dependsOn: Sign + condition: >- + and( + succeeded(), + ne(variables['Skip.Release'], 'true'), + or( + eq('Manual', variables['BuildReasonOverride']), + and( + eq('', variables['BuildReasonOverride']), + eq(variables['Build.Reason'], 'Manual') + ) + ) + ) + + variables: + - template: /eng/pipelines/templates/variables/globals.yml + - template: /eng/pipelines/templates/variables/image.yml + + jobs: + - deployment: Publish_Release + environment: azure-dev + pool: + name: azsdk-pool-mms-ubuntu-2004-general + image: azsdk-pool-mms-ubuntu-2004-1espt + os: linux + + templateContext: + inputs: + - input: checkout + repository: self + + strategy: + runOnce: + deploy: + steps: + - template: /eng/pipelines/templates/steps/set-vscode-version.yml + + - template: /eng/pipelines/templates/steps/publish-vscode.yml + parameters: + PublishLocations: vscode/release/$(VSIX_VERSION);vscode/release/latest + TagRepository: true + UpdateShield: true + + - deployment: Increment_Version + condition: >- + and( + succeeded(), + ne('true', variables['Skip.IncrementVersion']) + ) + dependsOn: Publish_Release + environment: azure-dev + + pool: + name: azsdk-pool-mms-ubuntu-2004-general + image: azsdk-pool-mms-ubuntu-2004-1espt + os: linux + + templateContext: + inputs: + - input: checkout + repository: self + + strategy: + runOnce: + deploy: + steps: + - task: PowerShell@2 + inputs: + pwsh: true + targetType: filePath + filePath: eng/scripts/Update-VscodeExtensionVersion.ps1 + displayName: Increment VSCode Extension version + + - template: /eng/common/pipelines/templates/steps/create-pull-request.yml + parameters: + PRBranchName: vscode-version-increment-$(Build.BuildId) + CommitMsg: Increment VSCode Extension version after release + PRTitle: Increment VSCode Extension version after release diff --git a/eng/pipelines/templates/stages/vscode-sign.yml b/eng/pipelines/templates/stages/vscode-sign.yml new file mode 100644 index 00000000000..fee8d2193b4 --- /dev/null +++ b/eng/pipelines/templates/stages/vscode-sign.yml @@ -0,0 +1,52 @@ + +stages: + - stage: Sign + dependsOn: BuildAndTest + + variables: + - template: /eng/pipelines/templates/variables/globals.yml + - template: /eng/pipelines/templates/variables/image.yml + + jobs: + - job: Sign + pool: + name: $(WINDOWSPOOL) + image: $(WINDOWSVMIMAGE) + os: windows + + steps: + - checkout: self + + - task: DownloadPipelineArtifact@2 + inputs: + artifact: vsix + path: vsix + + - ${{ if in(variables['Build.Reason'], 'IndividualCI', 'BatchedCI', 'Manual') }}: + - template: pipelines/steps/azd-vscode-signing.yml@azure-sdk-build-tools + parameters: + VsixPath: vsix + + - ${{ else }}: + - pwsh: Write-Host "Skipping signing. Build reason - $(Build.Reason)" + displayName: Signing process skipped for non-release build + + - pwsh: | + New-Item -ItemType Directory -Path signed + Copy-Item vsix/ signed/ -Recurse + displayName: Copy signing outputs + condition: always() + + templateContext: + outputs: + - output: pipelineArtifact + condition: succeeded() + displayName: Publish Signed Artifacts + artifact: signed + path: signed/ + + - output: pipelineArtifact + condition: failed() + displayName: Publish failed Signed Artifacts + artifact: signed-FailedAttempt$(System.JobAttempt) + path: signed/ diff --git a/eng/pipelines/templates/steps/publish-cli-choco.yml b/eng/pipelines/templates/steps/publish-cli-choco.yml index 8364123dc3c..d4ccc874456 100644 --- a/eng/pipelines/templates/steps/publish-cli-choco.yml +++ b/eng/pipelines/templates/steps/publish-cli-choco.yml @@ -48,9 +48,11 @@ steps: -Version $(MSI_VERSION) -Tag 'azure-dev-cli_${{ parameters.CliVersion }}' - - publish: cli/installer/choco/azd.$(MSI_VERSION).nupkg - artifact: choco-package + - task: 1ES.PublishPipelineArtifact@1 displayName: Publish Choco Package Artifact + inputs: + targetPath: cli/installer/choco/azd.$(MSI_VERSION).nupkg + artifact: choco-package - pwsh: | # Defense in depth: Legacy argument passing may be needed here diff --git a/eng/pipelines/templates/steps/publish-cli-winget.yml b/eng/pipelines/templates/steps/publish-cli-winget.yml index 4bdd3fce661..fd7e9de8930 100644 --- a/eng/pipelines/templates/steps/publish-cli-winget.yml +++ b/eng/pipelines/templates/steps/publish-cli-winget.yml @@ -48,6 +48,8 @@ steps: -GitHubToken ${{ parameters.GitHubToken }} -Submit:$$(SubmitWinGetPackage) - - publish: winget - artifact: WinGetManifest + - task: 1ES.PublishPipelineArtifact@1 displayName: Upload updated WinGet manifest + inputs: + targetPath: winget + artifact: WinGetManifest diff --git a/eng/pipelines/templates/steps/publish-cli.yml b/eng/pipelines/templates/steps/publish-cli.yml index f85011b3c34..05656802feb 100644 --- a/eng/pipelines/templates/steps/publish-cli.yml +++ b/eng/pipelines/templates/steps/publish-cli.yml @@ -37,6 +37,7 @@ steps: -DevOpsOutputFormat displayName: Verify and set GitHub Release Tag + # TODO: Docker stuff should be handled as per: https://github.com/Azure/azure-sdk-tools/commit/2623b00fc5b660d48e2301977602ddd8f934ac4a - ${{ if eq('true', parameters.PublishContainer) }}: - pwsh: | docker login ` @@ -204,8 +205,10 @@ steps: } displayName: Upload release to storage account - - publish: release - artifact: UploadedReleaseArtifacts + - task: 1ES.PublishPipelineArtifact@1 + inputs: + targetPath: release + artifact: UploadedReleaseArtifacts - ${{ if eq('true', parameters.PublishShield) }}: - template: /eng/pipelines/templates/steps/publish-shield.yml diff --git a/eng/pipelines/templates/steps/setup-go.yml b/eng/pipelines/templates/steps/setup-go.yml index a0899dbd06f..f4057506701 100644 --- a/eng/pipelines/templates/steps/setup-go.yml +++ b/eng/pipelines/templates/steps/setup-go.yml @@ -3,7 +3,32 @@ parameters: Condition: succeeded() steps: + - pwsh: | + if (!$IsWindows -and (arch) -in @('arm64', 'aarch64')) { + Write-Host "Circumventing GoTool@0 because it does not support ARM64" + $tempDir = [System.IO.Path]::GetTempPath() + $os = 'darwin' + if ($IsLinux) { + $os = 'linux' + } + $goFile = "go${{ parameters.GoVersion }}.$os-arm64.tar.gz" + curl -L https://golang.google.cn/dl/$goFile -o "$tempDir/$goFile" + sudo rm -rf /usr/local/go && sudo tar -C /usr/local -xzf "$tempDir/$goFile" + + Write-Host "go version" + /usr/local/go/bin/go version + + echo "##vso[task.prependpath]/usr/local/go/bin" + Write-Host "##vso[task.setvariable variable=DEFAULT_GO_SETUP]false" + + } else { + Write-Host "Use tools" + Write-Host "##vso[task.setvariable variable=DEFAULT_GO_SETUP]true" + } + displayName: Setup Go (ARM64) + - task: GoTool@0 + condition: eq(variables['DEFAULT_GO_SETUP'], 'true') inputs: version: ${{ parameters.GoVersion }} diff --git a/eng/pipelines/templates/variables/image.yml b/eng/pipelines/templates/variables/image.yml new file mode 100644 index 00000000000..af8871eff3d --- /dev/null +++ b/eng/pipelines/templates/variables/image.yml @@ -0,0 +1,33 @@ +# Default pool image selection. Set as variable so we can override at pipeline level + +variables: + - name: LINUXPOOL + value: azsdk-pool-mms-ubuntu-2004-general + - name: LINUXARMPOOL + value: azsdk-pool-mms-ubuntu-2004-arm + - name: WINDOWSPOOL + value: azsdk-pool-mms-win-2022-general + - name: MACPOOL + value: Azure Pipelines + + - name: LINUXVMIMAGE + value: azsdk-pool-mms-ubuntu-2004-1espt + - name: LINUXNEXTVMIMAGE + value: azsdk-pool-mms-ubuntu-2204-1espt + - name: LINUXARMVMIMAGE + value: azsdk-pool-mms-mariner-2-arm-1espt + - name: WINDOWSVMIMAGE + value: azsdk-pool-mms-win-2022-1espt + - name: MACVMIMAGE + value: macos-11 + - name: MACVMIMAGE12 + value: macos-12 + + # Values required for pool.os field in 1es pipeline templates. Variable form + # cannot be used, instead those values must be written directly into pool.os. + - name: LINUXOS + value: linux + - name: WINDOWSOS + value: windows + - name: MACOS + value: macOS