diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 31d0cd118..cf4227d7a 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -37,7 +37,7 @@ jobs: - name: Build shell: pwsh - run: scripts/azurePipelinesBuild.ps1 + run: tools/azurePipelinesBuild.ps1 - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v1 diff --git a/.vsts-ci/azure-pipelines-release.yml b/.vsts-ci/azure-pipelines-release.yml index 4b861a570..aecf27d07 100644 --- a/.vsts-ci/azure-pipelines-release.yml +++ b/.vsts-ci/azure-pipelines-release.yml @@ -1,3 +1,5 @@ +name: Release-$(Build.SourceBranchName)-$(Date:yyyyMMdd)$(Rev:.rr) + variables: # Don't download unneeded packages - name: DOTNET_SKIP_FIRST_TIME_EXPERIENCE @@ -18,24 +20,45 @@ resources: repositories: - repository: ComplianceRepo type: github - endpoint: ComplianceGHRepo + endpoint: GitHub name: PowerShell/compliance + - repository: vscode-powershell + type: git + name: vscode-powershell + +stages: +- stage: Build + displayName: Build the release + jobs: + - job: Build + pool: + vmImage: vs2017-win2016 + steps: + - template: templates/ci-general.yml -jobs: -- job: 'ReleaseBuild' - displayName: 'Build release' - pool: - vmImage: 'vs2017-win2016' - steps: - - template: templates/ci-general.yml +- stage: Sign + displayName: Sign the release + jobs: + - job: Sign + pool: + name: 1ES + demands: ImageOverride -equals MMS2019 + variables: + - group: ESRP + steps: + - template: templates/release-general.yml -- job: 'SignBuild' - displayName: Signing Build - dependsOn: 'ReleaseBuild' - pool: - name: '1ES' - demands: ImageOverride -equals MMS2019 - variables: - - group: ESRP - steps: - - template: templates/release-general.yml +- stage: Publish + displayName: Publish the draft release + jobs: + - deployment: Publish + environment: PowerShellEditorServices + pool: + name: 1ES + variables: + - group: Publish + strategy: + runOnce: + deploy: + steps: + - template: templates/publish-general.yml diff --git a/.vsts-ci/templates/ci-general.yml b/.vsts-ci/templates/ci-general.yml index 34b81b7c1..f3e237e88 100644 --- a/.vsts-ci/templates/ci-general.yml +++ b/.vsts-ci/templates/ci-general.yml @@ -1,43 +1,26 @@ parameters: - pwsh: true +- name: pwsh + type: boolean + default: true steps: - - powershell: | - Write-Host "Installing PowerShell Daily..." +- pwsh: '$PSVersionTable' + displayName: PowerShell version - # Use `AGENT_TEMPDIRECTORY` to make sure the downloaded PowerShell is cleaned up. - $powerShellPath = Join-Path -Path $env:AGENT_TEMPDIRECTORY -ChildPath 'powershell' - Invoke-WebRequest -Uri https://aka.ms/install-powershell.ps1 -OutFile ./install-powershell.ps1 +- task: PowerShell@2 + displayName: Build and test + inputs: + filePath: tools/azurePipelinesBuild.ps1 + pwsh: ${{ parameters.pwsh }} - ./install-powershell.ps1 -Destination $powerShellPath -Daily +- publish: module + artifact: PowerShellEditorServices-Build-$(System.JobId) + displayName: Publish unsigned pipeline artifacts + condition: succeededOrFailed() - # Using `prependpath` to update the PATH just for this build. - Write-Host "##vso[task.prependpath]$powerShellPath" - displayName: Install PowerShell Daily - continueOnError: true - - - pwsh: '$PSVersionTable' - displayName: Display PowerShell version information - - - pwsh: Write-Host "##vso[build.updatebuildnumber]$env:BUILD_SOURCEBRANCHNAME-$env:BUILD_SOURCEVERSION-$((get-date).ToString("yyyyMMddhhmmss"))" - displayName: Set Build Name for Non-PR - condition: ne(variables['Build.Reason'], 'PullRequest') - - task: PowerShell@2 - inputs: - filePath: scripts/azurePipelinesBuild.ps1 - pwsh: ${{ parameters.pwsh }} - - task: PublishTestResults@2 - inputs: - testRunner: VSTest - testResultsFiles: '**/*.trx' - condition: succeededOrFailed() - - task: PublishTestResults@2 - inputs: - testRunner: NUnit - testResultsFiles: '**/TestResults.xml' - condition: succeededOrFailed() - - task: PublishBuildArtifacts@1 - inputs: - ArtifactName: PowerShellEditorServices-CI - PathtoPublish: '$(Build.ArtifactStagingDirectory)' - condition: succeededOrFailed() +- task: PublishTestResults@2 + displayName: Publish test results + inputs: + testRunner: VSTest + testResultsFiles: '**/*.trx' + condition: succeededOrFailed() diff --git a/.vsts-ci/templates/publish-general.yml b/.vsts-ci/templates/publish-general.yml new file mode 100644 index 000000000..56177e389 --- /dev/null +++ b/.vsts-ci/templates/publish-general.yml @@ -0,0 +1,15 @@ +steps: +- checkout: self +- checkout: vscode-powershell +- download: current + artifact: PowerShellEditorServices + displayName: Download signed pipeline artifacts +- pwsh: | + Set-PSRepository -Name PSGallery -InstallationPolicy Trusted | Out-Null + Install-Module -Name PowerShellForGitHub -Scope CurrentUser -Force -Confirm:$false + Import-Module '$(Build.SourcesDirectory)/vscode-powershell/tools/ReleaseTools.psm1' + Set-GitHubConfiguration -SuppressTelemetryReminder + $password = ConvertTo-SecureString -String '$(GitHubToken)' -AsPlainText -Force + Set-GitHubAuthentication -Credential (New-Object System.Management.Automation.PSCredential ("token", $password)) + New-DraftRelease -RepositoryName PowerShellEditorServices -Assets '$(Pipeline.Workspace)/PowerShellEditorServices/PowerShellEditorServices.zip' + displayName: Drafting a GitHub Release diff --git a/.vsts-ci/templates/release-general.yml b/.vsts-ci/templates/release-general.yml index 9a9ec2029..a56229448 100644 --- a/.vsts-ci/templates/release-general.yml +++ b/.vsts-ci/templates/release-general.yml @@ -1,27 +1,20 @@ steps: -- task: DownloadBuildArtifacts@0 - displayName: 'Download Build Artifacts' - inputs: - downloadType: specific - -- task: ExtractFiles@1 - displayName: 'Extract Build Zip' - inputs: - archiveFilePatterns: '$(Build.ArtifactStagingDirectory)/PowerShellEditorServices-CI/PowerShellEditorServices*.zip' - destinationFolder: '$(Build.ArtifactStagingDirectory)/PowerShellEditorServices' +- download: current + displayName: Download unsigned pipeline artifacts - checkout: ComplianceRepo - displayName: 'Checkout the ComplianceRepo' +# NOTE: The signing templates explicitly copy everything along as they run, so +# the last output path has every signed (and intentionally unsigned) file. - template: EsrpSign.yml@ComplianceRepo parameters: - buildOutputPath: '$(Build.ArtifactStagingDirectory)/PowerShellEditorServices' - signOutputPath: '$(Build.ArtifactStagingDirectory)/FirstPartySigned' - alwaysCopy: true # So publishing works - certificateId: 'CP-230012' # Authenticode certificate - useMinimatch: true # This enables the use of globbing + buildOutputPath: $(Pipeline.Workspace)/PowerShellEditorServices-Build-* + signOutputPath: $(Pipeline.Workspace)/FirstPartySigned + alwaysCopy: true + certificateId: CP-230012 # Authenticode certificate shouldSign: true # We always want to sign + useMinimatch: true # This enables the use of globbing pattern: | # PowerShellEditorServices Script PowerShellEditorServices/*.{ps1,psd1,psm1,ps1xml} @@ -35,12 +28,12 @@ steps: - template: EsrpSign.yml@ComplianceRepo parameters: - buildOutputPath: '$(Build.ArtifactStagingDirectory)/FirstPartySigned' - signOutputPath: '$(Build.ArtifactStagingDirectory)/ThirdPartySigned' - alwaysCopy: true # So publishing works - certificateId: 'CP-231522' # Third-party certificate - useMinimatch: true # This enables the use of globbing + buildOutputPath: $(Pipeline.Workspace)/FirstPartySigned + signOutputPath: $(Pipeline.Workspace)/ThirdPartySigned + alwaysCopy: true + certificateId: CP-231522 # Third-party certificate shouldSign: true # We always want to sign + useMinimatch: true # This enables the use of globbing pattern: | **/MediatR.dll **/Nerdbank.Streams.dll @@ -49,27 +42,37 @@ steps: **/Serilog*.dll **/UnixConsoleEcho.dll -- publish: $(Build.ArtifactStagingDirectory)/ThirdPartySigned +- task: ArchiveFiles@2 + displayName: Zip finished assets + inputs: + rootFolderOrFile: $(Pipeline.Workspace)/ThirdPartySigned + includeRootFolder: false + archiveType: zip + archiveFile: PowerShellEditorServices.zip + replaceExistingArchive: true + verbose: true + +- publish: PowerShellEditorServices.zip artifact: PowerShellEditorServices - displayName: 'Publish signed (and unsigned) artifacts' + displayName: Publish signed pipeline artifacts - checkout: self - template: assembly-module-compliance.yml@ComplianceRepo parameters: # binskim - AnalyzeTarget: '$(Build.ArtifactStagingDirectory)/*.dll' + AnalyzeTarget: $(Pipeline.Workspace)/*.dll AnalyzeSymPath: 'SRV*' # component-governance - sourceScanPath: '$(Build.SourcesDirectory)/PowerShellEditorServices' + sourceScanPath: $(Build.SourcesDirectory)/PowerShellEditorServices # credscan suppressionsFile: '' # TermCheck AKA PoliCheck - targetArgument: '$(Build.SourcesDirectory)/PowerShellEditorServices' - optionsUEPATH: '$(Build.SourcesDirectory)/PowerShellEditorServices/tools/terms/UserExclusions.xml' + targetArgument: $(Build.SourcesDirectory)/PowerShellEditorServices + optionsUEPATH: $(Build.SourcesDirectory)/PowerShellEditorServices/tools/terms/UserExclusions.xml optionsRulesDBPath: '' - optionsFTPath: '$(Build.SourcesDirectory)/PowerShellEditorServices/tools/terms/FileTypeSet.xml' + optionsFTPath: $(Build.SourcesDirectory)/PowerShellEditorServices/tools/terms/FileTypeSet.xml # tsa-upload - codeBaseName: 'PowerShell_PowerShellEditorServices_20210201' + codeBaseName: PowerShell_PowerShellEditorServices_20210201 # selections APIScan: false diff --git a/PowerShellEditorServices.build.ps1 b/PowerShellEditorServices.build.ps1 index fbd126708..60274440e 100644 --- a/PowerShellEditorServices.build.ps1 +++ b/PowerShellEditorServices.build.ps1 @@ -146,31 +146,6 @@ task Clean BinClean,{ } } -task GetProductVersion -Before PackageModule, UploadArtifacts { - [xml]$props = Get-Content .\PowerShellEditorServices.Common.props - - $script:BuildNumber = 9999 - $script:VersionSuffix = $props.Project.PropertyGroup.VersionSuffix - - if ($env:TF_BUILD) { - # SYSTEM_PHASENAME is the Job name. - # Job names can only include `_` but that's not a valid character for versions. - $jobname = $env:SYSTEM_PHASENAME -replace '_', '' - $script:BuildNumber = "$jobname-$env:BUILD_BUILDID" - } - - if ($script:VersionSuffix -ne $null) { - $script:VersionSuffix = "$script:VersionSuffix-$script:BuildNumber" - } - else { - $script:VersionSuffix = "$script:BuildNumber" - } - - $script:FullVersion = "$($props.Project.PropertyGroup.VersionPrefix)-$script:VersionSuffix" - - Write-Host "`n### Product Version: $script:FullVersion`n" -ForegroundColor Green -} - task CreateBuildInfo -Before Build { $buildVersion = "" $buildOrigin = "Development" @@ -435,17 +410,5 @@ task BuildCmdletHelp { New-ExternalHelp -Path $PSScriptRoot\module\PowerShellEditorServices.VSCode\docs -OutputPath $PSScriptRoot\module\PowerShellEditorServices.VSCode\en-US -Force } -task PackageModule { - [System.IO.Compression.ZipFile]::CreateFromDirectory( - "$PSScriptRoot/module/", - "$PSScriptRoot/PowerShellEditorServices-$($script:FullVersion).zip", - [System.IO.Compression.CompressionLevel]::Optimal, - $false) -} - -task UploadArtifacts -If ($null -ne $env:TF_BUILD) { - Copy-Item -Path .\PowerShellEditorServices-$($script:FullVersion).zip -Destination $env:BUILD_ARTIFACTSTAGINGDIRECTORY -Force -} - # The default task is to run the entire CI build -task . GetProductVersion, Clean, Build, Test, BuildCmdletHelp, PackageModule, UploadArtifacts +task . Clean, Build, Test, BuildCmdletHelp diff --git a/scripts/azurePipelinesBuild.ps1 b/tools/azurePipelinesBuild.ps1 similarity index 100% rename from scripts/azurePipelinesBuild.ps1 rename to tools/azurePipelinesBuild.ps1