Skip to content

Commit cb7ee2b

Browse files
authored
Merge pull request #439 from jkloetzke/fix-jenkins-cyclic-jobs
Fix jenkins cyclic jobs
2 parents 6f08ca3 + 91e04fb commit cb7ee2b

File tree

6 files changed

+68
-18
lines changed

6 files changed

+68
-18
lines changed

pym/bob/cmds/jenkins.py

Lines changed: 29 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,23 @@ def verifyAuditMeta(meta):
181181
valid = re.compile(r"[0-9A-Za-z._-]+")
182182
return all(valid.fullmatch(k) for k in meta.keys())
183183

184+
def getJenkinsVariantId(step):
185+
"""Get the variant-id of a step with it's sandbox dependency.
186+
187+
Even though the sandbox is considered an invariant of the build
188+
(sandboxInvariant policy) it still needs to be respected when building the
189+
packages. Because the Jenkins logic cannot rely on lazy evaluation like the
190+
local builds we need to regard the sandbox as real dependency.
191+
192+
This is only relevant when calculating the job graph. The actual build
193+
result still uses the original variant- and build-id.
194+
"""
195+
vid = step.getVariantId()
196+
sandbox = step.getSandbox()
197+
if sandbox:
198+
vid += sandbox.getStep().getVariantId()
199+
return vid
200+
184201
class JenkinsJob:
185202
def __init__(self, name, displayName, nameCalculator, recipe, archiveBackend):
186203
self.__name = name
@@ -242,7 +259,7 @@ def getDescription(self, date, warnLazy):
242259
return "\n".join(description)
243260

244261
def addStep(self, step):
245-
vid = step.getVariantId()
262+
vid = getJenkinsVariantId(step)
246263
if step.isCheckoutStep():
247264
self.__checkoutSteps.setdefault(vid, step)
248265
elif step.isBuildStep():
@@ -262,7 +279,7 @@ def addStep(self, step):
262279
# add dependencies unless they are built by this job or invalid
263280
for dep in step.getAllDepSteps(True):
264281
if not dep.isValid(): continue
265-
vid = dep.getVariantId()
282+
vid = getJenkinsVariantId(dep)
266283
if vid in self.__steps: continue
267284
self.__deps.setdefault(vid, dep)
268285

@@ -1108,7 +1125,7 @@ def sanitize(self):
11081125
# Helper function that recursively adds the packages to the graph.
11091126
# Recursion stops at already known packages.
11101127
def addStep(step, parentJob):
1111-
sbxVariantId = step._getSandboxVariantId()
1128+
sbxVariantId = getJenkinsVariantId(step)
11121129
job = vidToJob.get(sbxVariantId)
11131130
if job is None:
11141131
if step.isPackageStep():
@@ -1207,9 +1224,9 @@ def longestPrefix(pkgs):
12071224

12081225
def getJobDisplayName(self, step):
12091226
if step.isPackageStep():
1210-
vid = step._getSandboxVariantId()
1227+
vid = getJenkinsVariantId(step)
12111228
else:
1212-
vid = step.getPackage().getPackageStep()._getSandboxVariantId()
1229+
vid = getJenkinsVariantId(step.getPackage().getPackageStep())
12131230
return self.__prefix + self.__packageName[vid]
12141231

12151232
def getJobInternalName(self, step):
@@ -1220,11 +1237,11 @@ def _genJenkinsJobs(step, jobs, nameCalculator, archiveBackend, seenPackages, al
12201237
shortdescription):
12211238

12221239
if step.isPackageStep() and shortdescription:
1223-
if step.getVariantId() in allVariantIds:
1240+
if getJenkinsVariantId(step) in allVariantIds:
12241241
name = nameCalculator.getJobInternalName(step)
12251242
return jobs[name]
12261243
else:
1227-
allVariantIds.add(step.getVariantId())
1244+
allVariantIds.add(getJenkinsVariantId(step))
12281245

12291246
name = nameCalculator.getJobInternalName(step)
12301247
if name in jobs:
@@ -1272,14 +1289,8 @@ def jenkinsNameFormatter(step, props):
12721289
def jenkinsNamePersister(jenkins, wrapFmt, uuid):
12731290

12741291
def persist(step, props):
1275-
vid = step.getVariantId()
1276-
# Make sure that build steps of sandboxed and non-sandboxed builds are
1277-
# not mixed. Does not apply to other steps because checkout steps must
1278-
# be self contained and package steps are always built clean.
1279-
if step.isBuildStep():
1280-
vid += b'\x00' if step.getSandbox() is None else b'\x01'
12811292
ret = BobState().getJenkinsByNameDirectory(
1282-
jenkins, wrapFmt(step, props), vid)
1293+
jenkins, wrapFmt(step, props), getJenkinsVariantId(step))
12831294
if uuid: ret = ret + "-" + uuid
12841295
return ret
12851296

@@ -1328,13 +1339,13 @@ def genJenkinsJobs(recipes, jenkins):
13281339
return jobs
13291340

13301341
def genJenkinsBuildOrder(jobs):
1331-
def visit(j, pending, processing, order):
1342+
def visit(j, pending, processing, order, stack):
13321343
if j in processing:
1333-
raise ParseError("Jobs are cyclic")
1344+
raise ParseError("Jobs are cyclic: " + " -> ".join(stack))
13341345
if j in pending:
13351346
processing.add(j)
13361347
for d in jobs[j].getDependentJobs():
1337-
visit(d, pending, processing, order)
1348+
visit(d, pending, processing, order, stack + [d])
13381349
pending.remove(j)
13391350
processing.remove(j)
13401351
order.append(j)
@@ -1345,7 +1356,7 @@ def visit(j, pending, processing, order):
13451356
while pending:
13461357
j = pending.pop()
13471358
pending.add(j)
1348-
visit(j, pending, processing, order)
1359+
visit(j, pending, processing, order, [j])
13491360

13501361
return order
13511362

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
bobMinimumVersion: "0.19"
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
packageScript: |
2+
true
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
root: True
2+
3+
depends:
4+
- name: sandbox
5+
use: [sandbox]
6+
forward: True
7+
- prog
8+
9+
buildScript: |
10+
true
11+
packageScript: |
12+
true
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
depends:
2+
- prog
3+
4+
buildScript: |
5+
true
6+
packageScript: |
7+
true
8+
9+
provideSandbox:
10+
paths: []
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#!/bin/bash -e
2+
. ../test-lib.sh 2>/dev/null || { echo "Must run in script directory!" ; exit 1 ; }
3+
4+
# Regression test for #438 to see if jenkins jobs can still be generated even
5+
# if identical package (prog) is built inside and outside of sandbox in same
6+
# project.
7+
8+
cleanup
9+
10+
exp="$(mktemp -d)"
11+
trap 'rm -rf "$exp"' EXIT
12+
13+
run_bob jenkins add local http://example.test/ -r root
14+
run_bob jenkins export local "$exp"

0 commit comments

Comments
 (0)