Skip to content

Commit 389ea8a

Browse files
authored
Merge pull request #1770 from lemeurherve/issue1489-windows-build-refactor
feat(Windows): refactor build process
2 parents 64dadbc + d46407f commit 389ea8a

File tree

8 files changed

+351
-270
lines changed

8 files changed

+351
-270
lines changed

Jenkinsfile

+51-45
Original file line numberDiff line numberDiff line change
@@ -13,56 +13,62 @@ properties(listOfProperties)
1313

1414
stage('Build') {
1515
def builds = [:]
16-
builds['windows'] = {
17-
nodeWithTimeout('docker-windows') {
18-
stage('Checkout') {
19-
checkout scm
20-
}
21-
22-
if (!infra.isTrusted()) {
23-
24-
/* Outside of the trusted.ci environment, we're building and testing
25-
* the Dockerfile in this repository, but not publishing to docker hub
26-
*/
27-
stage('Build') {
28-
infra.withDockerCredentials {
29-
powershell './make.ps1'
30-
}
16+
def windowsImageTypes = [
17+
'windowsservercore-ltsc2019',
18+
]
19+
for (anImageType in windowsImageTypes) {
20+
def imageType = anImageType
21+
builds[imageType] = {
22+
nodeWithTimeout('windows-2019') {
23+
stage('Checkout') {
24+
checkout scm
3125
}
3226

33-
stage('Test') {
34-
infra.withDockerCredentials {
35-
def windowsTestStatus = powershell(script: './make.ps1 test', returnStatus: true)
36-
junit(allowEmptyResults: true, keepLongStdio: true, testResults: 'target/**/junit-results.xml')
37-
if (windowsTestStatus > 0) {
38-
// If something bad happened let's clean up the docker images
39-
error('Windows test stage failed.')
27+
withEnv(["IMAGE_TYPE=${imageType}"]) {
28+
if (!infra.isTrusted()) {
29+
/* Outside of the trusted.ci environment, we're building and testing
30+
* the Dockerfile in this repository, but not publishing to docker hub
31+
*/
32+
stage("Build ${imageType}") {
33+
infra.withDockerCredentials {
34+
powershell './make.ps1'
35+
}
4036
}
41-
}
42-
}
4337

44-
// disable until we get the parallel changes merged in
45-
//def branchName = "${env.BRANCH_NAME}"
46-
//if (branchName ==~ 'master'){
47-
// stage('Publish Experimental') {
48-
// infra.withDockerCredentials {
49-
// withEnv(['DOCKERHUB_ORGANISATION=jenkins4eval','DOCKERHUB_REPO=jenkins']) {
50-
// powershell './make.ps1 publish'
51-
// }
52-
// }
53-
// }
54-
//}
55-
56-
} else {
57-
// Only publish when a tag triggered the build
58-
if (env.TAG_NAME) {
59-
// Split to ensure any suffix is not taken in account (but allow suffix tags to trigger rebuilds)
60-
jenkins_version = env.TAG_NAME.split('-')[0]
61-
withEnv(["JENKINS_VERSION=${jenkins_version}"]) {
62-
stage('Publish') {
38+
stage("Test ${imageType}") {
6339
infra.withDockerCredentials {
64-
withEnv(['DOCKERHUB_ORGANISATION=jenkins','DOCKERHUB_REPO=jenkins']) {
65-
powershell './make.ps1 publish'
40+
def windowsTestStatus = powershell(script: './make.ps1 test', returnStatus: true)
41+
junit(allowEmptyResults: true, keepLongStdio: true, testResults: 'target/**/junit-results.xml')
42+
if (windowsTestStatus > 0) {
43+
// If something bad happened let's clean up the docker images
44+
error('Windows test stage failed.')
45+
}
46+
}
47+
}
48+
49+
// disable until we get the parallel changes merged in
50+
// def branchName = "${env.BRANCH_NAME}"
51+
// if (branchName ==~ 'master'){
52+
// stage('Publish Experimental') {
53+
// infra.withDockerCredentials {
54+
// withEnv(['DOCKERHUB_ORGANISATION=jenkins4eval','DOCKERHUB_REPO=jenkins']) {
55+
// powershell './make.ps1 publish'
56+
// }
57+
// }
58+
// }
59+
// }
60+
} else {
61+
// Only publish when a tag triggered the build
62+
if (env.TAG_NAME) {
63+
// Split to ensure any suffix is not taken in account (but allow suffix tags to trigger rebuilds)
64+
jenkins_version = env.TAG_NAME.split('-')[0]
65+
withEnv(["JENKINS_VERSION=${jenkins_version}"]) {
66+
stage('Publish') {
67+
infra.withDockerCredentials {
68+
withEnv(['DOCKERHUB_ORGANISATION=jenkins','DOCKERHUB_REPO=jenkins']) {
69+
powershell './make.ps1 publish'
70+
}
71+
}
6672
}
6773
}
6874
}

build-windows.yaml

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
services:
2+
jdk11:
3+
image: ${DOCKERHUB_ORGANISATION}/${DOCKERHUB_REPO}:jdk11-hotspot-${WINDOWS_FLAVOR}-${WINDOWS_VERSION}
4+
build:
5+
context: ./
6+
dockerfile: ./windows/${WINDOWS_FLAVOR}/hotspot/Dockerfile
7+
args:
8+
COMMIT_SHA: ${COMMIT_SHA}
9+
JAVA_HOME: "C:/openjdk-11"
10+
JAVA_VERSION: "11.0.20.1_1"
11+
JENKINS_SHA: ${JENKINS_SHA}
12+
JENKINS_VERSION: ${JENKINS_VERSION}
13+
TOOLS_WINDOWS_VERSION: ${TOOLS_WINDOWS_VERSION}
14+
WINDOWS_VERSION: ${WINDOWS_VERSION}
15+
tags:
16+
- ${DOCKERHUB_ORGANISATION}/${DOCKERHUB_REPO}:${JENKINS_VERSION}-jdk11-hotspot-${WINDOWS_FLAVOR}-${WINDOWS_VERSION}
17+
jdk17:
18+
image: ${DOCKERHUB_ORGANISATION}/${DOCKERHUB_REPO}:jdk17-hotspot-${WINDOWS_FLAVOR}-${WINDOWS_VERSION}
19+
build:
20+
context: ./
21+
dockerfile: ./windows/${WINDOWS_FLAVOR}/hotspot/Dockerfile
22+
args:
23+
COMMIT_SHA: ${COMMIT_SHA}
24+
JAVA_HOME: "C:/openjdk-17"
25+
JAVA_VERSION: "17.0.9_9"
26+
JENKINS_SHA: ${JENKINS_SHA}
27+
JENKINS_VERSION: ${JENKINS_VERSION}
28+
TOOLS_WINDOWS_VERSION: ${TOOLS_WINDOWS_VERSION}
29+
WINDOWS_VERSION: ${WINDOWS_VERSION}
30+
tags:
31+
- ${DOCKERHUB_ORGANISATION}/${DOCKERHUB_REPO}:${JENKINS_VERSION}-jdk17-hotspot-${WINDOWS_FLAVOR}-${WINDOWS_VERSION}
32+
- ${DOCKERHUB_ORGANISATION}/${DOCKERHUB_REPO}:${JENKINS_VERSION}-${WINDOWS_FLAVOR}-${WINDOWS_VERSION}
33+
- ${DOCKERHUB_ORGANISATION}/${DOCKERHUB_REPO}:${WINDOWS_FLAVOR}-${WINDOWS_VERSION}

make.ps1

+110-72
Original file line numberDiff line numberDiff line change
@@ -1,126 +1,164 @@
11
[CmdletBinding()]
22
Param(
33
[Parameter(Position=1)]
4-
[String] $Target = "build",
5-
[String] $JenkinsVersion = '',
4+
[String] $Target = 'build',
5+
[String] $JenkinsVersion = '2.431',
66
[switch] $DryRun = $false
77
)
88

9+
$ErrorActionPreference = 'Stop'
10+
$ProgressPreference = 'SilentlyContinue' # Disable Progress bar for faster downloads
11+
912
$Repository = 'jenkins'
10-
$Organization = 'jenkins4eval'
13+
$Organisation = 'jenkins4eval'
14+
$ImageType = 'windowsservercore-ltsc2019' # <WINDOWS_FLAVOR>-<WINDOWS_VERSION>
1115

1216
if(![String]::IsNullOrWhiteSpace($env:DOCKERHUB_REPO)) {
1317
$Repository = $env:DOCKERHUB_REPO
1418
}
1519

1620
if(![String]::IsNullOrWhiteSpace($env:DOCKERHUB_ORGANISATION)) {
17-
$Organization = $env:DOCKERHUB_ORGANISATION
21+
$Organisation = $env:DOCKERHUB_ORGANISATION
1822
}
1923

20-
# this is the jdk version that will be used for the 'bare tag' images, e.g., jdk17-windowsservercore-1809 -> windowsserver-1809
21-
$defaultBuild = '17'
22-
$defaultJvm = 'hotspot'
23-
$builds = @{}
24+
if(![String]::IsNullOrWhiteSpace($env:JENKINS_VERSION)) {
25+
$JenkinsVersion = $env:JENKINS_VERSION
26+
}
2427

25-
Get-ChildItem -Recurse -Include windows -Directory | ForEach-Object {
26-
Get-ChildItem -Recurse -Directory -Path $_ | Where-Object { Test-Path (Join-Path $_.FullName "Dockerfile") } | ForEach-Object {
27-
$dir = $_.FullName.Replace((Get-Location), "").TrimStart([IO.Path]::DirectorySeparatorChar)
28-
$items = $dir.Split([IO.Path]::DirectorySeparatorChar)
29-
$jdkVersion = $items[0]
30-
$baseImage = $items[2]
31-
$jvmType = $items[3]
32-
$basicTag = "jdk${jdkVersion}-${jvmType}-${baseImage}"
33-
$tags = @( $basicTag )
34-
if(($jdkVersion -eq $defaultBuild) -and ($jvmType -eq $defaultJvm)) {
35-
$tags += $baseImage
36-
}
28+
if(![String]::IsNullOrWhiteSpace($env:IMAGE_TYPE)) {
29+
$ImageType = $env:IMAGE_TYPE
30+
}
3731

38-
$builds[$basicTag] = @{
39-
'Folder' = $dir;
40-
'Tags' = $tags;
41-
}
42-
}
32+
$env:DOCKERHUB_ORGANISATION = "$Organisation"
33+
$env:DOCKERHUB_REPO = "$Repository"
34+
$env:JENKINS_VERSION = "$JenkinsVersion"
35+
36+
$items = $ImageType.Split('-')
37+
$env:WINDOWS_FLAVOR = $items[0]
38+
$env:WINDOWS_VERSION = $items[1]
39+
$env:TOOLS_WINDOWS_VERSION = $items[1]
40+
if ($items[1] -eq 'ltsc2019') {
41+
# There are no eclipse-temurin:*-ltsc2019 or mcr.microsoft.com/powershell:*-ltsc2019 docker images unfortunately, only "1809" ones
42+
$env:TOOLS_WINDOWS_VERSION = '1809'
4343
}
4444

45-
Write-Host "= PREPARE: List of $Organization/$Repository images and tags to be processed:"
46-
ConvertTo-Json $builds
47-
48-
foreach($b in $builds.Keys) {
49-
foreach($tag in $builds[$b]['Tags']) {
50-
Write-Host "Building $b => tag=$tag"
51-
$cmd = "docker build -t {0}/{1}:{2} {3}" -f $Organization, $Repository, $tag, $builds[$b]['Folder']
52-
switch ($DryRun) {
53-
$true { Write-Host "(dry-run) $cmd" }
54-
$false {
55-
Copy-Item -Path 'jenkins.ps1' -Destination (Join-Path $builds[$b]['Folder'] 'jenkins.ps1') -Force
56-
Copy-Item -Path 'jenkins-support.psm1' -Destination (Join-Path $builds[$b]['Folder'] 'jenkins-support.psm1') -Force
57-
Copy-Item -Path 'jenkins-plugin-cli.ps1' -Destination (Join-Path $builds[$b]['Folder'] 'jenkins-plugin-cli.ps1') -Force
58-
Invoke-Expression $cmd
59-
}
60-
}
61-
}
45+
# Retrieve the sha256 corresponding to the JENKINS_VERSION
46+
$jenkinsShaURL = 'https://repo.jenkins-ci.org/releases/org/jenkins-ci/main/jenkins-war/{0}/jenkins-war-{0}.war.sha256' -f $env:JENKINS_VERSION
47+
$webClient = New-Object System.Net.WebClient
48+
$env:JENKINS_SHA = $webClient.DownloadString($jenkinsShaURL).ToUpper()
49+
50+
$env:COMMIT_SHA=$(git rev-parse HEAD)
51+
52+
$baseDockerCmd = 'docker-compose --file=build-windows.yaml'
53+
$baseDockerBuildCmd = '{0} build --parallel --pull' -f $baseDockerCmd
54+
55+
$builds = @{}
56+
$compose = Invoke-Expression "$baseDockerCmd config --format=json" 2>$null | ConvertFrom-Json
57+
foreach ($service in $compose.services.PSObject.Properties) {
58+
$tags = @($service.Value.image)
59+
$tags += $service.Value.build.tags
60+
$builds[$service.Value.image] = @{
61+
'Tags' = $tags;
62+
}
63+
}
64+
65+
Write-Host "= PREPARE: List of $Organisation/$Repository images and tags to be processed:"
66+
Invoke-Expression "$baseDockerCmd config"
67+
68+
Write-Host '= BUILD: Building all images...'
69+
switch ($DryRun) {
70+
$true { Write-Host "(dry-run) $baseDockerBuildCmd" }
71+
$false { Invoke-Expression $baseDockerBuildCmd }
6272
}
73+
Write-Host '= BUILD: Finished building all images.'
6374

6475
if($lastExitCode -ne 0 -and !$DryRun) {
6576
exit $lastExitCode
6677
}
6778

68-
if($target -eq "test") {
79+
function Test-Image {
80+
param (
81+
$ImageName
82+
)
83+
84+
Write-Host "= TEST: Testing image ${ImageName}:"
85+
86+
$env:CONTROLLER_IMAGE = $ImageName
87+
$env:DOCKERFILE = 'windows/{0}/hotspot/Dockerfile' -f $env:WINDOWS_FLAVOR
88+
89+
if (Test-Path ".\target\$ImageName") {
90+
Remove-Item -Recurse -Force ".\target\$ImageName"
91+
}
92+
New-Item -Path ".\target\$ImageName" -Type Directory | Out-Null
93+
$configuration.TestResult.OutputPath = ".\target\$ImageName\junit-results.xml"
94+
95+
$TestResults = Invoke-Pester -Configuration $configuration
96+
if ($TestResults.FailedCount -gt 0) {
97+
Write-Host "There were $($TestResults.FailedCount) failed tests in $ImageName"
98+
$testFailed = $true
99+
} else {
100+
Write-Host "There were $($TestResults.PassedCount) passed tests out of $($TestResults.TotalCount) in $ImageName"
101+
}
102+
103+
Remove-Item env:\CONTROLLER_IMAGE
104+
Remove-Item env:\DOCKERFILE
105+
}
106+
107+
if($target -eq 'test') {
69108
if ($DryRun) {
70-
Write-Host "(dry-run) test"
109+
Write-Host '(dry-run) test'
71110
} else {
72111
# Only fail the run afterwards in case of any test failures
73112
$testFailed = $false
74-
$mod = Get-InstalledModule -Name Pester -MinimumVersion 4.9.0 -MaximumVersion 4.99.99 -ErrorAction SilentlyContinue
113+
$mod = Get-InstalledModule -Name Pester -MinimumVersion 5.3.0 -MaximumVersion 5.3.3 -ErrorAction SilentlyContinue
75114
if($null -eq $mod) {
76-
$module = "c:\Program Files\WindowsPowerShell\Modules\Pester"
115+
$module = 'c:\Program Files\WindowsPowerShell\Modules\Pester'
77116
if(Test-Path $module) {
78117
takeown /F $module /A /R
79118
icacls $module /reset
80119
icacls $module /grant Administrators:'F' /inheritance:d /T
81120
Remove-Item -Path $module -Recurse -Force -Confirm:$false
82121
}
83-
Install-Module -Force -Name Pester -MaximumVersion 4.99.99
122+
Install-Module -Force -Name Pester -Verbose -MaximumVersion 5.3.3
84123
}
85124

86-
foreach($b in $builds.Keys) {
87-
$folder = $builds[$b]['Folder']
88-
$env:FOLDER = $folder
89-
if(Test-Path ".\target\$folder") {
90-
Remove-Item -Force -Recurse ".\target\$folder"
91-
}
92-
New-Item -Path ".\target\$folder" -Type Directory | Out-Null
93-
$TestResults = Invoke-Pester -Path tests -PassThru -OutputFile ".\target\$folder\junit-results.xml" -OutputFormat JUnitXml
94-
if ($TestResults.FailedCount -gt 0) {
95-
Write-Host "There were $($TestResults.FailedCount) failed tests in $b"
96-
$testFailed = $true
97-
} else {
98-
Write-Host "There were $($TestResults.PassedCount) passed tests out of $($TestResults.TotalCount) in $b"
99-
}
100-
Remove-Item -Force env:\FOLDER
125+
Import-Module -Verbose Pester
126+
Write-Host '= TEST: Setting up Pester environment...'
127+
$configuration = [PesterConfiguration]::Default
128+
$configuration.Run.PassThru = $true
129+
$configuration.Run.Path = '.\tests'
130+
$configuration.Run.Exit = $true
131+
$configuration.TestResult.Enabled = $true
132+
$configuration.TestResult.OutputFormat = 'JUnitXml'
133+
$configuration.Output.Verbosity = 'Diagnostic'
134+
$configuration.CodeCoverage.Enabled = $false
135+
136+
Write-Host '= TEST: Testing all images...'
137+
foreach($image in $builds.Keys) {
138+
Test-Image $image.split(':')[1]
101139
}
102140

103141
# Fail if any test failures
104142
if($testFailed -ne $false) {
105-
Write-Error "Test stage failed!"
143+
Write-Error 'Test stage failed!'
106144
exit 1
107145
} else {
108-
Write-Host "Test stage passed!"
146+
Write-Host 'Test stage passed!'
109147
}
110148
}
111149
}
112150

113-
if($target -eq "publish") {
151+
if($target -eq 'publish') {
114152
# Only fail the run afterwards in case of any issues when publishing the docker images
115153
$publishFailed = 0
116154
foreach($b in $builds.Keys) {
117-
foreach($tag in $Builds[$b]['Tags']) {
118-
Write-Host "Publishing $b => tag=$tag"
119-
$cmd = "docker push {0}/{1}:{2}" -f $Organization, $Repository, $tag
155+
foreach($taggedImage in $Builds[$b]['Tags']) {
156+
Write-Host "Publishing $b => tag=$taggedImage"
157+
$cmd = 'docker push {0}' -f $taggedImage
120158
switch ($DryRun) {
121159
$true { Write-Host "(dry-run) $cmd" }
122160
$false { Invoke-Expression $cmd}
123-
}
161+
}
124162
if($lastExitCode -ne 0) {
125163
$publishFailed = 1
126164
}
@@ -129,14 +167,14 @@ if($target -eq "publish") {
129167

130168
# Fail if any issues when publising the docker images
131169
if($publishFailed -ne 0 -and !$DryRun) {
132-
Write-Error "Publish failed!"
170+
Write-Error 'Publish failed!'
133171
exit 1
134172
}
135173
}
136174

137175
if($lastExitCode -ne 0 -and !$DryRun) {
138-
Write-Error "Build failed!"
176+
Write-Error 'Build failed!'
139177
} else {
140-
Write-Host "Build finished successfully"
178+
Write-Host 'Build finished successfully'
141179
}
142180
exit $lastExitCode

0 commit comments

Comments
 (0)