-
Notifications
You must be signed in to change notification settings - Fork 75
/
Copy pathJenkinsfile
285 lines (254 loc) · 12.5 KB
/
Jenkinsfile
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
// This file is part of the HörTech Open Master Hearing Aid (openMHA)
// Copyright © 2018 2019 2020 2021 HörTech gGmbH
// Copyright © 2021 2022 2024 Hörzentrum Oldenburg gGmbH
//
// openMHA is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, version 3 of the License.
//
// openMHA is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License, version 3 for more details.
//
// You should have received a copy of the GNU Affero General Public License,
// version 3 along with openMHA. If not, see <http://www.gnu.org/licenses/>.
// Encapsulation of the build steps to perform when compiling openMHA
// @param stage_name the stage name is "system && arch && devenv" where system
// is focal, jammy, windows, or mac, arch is x86_64, aarch64,
// or armv7, and devenv is either mhadev or mhadoc.
// All parts are separated by an && operator and spaces.
// This string is also used as a valid label expression for
// jenkins. The appropriate nodes have the respective labels.
def openmha_build_steps(stage_name) {
// Extract components from stage_name:
def system, arch, devenv
(system,arch,devenv) = stage_name.split(/ *&& */) // regexp for missing/extra spaces
// platform booleans
def linux = (system != "windows" && system != "mac")
def windows = (system == "windows")
def mac = (system == "mac")
def docs = (devenv == "mhadoc") //Create PDFs only on 1 of the parallel builds
// Compilation on ARM is the slowest, assign 5 CPU cores to each ARM build job
def cpus = 2 // default on other systems is 2 cores
if (arch == "armv7" || arch == "aarch64") {
cpus = 5
}
if (system == "windows") {
cpus = 5
}
def additional_cpus_for_docs = 7
// checkout openMHA from version control system, the exact same revision that
// triggered this job on each build slave
checkout scm
// Avoid that artifacts from previous builds influence this build
sh "git reset --hard && git clean -ffdx"
// Save time by using precompiled external libs if possible.
// Install pre-compiled external libraries for the common branches
copyArtifacts(projectName: "MHA/external_libs/external_libs_development",
selector: lastSuccessful())
sh "tar xvzf external_libs.tgz"
// if we notice any differences between the sources of the precompiled
// dependencies and the current sources, we cannot help but need to recompile
sh "git diff --exit-code || (git reset --hard && git clean -ffdx)"
// Autodetect libs/compiler
sh "./configure"
if (docs) {
// Create the cross-platform artifacts (PDFs and debs).
// All other platforms have to wait for the documents to be created and
// published here, therefore we give this task additional cpus to create
// the docs.
sh ("make -j ${cpus + additional_cpus_for_docs} doc")
// Store generated PDF documents as Jenkins artifacts
stash name: "docs", includes: '*.pdf'
sh ("echo stashed docs on $system $arch at \$(date -R)")
archiveArtifacts 'pdf-*.zip'
// The docker slave that builds the docs also builds the architecture
// independent debian packages. Again, all linux build jobs have to
// wait for these debs created here, hence the additional cpus again.
sh ("make -j ${cpus + additional_cpus_for_docs} deb")
// make deb leaves copies of the platform-independent debs in base directory
stash name: "debs", includes: '*.deb'
sh ("echo stashed debs on $system $arch at \$(date -R)")
archiveArtifacts '*.deb'
// Doxygen generates html version of developer documentation. Publish.
archiveArtifacts 'mha/doc/mhadoc/html/**'
}
// Build executables, plugins, execute tests
sh ("make -j $cpus test")
// Retrieve the documents and matlab coder, wait if they are not ready yet
def wait_time = 1 // short sleep time for first iteration
def attempt = 0
retry(45){
sleep(wait_time)
wait_time = 15 // longer sleep times for subsequent iterations
attempt = attempt + 1
sh ("echo unstash docs attempt $attempt on $system $arch at \$(date -R)")
unstash "docs"
unstash "MatlabCoderGeneration"
}
if (linux) {
if (!docs) { // The docs builder already has the debs. Built them above.
// Retrieve the architecture-independent debs, wait until they are ready.
wait_time = 1
attempt = 0
retry(45){
sleep(wait_time)
wait_time = 15
attempt = attempt + 1
sh ("echo unstash debs attempt $attempt on $system $arch at \$(date -R)")
unstash "debs"
sh ("touch *.deb")
}
sh ("make -j $cpus deb")
}
// Store debian packages
stash name: (arch+"_"+system), includes: 'mha/tools/packaging/deb/hoertech/'
archiveArtifacts 'mha/tools/packaging/deb/hoertech/*/*.deb'
}
if (windows) {
sh ("make exe")
// Store windows installer
archiveArtifacts 'mha/tools/packaging/exe/*.exe'
}
if (mac) {
sh ("mkdir homebrew")
sh ('make PREFIX="$(realpath homebrew)" -j $cpus homebrew')
archiveArtifacts 'homebrew/**'
}
// Check reproducibility: No package should contain "modified" in its name
sh ('if find mha/tools/packaging | grep modified;' +
'then echo error: Some installation packages have \"modified\" as part'+
' of their file name, which means that some git-controlled' +
' files contained modifications when these installation' +
' packages were created. This should not happen because the' +
' resulting installer packages are not reproducible. Find' +
' the cause and fix the error.;' +
' exit 1;' +
'fi')
}
pipeline {
agent {label "pipeline"}
options {
buildDiscarder(logRotator(daysToKeepStr: '7', artifactDaysToKeepStr: '7'))
}
stages {
stage("build") {
parallel {
stage("Matlab Coder Generation") {
agent {label "matlabcoder"}
steps {
dir('mha/mhatest') {
sh "matlab -nodisplay -r 'generate_matlab_coder_native;quit'"
}
stash name: "MatlabCoderGeneration",
includes: 'mha/plugins/matlabcoder_skeleton/'
archiveArtifacts 'mha/plugins/matlabcoder_skeleton/**'
}
}
stage( "noble && x86_64 && mhadev") {
agent {label "noble && x86_64 && mhadev"}
steps {openmha_build_steps("noble && x86_64 && mhadev")}
}
stage( "jammy && x86_64 && mhadoc") {
agent {label "jammy && x86_64 && mhadoc"}
steps {openmha_build_steps("jammy && x86_64 && mhadoc")}
}
stage( "focal && x86_64 && mhadev") {
agent {label "focal && x86_64 && mhadev"}
steps {openmha_build_steps("focal && x86_64 && mhadev")}
}
stage( "bullseye && armv7 && mhadev") {
agent {label "bullseye && armv7 && mhadev"}
steps {openmha_build_steps("bullseye && armv7 && mhadev")}
}
stage( "bullseye && aarch64 && mhadev") {
agent {label "bullseye && aarch64 && mhadev"}
steps {openmha_build_steps("bullseye && aarch64 && mhadev")}
}
stage( "bionic && armv7 && mhadev") {
agent {label "bionic && armv7 && mhadev"}
steps {openmha_build_steps("bionic && armv7 && mhadev")}
}
stage( "windows && x86_64 && mhadev") {
agent {label "windows && x86_64 && mhadev"}
steps {openmha_build_steps("windows && x86_64 && mhadev")}
}
}
}
stage("debian packages for apt") {
agent {label "aptly"}
// publish packages for branch development automatically
when { branch 'development' }
// Releases are not automatically uploaded to apt because
// we still need to check that all installers function
// after they have been created. When this verification has
// been done, then start a Replay build of master on Jenkins,
// and change this Jenkinsfile as follows: comment-out the "when"
// line above, remove the comment before the following "when"
// line, and then Run the replay build.
// when { anyOf { branch 'master'; branch 'development' } }
steps {
// receive all deb packages from openmha build
unstash "x86_64_noble"
unstash "x86_64_jammy"
unstash "x86_64_focal"
unstash "armv7_bullseye"
unstash "aarch64_bullseye"
unstash "armv7_bionic"
// Copies the new debs to the stash of existing debs,
sh "./configure || true; make storage"
build job: "/Packaging/hoertech-aptly/$BRANCH_NAME",
quietPeriod: 300,
wait: false
}
}
stage("push updates in development branch to github when build successful") {
// This stage needs an agent that has the git-switch command.
agent {label "focal && mhadev"}
// This stage is only executed if all prevous stages were successful
when { branch 'development' } // and only for branch development!
steps {
// Make sure we have a git checkout
checkout scm
// Make sure branch development is not shallow in this clone
sh "git fetch --unshallow || true"
// Jenkins builds work in detached head mode, because when you
// have git commits to the same branch in quick succession,
// this Jenkins build may not build the latest state of branch
// development, but an earlier state. Furthermore, there can
// be situations where this build of the earlier state is
// successful, but the build on the latest state of branch
// development will later fail. Because of this possibility,
// we may only push the current git commit to github and not
// the tip of branch develpment. We must not checkout branch
// development here, but create a new branch here at the
// detached head and push the new branch to github as branch
// development there.
sh "git switch --force-create temporary-branch-name-for-jenkins"
// Push this state here to branch development on github. For
// details about the ssh key, see https://dev.openmha.org/K36
withCredentials(bindings: [sshUserPrivateKey( \
credentialsId: 'K36', \
keyFileVariable: 'GIT_SSH_KEY')]) {
sh '''
GIT_SSH_COMMAND="ssh -i $GIT_SSH_KEY -o IdentitiesOnly=yes -o StrictHostKeyChecking=no" \
git push [email protected]:HoerTech-gGmbH/openMHA.git \
temporary-branch-name-for-jenkins:development
'''
}
}
}
}
// Email notification on failed build taken from
// https://jenkins.io/doc/pipeline/tour/post/
// multiple recipients are comma-separated:
// https://jenkins.io/doc/pipeline/steps/workflow-basic-steps/#-mail-%20mail
post {
failure {
mail to: '[email protected]',
subject: "Failed Pipeline: ${currentBuild.fullDisplayName}",
body: "Something is wrong with ${env.BUILD_URL}"
}
}
}