diff --git a/azure-pipelines.yml b/azure-pipelines.yml index fa2b36d..0554c4a 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -1,91 +1,127 @@ trigger: - main - -variables: - Codeql.Enabled: true - -jobs: - - job: Test - strategy: - matrix: - Linux.Node10: - node.version: 10.x - vm.image: 'ubuntu-20.04' - Linux.Node12: - node.version: 12.x - vm.image: 'ubuntu-20.04' - Win.Node10: - node.version: 10.x - vm.image: 'windows-2019' - Win.Node12: - node.version: 12.x - vm.image: 'windows-2019' - pool: - vmImage: $(vm.image) - steps: - - task: NodeTool@0 - displayName: 'Install Node' - inputs: - versionSpec: $(node.version) - - script: npm install - - task: Npm@1 - displayName: 'npm test' - inputs: - command: custom - verbose: false - customCommand: test - - task: PublishTestResults@2 - condition: succeededOrFailed() - inputs: - testResultsFiles: '**/test-results.xml' - testRunTitle: 'Test results for JavaScript' - - task: PublishCodeCoverageResults@1 - condition: succeededOrFailed() - inputs: - codeCoverageTool: Cobertura - summaryFileLocation: '$(System.DefaultWorkingDirectory)/**/*coverage.xml' - reportDirectory: '$(System.DefaultWorkingDirectory)/**/coverage' - - job: Build - pool: - vmImage: 'ubuntu-22.04' - steps: - - task: Npm@1 - displayName: 'npm pack' - inputs: - command: custom - verbose: false - customCommand: pack - - task: CopyFiles@2 - displayName: 'Copy Files to: drop' - inputs: - Contents: '*.tgz' - TargetFolder: drop - - task: PublishBuildArtifacts@1 - inputs: - pathtoPublish: $(Build.SourcesDirectory)/drop - - job: Windows - pool: - vmImage: 'windows-2019' +extends: + template: /eng/1es-redirect.yml + parameters: + stages: + - stage: Build_And_Test + displayName: 'Build and Test' - steps: - - task: ea576cd4-c61f-48f8-97e7-a3cb07b90a6f@2 # CredScan@2 - inputs: - toolMajorVersion: 'V2' + variables: + - template: /eng/image.yml - - task: f5679091-e6da-4974-a8dc-0eec03a8ea63@1 # PostAnalysis@1 - inputs: - AllTools: false - APIScan: false - BinSkim: false - CodesignValidation: false - CredScan: true - FortifySCA: false - FxCop: false - ModernCop: false - PoliCheck: false - RoslynAnalyzers: false - SDLNativeRules: false - Semmle: false - TSLint: false - ToolLogsNotFoundAction: 'Standard' + jobs: + - job: Build + pool: + image: $(LINUXVMIMAGE) + name: $(LINUXPOOL) + os: linux + steps: + - task: Npm@1 + displayName: 'npm pack' + inputs: + command: custom + verbose: false + customCommand: pack + + - task: CopyFiles@2 + displayName: 'Copy Files to: drop' + inputs: + Contents: '*.tgz' + TargetFolder: $(Build.ArtifactStagingDirectory) + + - template: /eng/publish-1es-artifact.yml + parameters: + artifactName: 'drop' + artifactPath: '$(Build.ArtifactStagingDirectory)' + + - job: Test_Windows + strategy: + matrix: + Win.Node10: + node.version: 10.x + Win.Node12: + node.version: 12.x + pool: + image: $(WINDOWSVMIMAGE) + name: $(WINDOWSPOOL) + os: windows + steps: + - template: /eng/test-steps.yml + parameters: + version: $(node.version) + + - job: Test_Linux + strategy: + matrix: + Linux.Node10: + node.version: 10.x + Linux.Node12: + node.version: 12.x + pool: + image: $(LINUXVMIMAGE) + name: $(LINUXPOOL) + os: linux + steps: + - template: /eng/test-steps.yml + parameters: + version: $(node.version) + + # only include if running on `internal` build with manual queue, otherwise never include + - ${{ if and(in(variables['Build.Reason'], 'Manual', ''), eq(variables['System.TeamProject'], 'internal'))}}: + - stage: Publish + displayName: Publish + dependsOn: Build_And_Test + + jobs: + - deployment: Publish + environment: 'package-publish' + pool: + name: azsdk-pool-mms-ubuntu-2004-general + image: azsdk-pool-mms-ubuntu-2004-1espt + os: linux + + strategy: + runOnce: + deploy: + steps: + - checkout: self + submodules: false + + - download: current + artifact: drop + timeoutInMinutes: 5 + + - task: PowerShell@2 + inputs: + filePath: '$(Build.SourcesDirectory)/eng/scripts/determine-release-tag.ps1' + failOnStderr: true + pwsh: true + + - pwsh: | + Write-Host "Will deploy with tag of $(Tag)" + Get-ChildItem "$(Pipeline.Workspace)/drop" -Recurse -Force ` + | Where-Object { $_.Name -like "*.tgz" } ` + | Copy-Item -Destination "$(Build.ArtifactStagingDirectory)" + + Get-ChildItem "$(Build.ArtifactStagingDirectory)" -Recurse -Force | % { Write-Host $_.FullName } + displayName: Move artifact to $(Build.ArtifactStagingDirectory) + + - task: EsrpRelease@7 + inputs: + displayName: 'Publish oav to ESRP' + ConnectedServiceName: 'Azure SDK Engineering System' + ClientId: '5f81938c-2544-4f1f-9251-dd9de5b8a81b' + KeyVaultName: 'AzureSDKEngKeyVault' + AuthCertName: 'azure-sdk-esrp-release-auth-certificate' + SignCertName: 'azure-sdk-esrp-release-sign-certificate' + Intent: 'PackageDistribution' + ContentType: 'npm' + FolderLocation: $(Build.ArtifactStagingDirectory) + Owners: ${{ coalesce(variables['Build.RequestedForEmail'], 'azuresdk@microsoft.com') }} + Approvers: 'azuresdk@microsoft.com' + ServiceEndpointUrl: 'https://api.esrp.microsoft.com' + MainPublisher: 'ESRPRELPACMANTEST' + DomainTenantId: '72f988bf-86f1-41af-91ab-2d7cd011db47' + productstate: $(Tag) \ No newline at end of file diff --git a/eng/1es-redirect.yml b/eng/1es-redirect.yml new file mode 100644 index 0000000..4a968bf --- /dev/null +++ b/eng/1es-redirect.yml @@ -0,0 +1,64 @@ +resources: + repositories: + - repository: 1ESPipelineTemplates + type: git + name: 1ESPipelineTemplates/1ESPipelineTemplates + ref: refs/tags/release + - repository: 1ESPipelineTemplatesCanary + type: git + name: 1ESPipelineTemplates/1ESPipelineTemplates + ref: refs/tags/canary + +parameters: +- name: stages + type: stageList + default: [] +- name: Use1ESOfficial + type: boolean + default: true +- name: oneESTemplateTag + type: string + default: release + +extends: + ${{ if and(parameters.Use1ESOfficial, eq(parameters.oneESTemplateTag, 'canary')) }}: + template: v1/1ES.Official.PipelineTemplate.yml@1ESPipelineTemplatesCanary + ${{ elseif eq(parameters.oneESTemplateTag, 'canary') }}: + template: v1/1ES.Unofficial.PipelineTemplate.yml@1ESPipelineTemplatesCanary + ${{ elseif and(parameters.Use1ESOfficial, eq(variables['System.TeamProject'], 'internal')) }}: + template: v1/1ES.Official.PipelineTemplate.yml@1ESPipelineTemplates + ${{ else }}: + template: v1/1ES.Unofficial.PipelineTemplate.yml@1ESPipelineTemplates + parameters: + ${{ if eq(parameters.oneESTemplateTag, 'canary') }}: + # Enable 1es template team to verify validation has been run on canary + customBuildTags: + - 1ES.PT.Tag-refs/tags/canary + settings: + skipBuildTagsForGitHubPullRequests: true + sdl: + git: + longpaths: true + submodules: false + sourceRepositoriesToScan: + include: + - repository: self + submodule: false + runInSingleJob: true + sourceAnalysisPool: + name: azsdk-pool-mms-win-2022-general + image: azsdk-pool-mms-win-2022-1espt + os: windows + eslint: + enabled: false + justificationForDisabling: "ESLint injected task has failures because it uses an old version of mkdirp. We should not fail for tools not controlled by the repo. See: https://dev.azure.com/azur 19 e-sdk/internal/_build/results?buildId=3556850" + codeql: + compiled: + enabled: false + justificationForDisabling: "CodeQL times our pipelines out by running for 2+ hours before being force canceled." + psscriptanalyzer: + compiled: true + break: true + policy: M365 + + stages: ${{ parameters.stages }} \ No newline at end of file diff --git a/eng/image.yml b/eng/image.yml new file mode 100644 index 0000000..a7ce251 --- /dev/null +++ b/eng/image.yml @@ -0,0 +1,26 @@ +# 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: 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: ubuntu-22.04 + - name: WINDOWSVMIMAGE + value: azsdk-pool-mms-win-2022-1espt + - name: MACVMIMAGE + value: macos-11 + + # Values required for pool.os field in 1es pipeline templates + - name: LINUXOS + value: linux + - name: WINDOWSOS + value: windows + - name: MACOS + value: macOS \ No newline at end of file diff --git a/eng/publish-1es-artifact.yml b/eng/publish-1es-artifact.yml new file mode 100644 index 0000000..759d045 --- /dev/null +++ b/eng/publish-1es-artifact.yml @@ -0,0 +1,32 @@ +# This step is used to prevent duplication of artifact publishes when there is an issue that would prevent the overall success of the job. +# Ensuring that we only publish when successful (and two a differently named artifact otherwise) will allow easy retry on a build pipeline +# without running into the "cannot override artifact" failure when we finally do get a passing run. + +# ArtifactName - The name of the artifact in the "successful" case. +# ArtifactPath - The path we will be publishing. +# CustomCondition - Used if there is additional logic necessary to prevent attempt of publish. +# SbomEnabled - Set whether to auto-inject 1es pipeline template sbom tasks + +parameters: + ArtifactName: '' + ArtifactPath: '' + CustomCondition: true + SbomEnabled: true + +steps: + - pwsh: | + if ($env:AGENT_JOBSTATUS -eq "Failed") { + Write-Host "##vso[task.setvariable variable=PublishArtifactName;]${{ parameters.ArtifactName }}-FailedAttempt$(System.JobAttempt)" + } else { + Write-Host "##vso[task.setvariable variable=PublishArtifactName;]${{ parameters.ArtifactName }}" + } + condition: and(succeededOrFailed(), ${{ parameters.CustomCondition }}) + displayName: Set Artifact Name $(Agent.JobStatus) + + - task: 1ES.PublishPipelineArtifact@1 + condition: and(succeededOrFailed(), ${{ parameters.CustomCondition }}) + displayName: 'Publish ${{ parameters.ArtifactName }} Artifacts' + inputs: + artifactName: '$(PublishArtifactName)' + targetPath: '${{ parameters.ArtifactPath }}' + sbomEnabled: ${{ parameters.SbomEnabled }} \ No newline at end of file diff --git a/eng/scripts/determine-release-tag.ps1 b/eng/scripts/determine-release-tag.ps1 new file mode 100644 index 0000000..223b693 --- /dev/null +++ b/eng/scripts/determine-release-tag.ps1 @@ -0,0 +1,18 @@ +# Read the package.json file +$packageJsonPath = "$PSScriptRoot/../../package.json" +$packageJson = Get-Content $packageJsonPath -Raw | ConvertFrom-Json + +# Function to check if a version is non-GA +function Is-NonGA($version) { + return $version -match "-(alpha|beta|rc|pre)" +} + +$pkgVersion = $packageJson.version + +if (Is-NonGA($pkgVersion)) { + Write-Host "##vso[task.setvariable variable=Tag;]beta" +} +else { + Write-Host "##vso[task.setvariable variable=Tag;]latest" +} + diff --git a/eng/test-steps.yml b/eng/test-steps.yml new file mode 100644 index 0000000..50d82c3 --- /dev/null +++ b/eng/test-steps.yml @@ -0,0 +1,27 @@ +parameters: +- name: version + type: string + +steps: + - task: NodeTool@0 + displayName: 'Install Node' + inputs: + versionSpec: ${{ parameters.version }} + - script: npm install + - task: Npm@1 + displayName: 'npm test' + inputs: + command: custom + verbose: false + customCommand: test + - task: PublishTestResults@2 + condition: succeededOrFailed() + inputs: + testResultsFiles: '**/test-results.xml' + testRunTitle: 'Test results for JavaScript' + - task: PublishCodeCoverageResults@1 + condition: succeededOrFailed() + inputs: + codeCoverageTool: Cobertura + summaryFileLocation: '$(System.DefaultWorkingDirectory)/**/*coverage.xml' + reportDirectory: '$(System.DefaultWorkingDirectory)/**/coverage' \ No newline at end of file