Commit | Line | Data |
---|---|---|
017c762b JR |
1 | enum KernelVersioning { |
2 | MAJOR,MINOR,REVISION,BUILD | |
3 | } | |
4 | ||
81470b33 | 5 | class BasicVersion implements Comparable<BasicVersion> { |
017c762b JR |
6 | int major = -1 |
7 | int minor = -1 | |
8 | int revision = -1 | |
9 | int build = -1 | |
10 | int rc = -1 | |
5a67a345 | 11 | String gitRefs |
017c762b JR |
12 | |
13 | // Default Constructor | |
81470b33 | 14 | BasicVersion() {} |
017c762b | 15 | |
81470b33 JR |
16 | // Parse a version string of format X.Y.Z.W-A |
17 | BasicVersion(String version, String ref) { | |
5a67a345 | 18 | gitRefs = ref |
d11d0665 | 19 | def tokenVersion |
017c762b JR |
20 | def token |
21 | if (version.contains('-')) { | |
22 | // Release canditate | |
23 | token = version.tokenize('-') | |
24 | tokenVersion = token[0] | |
81470b33 | 25 | if (token[1]?.isInteger()) { |
017c762b JR |
26 | rc = token[1].toInteger() |
27 | } | |
28 | } else { | |
29 | tokenVersion = version | |
30 | } | |
31 | ||
32 | tokenVersion = tokenVersion.tokenize('.') | |
33 | ||
34 | def tagEnum = KernelVersioning.MAJOR | |
35 | tokenVersion.each { | |
81470b33 | 36 | if (it?.isInteger()) { |
017c762b JR |
37 | switch (tagEnum) { |
38 | case KernelVersioning.MAJOR: | |
39 | major = it.toInteger() | |
40 | tagEnum = KernelVersioning.MINOR | |
41 | break | |
42 | case KernelVersioning.MINOR: | |
43 | minor = it.toInteger() | |
44 | tagEnum = KernelVersioning.REVISION | |
45 | break | |
46 | case KernelVersioning.REVISION: | |
47 | revision = it.toInteger() | |
48 | tagEnum = KernelVersioning.BUILD | |
49 | break | |
50 | case KernelVersioning.BUILD: | |
51 | build = it.toInteger() | |
52 | tagEnum = -1 | |
53 | break | |
54 | default: | |
55 | println("Unsupported version extension") | |
56 | println("Trying to parse: ${version}") | |
57 | println("Invalid sub version value: ${it}") | |
d11d0665 | 58 | //TODO: throw exception for jenkins |
017c762b JR |
59 | } |
60 | } | |
61 | } | |
62 | } | |
63 | ||
017c762b JR |
64 | String print() { |
65 | String ret = "" | |
66 | if (major != -1) { | |
67 | ret += major | |
68 | if (minor != -1) { | |
69 | ret += "." + minor | |
70 | if (revision != -1) { | |
71 | ret += "." + revision | |
72 | if (build != -1) { | |
73 | ret += "." + build | |
74 | } | |
75 | } | |
76 | } | |
77 | if (rc != -1) { | |
5a67a345 | 78 | ret += "-rc" + rc |
017c762b JR |
79 | } |
80 | } | |
81 | return ret | |
82 | } | |
83 | ||
84 | @Override | |
81470b33 | 85 | int compareTo(BasicVersion kernelVersion) { |
017c762b JR |
86 | return major <=> kernelVersion.major ?: minor <=> kernelVersion.minor ?: revision <=> kernelVersion.revision ?: build <=> kernelVersion.build ?: rc <=> kernelVersion.rc |
87 | } | |
88 | } | |
89 | ||
81b43564 | 90 | def kernelTagCutOff = new BasicVersion("2.6.36", "") |
f6613988 | 91 | def modulesBranches = ["master", "stable-2.5", "stable-2.6"] |
d11d0665 | 92 | |
472505ab | 93 | //def modulesBranches = ["master","stable-2.5","stable-2.6", "stable-2.4"] |
d11d0665 | 94 | |
017c762b | 95 | def linuxURL = "git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git" |
e37c4476 | 96 | def modulesURL = "https://github.com/lttng/lttng-modules.git" |
017c762b JR |
97 | |
98 | // Linux specific variable | |
99 | String linuxCheckoutTo = "linux-source" | |
100 | String recipeCheckoutTo = "recipe" | |
101 | String modulesCheckoutTo = "lttng-modules" | |
102 | ||
103 | def linuxGitReference = "/home/jenkins/gitcache/linux-stable.git" | |
017c762b | 104 | |
d11d0665 | 105 | // Check if we are on jenkins |
81f87da0 JR |
106 | // Useful for outside jenkins devellopment related to groovy only scripting |
107 | def isJenkinsInstance = binding.variables.containsKey('JENKINS_HOME') | |
108 | ||
132cba4a | 109 | // Fetch tags and format |
017c762b JR |
110 | // Split the string into sections based on | |
111 | // And pipe the results together | |
132cba4a | 112 | String process = "git ls-remote -t $linuxURL | cut -c42- | sort -V" |
017c762b JR |
113 | def out = new StringBuilder() |
114 | def err = new StringBuilder() | |
115 | Process result = process.tokenize( '|' ).inject( null ) { p, c -> | |
116 | if( p ) | |
117 | p | c.execute() | |
118 | else | |
119 | c.execute() | |
120 | } | |
121 | ||
122 | result.waitForProcessOutput(out,err) | |
123 | ||
124 | if ( result.exitValue() == 0 ) { | |
125 | def branches = out.readLines().collect { | |
d11d0665 | 126 | // Scrap special string tag |
5a67a345 | 127 | it.replaceAll("\\^\\{\\}", '') |
017c762b JR |
128 | } |
129 | ||
130 | branches = branches.unique() | |
017c762b | 131 | |
81f87da0 | 132 | List versions = [] |
017c762b | 133 | branches.each { branch -> |
d11d0665 JR |
134 | def stripBranch = branch.replaceAll("rc", '').replaceAll(/refs\/tags\/v/,'') |
135 | BasicVersion kVersion = new BasicVersion(stripBranch, branch) | |
017c762b JR |
136 | versions.add(kVersion) |
137 | } | |
138 | ||
81f87da0 | 139 | // Sort the version via Comparable implementation of KernelVersion |
017c762b JR |
140 | versions = versions.sort() |
141 | ||
132cba4a | 142 | // Find the version cutoff |
d11d0665 | 143 | def cutoffPos = versions.findIndexOf{(it.major >= kernelTagCutOff.major) && (it.minor >= kernelTagCutOff.minor) && (it.revision >= kernelTagCutOff.revision) && (it.build >= kernelTagCutOff.build) && (it.rc >= kernelTagCutOff.rc)} |
017c762b | 144 | |
831d4383 JR |
145 | // If error set cutoff on last so no job are created |
146 | if (cutoffPos == -1) { | |
147 | cutoffPos = versions.size() | |
148 | } | |
017c762b JR |
149 | // Get last version and include only last rc |
150 | def last | |
151 | def lastNoRcPos | |
152 | last = versions.last() | |
153 | if (last.rc != -1) { | |
154 | int i = versions.size()-1 | |
155 | while (i > -1 && versions[i].rc != -1 ) { | |
156 | i-- | |
157 | } | |
158 | lastNoRcPos = i + 1 | |
159 | } else { | |
160 | lastNoRcPos = versions.size() | |
161 | } | |
162 | ||
d11d0665 | 163 | String modulesPrefix = "lttng-modules" |
162a2360 | 164 | String kernelPrefix = "dsl-kernel" |
d11d0665 | 165 | String separator = "-" |
831d4383 | 166 | |
07f90dd7 JR |
167 | |
168 | println("CutOff index") | |
169 | println(cutoffPos) | |
170 | ||
171 | ||
d11d0665 | 172 | // Actual job creation |
017c762b | 173 | for (int i = cutoffPos; i < versions.size() ; i++) { |
81f87da0 | 174 | |
d11d0665 | 175 | // Only create for valid build |
017c762b JR |
176 | if ( (i < lastNoRcPos && versions[i].rc == -1) || (i >= lastNoRcPos)) { |
177 | println ("Preparing job for") | |
d11d0665 JR |
178 | |
179 | String jobName = kernelPrefix + separator + versions[i].print() | |
180 | ||
181 | // Generate modules job based on supported modules jobs | |
182 | def modulesJob = [:] | |
183 | modulesBranches.each { branch -> | |
184 | modulesJob[branch] = modulesPrefix + separator + branch + separator + jobName | |
185 | } | |
186 | ||
187 | // Jenkins only dsl | |
017c762b | 188 | println(jobName) |
d11d0665 JR |
189 | if (isJenkinsInstance) { |
190 | matrixJob("${jobName}") { | |
191 | using("linux-master") | |
192 | scm { | |
193 | git { | |
194 | remote { | |
195 | url("${linuxURL}") | |
196 | } | |
197 | branch(versions[i].gitRefs) | |
198 | shallowClone(true) | |
199 | relativeTargetDir(linuxCheckoutTo) | |
200 | reference(linuxGitReference) | |
201 | } | |
202 | } | |
203 | publishers { | |
204 | modulesJob.each { | |
205 | downstream(it.value, 'SUCCESS') | |
206 | } | |
207 | } | |
208 | } | |
209 | } | |
210 | // Corresponding Module job | |
ef0e4e86 JR |
211 | modulesJob.each { job -> |
212 | println("\t" + job.key + " " + job.value) | |
d11d0665 | 213 | if (isJenkinsInstance) { |
ef0e4e86 | 214 | matrixJob(job.value) { |
d11d0665 JR |
215 | using("modules") |
216 | multiscm { | |
217 | git { | |
218 | remote { | |
219 | name(kernelPrefix) | |
220 | url("${linuxURL}") | |
221 | } | |
222 | branch(versions[i].gitRefs) | |
223 | shallowClone(true) | |
224 | relativeTargetDir(linuxCheckoutTo) | |
225 | reference(linuxGitReference) | |
226 | } | |
227 | git { | |
228 | remote { | |
229 | name(modulesPrefix) | |
230 | url(modulesURL) | |
231 | } | |
ef0e4e86 | 232 | branch(job.key) |
d11d0665 JR |
233 | relativeTargetDir(modulesCheckoutTo) |
234 | } | |
235 | } | |
236 | steps { | |
92d7d4cc | 237 | copyArtifacts("${jobName}/arch=\$arch,label=kernel", "linux-artifact/**", '', false, false) { |
d11d0665 JR |
238 | latestSuccessful(true) // Latest successful build |
239 | } | |
240 | shell(readFileFromWorkspace('lttng-modules/lttng-modules-dsl-master.sh')) | |
241 | } | |
242 | } | |
243 | } | |
244 | } | |
245 | } | |
246 | } | |
162a2360 JR |
247 | |
248 | // Trigger generations | |
249 | def dslTriggerKernel = """\ | |
162a2360 | 250 | import hudson.model.* |
5254a1ac | 251 | import jenkins.model.* |
162a2360 JR |
252 | import hudson.AbortException |
253 | import hudson.console.HyperlinkNote | |
254 | import java.util.concurrent.CancellationException | |
c086345d | 255 | import java.util.Random |
162a2360 JR |
256 | |
257 | ||
c086345d | 258 | Random random = new Random() |
162a2360 JR |
259 | def jobs = hudson.model.Hudson.instance.items |
260 | def fail = false | |
acd2d777 JR |
261 | def jobStartWithKernel = "KERNELPREFIX" |
262 | def jobStartWithModule = "MODULEPREFIX" | |
30429e88 JR |
263 | def toBuild = [] |
264 | def counter = 0 | |
1fc68d3f | 265 | def limitQueue = 4 |
162a2360 JR |
266 | |
267 | def anotherBuild | |
268 | jobs.each { job -> | |
3f5b174c JR |
269 | def jobName = job.getName() |
270 | if (jobName.startsWith(jobStartWithKernel)) { | |
271 | counter = counter + 1 | |
272 | def lastBuild = job.getLastBuild() | |
273 | if (lastBuild == null || lastBuild.result != Result.SUCCESS) { | |
274 | toBuild.push(job) | |
275 | } else { | |
276 | println("\tAlready built") | |
277 | } | |
278 | } | |
30429e88 JR |
279 | } |
280 | ||
281 | println "Kernel total "+ counter | |
282 | println "Kernel to build "+ toBuild.size() | |
283 | ||
284 | ||
285 | def kernelEnabledNode = 0 | |
286 | hudson.model.Hudson.instance.nodes.each { node -> | |
3f5b174c JR |
287 | if (node.getLabelString().contains("kernel")){ |
288 | kernelEnabledNode++ | |
289 | } | |
30429e88 JR |
290 | } |
291 | println "Nb of live kernel enabled build node "+ kernelEnabledNode | |
292 | ||
293 | def ongoingBuild = [] | |
1fc68d3f | 294 | def q = jenkins.model.Jenkins.getInstance().getQueue() |
7260dcd9 | 295 | |
3b0b4cdc JR |
296 | def queuedTaskKernel = 0 |
297 | def queuedTaskModule = 0 | |
298 | ||
30429e88 | 299 | while (toBuild.size() != 0) { |
3f5b174c JR |
300 | // Throttle the build with both the number of current parent task and queued |
301 | // task.Look for both kernel and downstream module from previous kernel. | |
3b0b4cdc JR |
302 | queuedTaskKernel = q.getItems().findAll { |
303 | it.task.getParent().name.startsWith(jobStartWithKernel) | |
304 | }.size() | |
305 | ||
306 | queuedTaskModule = q.getItems().findAll { | |
307 | it.task.getParent().name.startsWith(jobStartWithModule) | |
308 | }.size() | |
309 | ||
310 | it.task.getParent().name.startsWith(jobStartWithModule) | |
311 | if ((ongoingBuild.size() <= kernelEnabledNode.intdiv(2)) && (queuedTaskKernel + queuedTaskModule < limitQueue)) { | |
30429e88 | 312 | def job = toBuild.pop() |
c66f2c31 | 313 | ongoingBuild.push(job.scheduleBuild2(0)) |
3f5b174c JR |
314 | println "\t trigering " + HyperlinkNote.encodeTo('/' + job.url, job.fullDisplayName) |
315 | } else { | |
316 | println "Currently " + ongoingBuild.size() + " build currently on execution. Limit: " + kernelEnabledNode.intdiv(2) | |
317 | println "Currently " + queuedTask.findAll{it.task.getParent().name.startsWith(jobStartWithModule)}.size() + " module jobs are queued. Limit: " + limitQueue | |
318 | println "Currently " + queuedTask.findAll{it.task.getParent().name.startsWith(jobStartWithKernel)}.size() + " kernel jobs are queued. Limit: " + limitQueue | |
319 | Thread.sleep(random.nextInt(60000)) | |
320 | ongoingBuild.removeAll{ it.isCancelled() || it.isDone() } | |
321 | } | |
162a2360 JR |
322 | } |
323 | ||
c76d8fe2 | 324 | if (fail){ |
3f5b174c | 325 | throw new AbortException("Some job failed") |
c76d8fe2 JR |
326 | } |
327 | """ | |
328 | def dslTriggerModule = """\ | |
329 | import hudson.model.* | |
330 | import hudson.AbortException | |
331 | import hudson.console.HyperlinkNote | |
332 | import java.util.concurrent.CancellationException | |
c086345d | 333 | import java.util.Random |
c76d8fe2 JR |
334 | |
335 | ||
c086345d | 336 | Random random = new Random() |
c76d8fe2 JR |
337 | def jobs = hudson.model.Hudson.instance.items |
338 | def fail = false | |
3b0b4cdc JR |
339 | def modulePrefix = "MODULEPREFIX" |
340 | def branchName = "BRANCHNAME" | |
341 | def kernelPrefix = "KERNELPREFIX" | |
342 | def nodeLabels=["kernel"] | |
343 | def validNodeDivider = 2 | |
344 | ||
345 | def fullModulePrefix = modulesPrefix + branchName | |
346 | ||
f6613988 JR |
347 | def toBuild = [] |
348 | def counter = 0 | |
6776fe0b | 349 | def limitQueue = 4 |
c76d8fe2 | 350 | |
c76d8fe2 | 351 | jobs.each { job -> |
f6613988 | 352 | def jobName = job.getName() |
3b0b4cdc | 353 | if (jobName.startsWith(fullModulePrefix)) { |
f6613988 JR |
354 | counter = counter + 1 |
355 | toBuild.push(job) | |
356 | } | |
357 | } | |
358 | ||
3b0b4cdc JR |
359 | // Get valid labeled node node |
360 | def validNodeCount = 0 | |
f6613988 | 361 | hudson.model.Hudson.instance.nodes.each { node -> |
3b0b4cdc JR |
362 | def valid = true |
363 | nodeLabels.each { label -> | |
364 | if (!node.getLabelString().contains(nodeLabel)){ | |
365 | valid = false | |
366 | break; | |
367 | } | |
368 | } | |
369 | if (valid){ | |
370 | validNodeCount++ | |
f6613988 JR |
371 | } |
372 | } | |
373 | ||
3b0b4cdc JR |
374 | // Divide the valid node by validNodeDivider based on user defined label slave descriminant ex arck type |
375 | def finalValidNodeCount = validNodeCount.intdiv(validNodeDivider | |
376 | ||
377 | // Scheduling | |
378 | ||
f6613988 | 379 | def ongoingBuild = [] |
6776fe0b | 380 | def q = jenkins.model.Jenkins.getInstance().getQueue() |
3b0b4cdc JR |
381 | def queuedTaskKernel = 0 |
382 | def queuedTaskModule = 0 | |
383 | def sleep = 0 | |
6776fe0b | 384 | |
f6613988 | 385 | while (toBuild.size() != 0) { |
6776fe0b JR |
386 | // Throttle the build with both the number of current parent task and queued |
387 | // task.Look for both kernel and downstream module from previous kernel. | |
3b0b4cdc JR |
388 | queuedTaskKernel = q.getItems().findAll {it.task.getParent().getDisplayName().startsWith(jobStartWithKernel)}.size() |
389 | queuedTaskModule = q.getItems().findAll {it.task.getParent().getDisplayName().startsWith(jobStartWithModule)}.size() | |
390 | if ((ongoingBuild.size() <= finalValidNodeCount) && (queuedTaskKernel + queuedTaskModule < limitQueue)) { | |
f6613988 JR |
391 | def job = toBuild.pop() |
392 | ongoingBuild.push(job.scheduleBuild2(0)) | |
3b0b4cdc | 393 | println "\t trigering " + HyperlinkNote.encodeTo('/' + job.url, job.fullDisplayName) |
f6613988 | 394 | } else { |
3b0b4cdc JR |
395 | println "Holding trigger" |
396 | println "Currently " + ongoingBuild.size() + " build ongoing. Max = " + validNodeCount | |
397 | println "Currently " + queuedTaskKernel + " Kernel build ongoing." | |
398 | println "Currently " + queuedTaskModule + " LTTng-modules build ongoing." | |
399 | println "Limit for combination of both:" + limitQueue | |
400 | ||
401 | sleep = random.nextInt(60000) | |
402 | println "Sleeping for " + sleep.intdiv(1000) + " seconds" | |
403 | Thread.sleep(sleep) | |
f6613988 JR |
404 | ongoingBuild.removeAll{ it.isCancelled() || it.isDone() } |
405 | } | |
c76d8fe2 | 406 | } |
162a2360 | 407 | if (fail){ |
f6613988 | 408 | throw new AbortException("Some job failed") |
162a2360 JR |
409 | } |
410 | """ | |
acd2d777 JR |
411 | |
412 | dslTriggerKernel = dslTriggerKernel.replaceAll("KERNELPREFIX", kernelPrefix) | |
413 | dslTriggerKernel = dslTriggerKernel.replaceAll("MODULEPREFIX", modulesPrefix) | |
162a2360 JR |
414 | if (isJenkinsInstance) { |
415 | freeStyleJob("dsl-trigger-kernel") { | |
416 | steps { | |
6f47f2cd | 417 | systemGroovyCommand(dslTriggerKernel) |
162a2360 | 418 | } |
d585fdc4 JR |
419 | triggers { |
420 | cron("H 0 * * *") | |
421 | } | |
c76d8fe2 JR |
422 | } |
423 | ||
424 | modulesBranches.each { branch -> | |
3b0b4cdc JR |
425 | dslTriggerModule = dslTriggerModule.replaceAll("MODULEPREFIX",modulesPrefix + separator + branch + separator) |
426 | dslTriggerModule = dslTriggerModule.replaceAll("BRANCHNAME",separator + branch + separator) | |
c76d8fe2 JR |
427 | freeStyleJob("dsl-trigger-module-${branch}") { |
428 | steps { | |
acd2d777 | 429 | systemGroovyCommand(dslTriggerModule) |
c76d8fe2 | 430 | } |
d585fdc4 JR |
431 | triggers { |
432 | scm('@daily') | |
433 | } | |
c76d8fe2 JR |
434 | } |
435 | } | |
162a2360 | 436 | } |
017c762b | 437 | } |