Skip to content

Commit 79e5ac2

Browse files
CI Build updates: build queuing and Windows PS7 (#260)
This updates the CI build with two new features: 1. **Validation against Windows PS7 (PowerShell Core)** This pipeline previously had three platforms that it tested against: * `Windows PS5` * `Linux PS7 (PowerShell Core)` * `macOS PS7 (PowerShell Core)` With this change, we add a fourth platform: `Windows PS7 (PowerShell Core)` 2. **Build queuing** The unit tests operate against live GitHub accounts (as opposed to mocking out the execution of the API calls). Each platform has its own account that it operates against to alllow each platform to be tested in parallel. However, if more than one build is queued at once, then the builds can start to stomp over the expected state in the tests accounts. This change adds a new `job` to the pipeline which will create a "queue" of running builds by only allowing a build to continue processing once all previously queued builds have completed. Initial idea came from here: https://developercommunity.visualstudio.com/idea/365730/prevent-parallel-execution-of-the-same-build-defin.html - Fixes #239
1 parent 2740026 commit 79e5ac2

File tree

6 files changed

+327
-44
lines changed

6 files changed

+327
-44
lines changed

build/pipelines/azure-pipelines.ci.yaml

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,42 @@ trigger:
1919
#- master
2020

2121
jobs:
22-
- job: Windows
22+
- job: waitForRunningBuilds
23+
displayName: 'Wait for Running Builds'
2324
pool:
2425
vmImage: 'windows-latest'
26+
timeoutInMinutes: 360
27+
continueOnError: true
28+
steps:
29+
- template: ./templates/wait-runningBuild.yaml
30+
parameters:
31+
buildQueryPersonalAccessToken: $(BuildQueryPersonalAccessToken)
32+
33+
- job: windowsWPS
34+
displayName: 'Windows [Windows PowerShell]'
35+
pool:
36+
vmImage: 'windows-latest'
37+
dependsOn: waitForRunningBuilds
38+
steps:
39+
- template: ./templates/verify-testConfigSettingsHash.yaml
40+
parameters:
41+
usePowerShellCore: false
42+
- template: ./templates/run-staticAnalysis.yaml
43+
parameters:
44+
usePowerShellCore: false
45+
- template: ./templates/run-unitTests.yaml
46+
parameters:
47+
gitHubAccessToken: $(WindowsPS5CIGitHubAccessToken)
48+
gitHubOwnerName: $(WindowsPS5CIGitHubOwnerName)
49+
gitHubOrganizationName: $(WindowsPS5CIGitHubOrganizationName)
50+
platformName: 'Windows'
51+
usePowerShellCore: false
52+
53+
- job: windows
54+
displayName: 'Windows [PowerShell Core]'
55+
pool:
56+
vmImage: 'windows-latest'
57+
dependsOn: waitForRunningBuilds
2558
steps:
2659
- template: ./templates/verify-testConfigSettingsHash.yaml
2760
- template: ./templates/run-staticAnalysis.yaml
@@ -32,9 +65,11 @@ jobs:
3265
gitHubOrganizationName: $(WindowsCIGitHubOrganizationName)
3366
platformName: 'Windows'
3467

35-
- job: Linux
68+
- job: linux
69+
displayName: 'Linux [PowerShell Core]'
3670
pool:
3771
vmImage: 'ubuntu-latest'
72+
dependsOn: waitForRunningBuilds
3873
steps:
3974
- template: ./templates/verify-testConfigSettingsHash.yaml
4075
- template: ./templates/run-staticAnalysis.yaml
@@ -46,8 +81,10 @@ jobs:
4681
platformName: 'Linux'
4782

4883
- job: macOS
84+
displayName: 'macOS [PowerShell Core]'
4985
pool:
5086
vmImage: 'macOS-latest'
87+
dependsOn: waitForRunningBuilds
5188
steps:
5289
- template: ./templates/verify-testConfigSettingsHash.yaml
5390
- template: ./templates/run-staticAnalysis.yaml

build/pipelines/templates/run-staticAnalysis.yaml

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,34 @@
33
# report the results.
44
#
55

6+
parameters:
7+
- name: 'usePowerShellCore'
8+
default: true
9+
type: boolean
10+
611
steps:
7-
- powershell: |
8-
Install-Module -Name PSScriptAnalyzer -Repository PSGallery -Scope CurrentUser -Force -Verbose
12+
- task: PowerShell@2
913
displayName: 'Install PSScriptAnalyzer'
14+
inputs:
15+
pwsh: eq('${{ parameters.usePowerShellCore }}', true)
16+
errorActionPreference: 'stop'
17+
targetType: 'inline'
18+
script: |
19+
Install-Module -Name PSScriptAnalyzer -Repository PSGallery -Scope CurrentUser -Force -Verbose
1020
11-
- powershell: |
12-
$results = try { Invoke-ScriptAnalyzer -Settings ./PSScriptAnalyzerSettings.psd1 -Path ./ –Recurse -ErrorAction Stop } catch { 'Unexpected Error'; $_.Exception.StackTrace; if ($IsCoreCLR) { Get-Error }; throw }
13-
$results | ForEach-Object { Write-Host "##vso[task.logissue type=$($_.Severity);sourcepath=$($_.ScriptPath);linenumber=$($_.Line);columnnumber=$($_.Column);]$($_.Message)" }
14-
15-
$null = New-Item -Path ..\ -Name ScriptAnalyzer -ItemType Directory -Force
16-
./build/scripts/ConvertTo-NUnitXml.ps1 -ScriptAnalyzerResult $results -Path ../ScriptAnalyzer/test-results.xml
17-
workingDirectory: '$(System.DefaultWorkingDirectory)'
21+
- task: PowerShell@2
1822
displayName: 'Run Static Code Analysis (PSScriptAnalyzer)'
23+
inputs:
24+
pwsh: eq('${{ parameters.usePowerShellCore }}', true)
25+
errorActionPreference: 'stop'
26+
workingDirectory: '$(System.DefaultWorkingDirectory)'
27+
targetType: 'inline'
28+
script: |
29+
$results = try { Invoke-ScriptAnalyzer -Settings ./PSScriptAnalyzerSettings.psd1 -Path ./ –Recurse -ErrorAction Stop } catch { 'Unexpected Error'; $_.Exception.StackTrace; if ($IsCoreCLR) { Get-Error }; throw }
30+
$results | ForEach-Object { Write-Host "##vso[task.logissue type=$($_.Severity);sourcepath=$($_.ScriptPath);linenumber=$($_.Line);columnnumber=$($_.Column);]$($_.Message)" }
31+
32+
$null = New-Item -Path ..\ -Name ScriptAnalyzer -ItemType Directory -Force
33+
./build/scripts/ConvertTo-NUnitXml.ps1 -ScriptAnalyzerResult $results -Path ../ScriptAnalyzer/test-results.xml
1934
2035
- task: PublishTestResults@2
2136
displayName: 'Publish ScriptAnalyzer Test Results'

build/pipelines/templates/run-unitTests.yaml

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,17 +23,31 @@ parameters:
2323
- name: 'platformName'
2424
default: 'Windows'
2525
type: string
26+
- name: 'usePowerShellCore'
27+
default: false
28+
type: boolean
2629

2730
steps:
28-
- powershell: |
29-
Install-Module -Name Pester -Repository PSGallery -Scope CurrentUser -AllowClobber -SkipPublisherCheck -RequiredVersion 4.10.1 -Force -Verbose
31+
- task: PowerShell@2
3032
displayName: 'Install Pester'
33+
inputs:
34+
pwsh: eq('${{ parameters.usePowerShellCore }}', true)
35+
errorActionPreference: 'stop'
36+
workingDirectory: '$(System.DefaultWorkingDirectory)'
37+
targetType: 'inline'
38+
script: |
39+
Install-Module -Name Pester -Repository PSGallery -Scope CurrentUser -AllowClobber -SkipPublisherCheck -RequiredVersion 4.10.1 -Force -Verbose
3140
32-
- powershell: |
33-
$null = New-Item -Path ..\ -Name Pester -ItemType Directory -Force
34-
Invoke-Pester -CodeCoverage .\*.ps*1 -CodeCoverageOutputFile ../Pester/coverage.xml -CodeCoverageOutputFileFormat JaCoCo -EnableExit -Strict -OutputFile ../Pester/test-results.xml -OutputFormat NUnitXml
35-
workingDirectory: '$(System.DefaultWorkingDirectory)'
41+
- task: PowerShell@2
3642
displayName: 'Run Unit Tests via Pester'
43+
inputs:
44+
pwsh: eq('${{ parameters.usePowerShellCore }}', true)
45+
errorActionPreference: 'stop'
46+
workingDirectory: '$(System.DefaultWorkingDirectory)'
47+
targetType: 'inline'
48+
script: |
49+
$null = New-Item -Path ..\ -Name Pester -ItemType Directory -Force
50+
Invoke-Pester -CodeCoverage .\*.ps*1 -CodeCoverageOutputFile ../Pester/coverage.xml -CodeCoverageOutputFileFormat JaCoCo -EnableExit -Strict -OutputFile ../Pester/test-results.xml -OutputFormat NUnitXml
3751
env:
3852
ciAccessToken: ${{ parameters.gitHubAccessToken }}
3953
ciOwnerName: ${{ parameters.gitHubOwnerName }}

build/pipelines/templates/verify-testConfigSettingsHash.yaml

Lines changed: 37 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -4,35 +4,45 @@
44
# the same in order to ensure the correct warning messages are presented to developers running UTs.
55
#
66

7+
parameters:
8+
- name: 'usePowerShellCore'
9+
default: true
10+
type: boolean
11+
712
steps:
8-
- powershell: |
9-
. ./Helpers.ps1
10-
$content = Get-Content -Path ./Tests/Config/Settings.ps1 -Raw -Encoding UTF8
11-
$hash = Get-SHA512Hash -PlainText $content
12-
$configurationFile = Get-Content -Path ./GitHubConfiguration.ps1 -Raw -Encoding Utf8
13-
if($configurationFile -match "'testConfigSettingsHash' = '([^']+)'")
14-
{
15-
if($hash -ne $Matches[1])
13+
- task: PowerShell@2
14+
displayName: 'Set GitHubConfiguration.ps1 testConfigSettingsHash value.'
15+
inputs:
16+
pwsh: eq('${{ parameters.usePowerShellCore }}', true)
17+
errorActionPreference: 'stop'
18+
workingDirectory: '$(System.DefaultWorkingDirectory)'
19+
targetType: 'inline'
20+
script: |
21+
. ./Helpers.ps1
22+
$content = Get-Content -Path ./Tests/Config/Settings.ps1 -Raw -Encoding UTF8
23+
$hash = Get-SHA512Hash -PlainText $content
24+
$configurationFile = Get-Content -Path ./GitHubConfiguration.ps1 -Raw -Encoding Utf8
25+
if($configurationFile -match "'testConfigSettingsHash' = '([^']+)'")
26+
{
27+
if($hash -ne $Matches[1])
28+
{
29+
$configHash = $Matches[1]
30+
$message = @(
31+
"`$testConfigSettingsHash value does not match the Get-SHA512Hash of file ./Tests/Config/Settings.ps1. If the contents of ",
32+
"Settings.ps1 has been updated, please update the `$testConfigSettingsHash value in ./GitHubConfiguration.ps1's ",
33+
"Import-GitHubConfiguration function. You can generate the new hash value using the commands:",
34+
"",
35+
"`t. ./Helpers.ps1",
36+
"`tGet-SHA512Hash -PlainText (Get-Content -Path ./Tests/Config/Settings.ps1 -Raw -Encoding Utf8)",
37+
"",
38+
"`$testConfigSettingsHash = $configHash",
39+
"Get-SHA512Hash(Settings.ps1) = $hash")
40+
throw ($message -join [Environment]::NewLine)
41+
}
42+
} else
1643
{
17-
$configHash = $Matches[1]
1844
$message = @(
19-
"`$testConfigSettingsHash value does not match the Get-SHA512Hash of file ./Tests/Config/Settings.ps1. If the contents of ",
20-
"Settings.ps1 has been updated, please update the `$testConfigSettingsHash value in ./GitHubConfiguration.ps1's ",
21-
"Import-GitHubConfiguration function. You can generate the new hash value using the commands:",
22-
"",
23-
"`t. ./Helpers.ps1",
24-
"`tGet-SHA512Hash -PlainText (Get-Content -Path ./Tests/Config/Settings.ps1 -Raw -Encoding Utf8)",
25-
"",
26-
"`$testConfigSettingsHash = $configHash",
27-
"Get-SHA512Hash(Settings.ps1) = $hash")
45+
"`$testConfigSettingsHash value not found in ./GitHubConfiguration.ps1. Please ensure ",
46+
"the default hash value is set within the Import-GitHubConfiguration function.")
2847
throw ($message -join [Environment]::NewLine)
2948
}
30-
} else
31-
{
32-
$message = @(
33-
"`$testConfigSettingsHash value not found in ./GitHubConfiguration.ps1. Please ensure ",
34-
"the default hash value is set within the Import-GitHubConfiguration function.")
35-
throw ($message -join [Environment]::NewLine)
36-
}
37-
displayName: 'Set GitHubConfiguration.ps1 testConfigSettingsHash value.'
38-
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#
2+
# This template contains the necessary jobs to create a queue for this pipeline and ensure that
3+
# there is never more than one concurrent build actively running at any given time.
4+
#
5+
6+
#--------------------------------------------------------------------------------------------------
7+
# This template is dependent on the following pipeline variables being configured within the pipeline.
8+
#
9+
# 1. buildQueryPersonalAccessToken - An Azure DevOps Personal Access Token with Build READ permission.
10+
# It should be configured as a "secret".
11+
#--------------------------------------------------------------------------------------------------
12+
13+
parameters:
14+
- name: 'buildQueryPersonalAccessToken'
15+
type: string
16+
- name: 'usePowerShellCore'
17+
default: true
18+
type: boolean
19+
20+
steps:
21+
- task: PowerShell@2
22+
displayName: 'Wait for previously queued builds'
23+
inputs:
24+
pwsh: eq('${{ parameters.usePowerShellCore }}', true)
25+
errorActionPreference: 'stop'
26+
workingDirectory: '$(System.DefaultWorkingDirectory)'
27+
targetType: 'inline'
28+
script: |
29+
$params = @{
30+
PersonalAccessToken = $env:buildReadAccessToken
31+
OrganizationName = 'ms'
32+
ProjectName = 'PowerShellForGitHub'
33+
BuildDefinitionId = $(System.DefinitionId)
34+
BuildId = $(Build.BuildId)
35+
}
36+
37+
./build/scripts/Wait-RunningBuild.ps1 @params
38+
env:
39+
buildReadAccessToken: ${{ parameters.buildQueryPersonalAccessToken }}

0 commit comments

Comments
 (0)