screwdriver-api 8.0.10 → 8.0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/plugins/builds/helper/updateBuild.js +16 -5
- package/plugins/builds/triggers/and.js +0 -1
- package/plugins/builds/triggers/helpers.js +66 -75
- package/plugins/builds/triggers/joinBase.js +4 -15
- package/plugins/builds/triggers/orBase.js +8 -2
- package/plugins/builds/triggers/remoteJoin.js +1 -9
- package/plugins/jobs/buildCluster/update.js +1 -1
package/package.json
CHANGED
|
@@ -135,18 +135,26 @@ async function getStage({ stageFactory, workflowGraph, jobName, pipelineId }) {
|
|
|
135
135
|
}
|
|
136
136
|
|
|
137
137
|
/**
|
|
138
|
-
*
|
|
138
|
+
* Get all builds in stage
|
|
139
139
|
*
|
|
140
140
|
* @param {Stage} stage Stage
|
|
141
141
|
* @param {Event} event Event
|
|
142
|
-
* @return {
|
|
142
|
+
* @return {Promise<Build[]>} Builds in stage
|
|
143
143
|
*/
|
|
144
|
-
async function
|
|
144
|
+
async function getStageJobBuilds({ stage, event }) {
|
|
145
145
|
// Get all jobIds for jobs in the stage
|
|
146
146
|
const stageJobIds = [...stage.jobIds, stage.setup];
|
|
147
147
|
|
|
148
148
|
// Get all builds in a stage for this event
|
|
149
|
-
|
|
149
|
+
return event.getBuilds({ params: { jobId: stageJobIds } });
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Checks if all builds in stage are done running
|
|
154
|
+
* @param {Build[]} stageJobBuilds Builds in stage
|
|
155
|
+
* @returns {Boolean} Flag if stage is done
|
|
156
|
+
*/
|
|
157
|
+
function isStageDone(stageJobBuilds) {
|
|
150
158
|
let stageIsDone = false;
|
|
151
159
|
|
|
152
160
|
if (stageJobBuilds && stageJobBuilds.length !== 0) {
|
|
@@ -292,10 +300,13 @@ async function updateBuildAndTriggerDownstreamJobs(config, build, server, userna
|
|
|
292
300
|
|
|
293
301
|
// Start stage teardown build if stage is done
|
|
294
302
|
if (stageTeardownBuild && stageTeardownBuild.status === 'CREATED') {
|
|
295
|
-
const
|
|
303
|
+
const stageJobBuilds = await getStageJobBuilds({ stage, event: newEvent });
|
|
304
|
+
const stageIsDone = isStageDone(stageJobBuilds);
|
|
296
305
|
|
|
297
306
|
if (stageIsDone) {
|
|
298
307
|
stageTeardownBuild.status = 'QUEUED';
|
|
308
|
+
stageTeardownBuild.parentBuildId = stageJobBuilds.map(b => b.id);
|
|
309
|
+
|
|
299
310
|
await stageTeardownBuild.update();
|
|
300
311
|
await stageTeardownBuild.start();
|
|
301
312
|
}
|
|
@@ -534,10 +534,9 @@ async function getBuildsForGroupEvent(groupEventId, buildFactory) {
|
|
|
534
534
|
* @param {Object} arg
|
|
535
535
|
* @param {ParentBuilds} arg.joinParentBuilds Parent builds object for join job
|
|
536
536
|
* @param {Build} arg.nextBuild Next build
|
|
537
|
-
* @param {Build} arg.build Build for current completed job
|
|
538
537
|
* @returns {Promise<Build>} Updated next build
|
|
539
538
|
*/
|
|
540
|
-
async function updateParentBuilds({ joinParentBuilds, nextBuild
|
|
539
|
+
async function updateParentBuilds({ joinParentBuilds, nextBuild }) {
|
|
541
540
|
// Override old parentBuilds info
|
|
542
541
|
const newParentBuilds = merge({}, joinParentBuilds, nextBuild.parentBuilds, (objVal, srcVal) =>
|
|
543
542
|
// passthrough objects, else mergeWith mutates source
|
|
@@ -545,59 +544,69 @@ async function updateParentBuilds({ joinParentBuilds, nextBuild, build }) {
|
|
|
545
544
|
);
|
|
546
545
|
|
|
547
546
|
nextBuild.parentBuilds = newParentBuilds;
|
|
548
|
-
// nextBuild.parentBuildId may be int or Array, so it needs to be flattened
|
|
549
|
-
nextBuild.parentBuildId = Array.from(new Set([build.id, nextBuild.parentBuildId || []].flat()));
|
|
550
547
|
|
|
551
548
|
return nextBuild.update();
|
|
552
549
|
}
|
|
553
550
|
|
|
554
551
|
/**
|
|
555
|
-
*
|
|
556
|
-
* @param {
|
|
557
|
-
* @param {Build} arg.newBuild Updated build
|
|
552
|
+
* Get builds in join list from parent builds
|
|
553
|
+
* @param {newBuild} arg.newBuild Updated build
|
|
558
554
|
* @param {String[]} arg.joinListNames Join list names
|
|
559
555
|
* @param {Number} arg.pipelineId Pipeline ID
|
|
560
556
|
* @param {BuildFactory} arg.buildFactory Build factory
|
|
561
|
-
* @returns {Promise<
|
|
557
|
+
* @returns {Promise<Map<String, Build>>} Join builds
|
|
562
558
|
*/
|
|
563
|
-
async function
|
|
559
|
+
async function getJoinBuilds({ newBuild, joinListNames, pipelineId, buildFactory }) {
|
|
564
560
|
const upstream = newBuild.parentBuilds || {};
|
|
561
|
+
const joinBuilds = {};
|
|
565
562
|
|
|
566
|
-
|
|
567
|
-
const joinBuildIds = joinListNames.map(name => {
|
|
563
|
+
for (const jobName of joinListNames) {
|
|
568
564
|
let upstreamPipelineId = pipelineId;
|
|
569
|
-
let upstreamJobName =
|
|
565
|
+
let upstreamJobName = jobName;
|
|
570
566
|
|
|
571
|
-
if (isExternalTrigger(
|
|
572
|
-
const { externalPipelineId, externalJobName } = getExternalPipelineAndJob(
|
|
567
|
+
if (isExternalTrigger(upstreamJobName)) {
|
|
568
|
+
const { externalPipelineId, externalJobName } = getExternalPipelineAndJob(jobName);
|
|
573
569
|
|
|
574
570
|
upstreamPipelineId = externalPipelineId;
|
|
575
571
|
upstreamJobName = externalJobName;
|
|
576
572
|
}
|
|
577
573
|
|
|
578
574
|
if (upstream[upstreamPipelineId] && upstream[upstreamPipelineId].jobs[upstreamJobName]) {
|
|
579
|
-
|
|
575
|
+
const buildId = upstream[upstreamPipelineId].jobs[upstreamJobName];
|
|
576
|
+
|
|
577
|
+
const build = await buildFactory.get(buildId);
|
|
578
|
+
|
|
579
|
+
if (typeof build.endTime === 'string') {
|
|
580
|
+
build.endTime = new Date(build.endTime);
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
joinBuilds[jobName] = build;
|
|
580
584
|
}
|
|
585
|
+
}
|
|
581
586
|
|
|
582
|
-
|
|
583
|
-
|
|
587
|
+
return joinBuilds;
|
|
588
|
+
}
|
|
584
589
|
|
|
590
|
+
/**
|
|
591
|
+
* Check if all parent builds of the new build are done
|
|
592
|
+
* @param {Object} arg
|
|
593
|
+
* @param {String[]} arg.joinListNames Join list names
|
|
594
|
+
* @param {String[]} arg.joinBuilds Join builds
|
|
595
|
+
* @returns {Promise<{hasFailure: Boolean, done: Boolean}>} Object with done and hasFailure statuses
|
|
596
|
+
*/
|
|
597
|
+
async function getParentBuildStatus({ joinListNames, joinBuilds }) {
|
|
585
598
|
// If buildId is empty, the job hasn't executed yet and the join is not done
|
|
586
|
-
const isExecuted =
|
|
587
|
-
|
|
588
|
-
// Get the status of the builds
|
|
589
|
-
const buildIds = joinBuildIds.filter(buildId => buildId !== undefined);
|
|
590
|
-
const promisesToAwait = buildIds.map(buildId => buildFactory.get(buildId));
|
|
591
|
-
const joinedBuilds = await Promise.all(promisesToAwait);
|
|
599
|
+
const isExecuted = joinListNames.every(name => joinBuilds[name] !== undefined);
|
|
600
|
+
const parentBuilds = Object.values(joinBuilds);
|
|
592
601
|
|
|
593
|
-
const hasFailure =
|
|
602
|
+
const hasFailure = parentBuilds
|
|
594
603
|
.map(build => {
|
|
595
604
|
// Do not need to run the next build; terminal status
|
|
596
605
|
return [Status.FAILURE, Status.ABORTED, Status.COLLAPSED, Status.UNSTABLE].includes(build.status);
|
|
597
606
|
})
|
|
598
607
|
.includes(true);
|
|
599
608
|
|
|
600
|
-
const isDoneStatus =
|
|
609
|
+
const isDoneStatus = parentBuilds.every(build => {
|
|
601
610
|
// All builds are done
|
|
602
611
|
return [Status.FAILURE, Status.SUCCESS, Status.ABORTED, Status.UNSTABLE, Status.COLLAPSED].includes(
|
|
603
612
|
build.status
|
|
@@ -616,40 +625,40 @@ async function getParentBuildStatus({ newBuild, joinListNames, pipelineId, build
|
|
|
616
625
|
* if no failure, start new build
|
|
617
626
|
* Otherwise, do nothing
|
|
618
627
|
* @param {Object} arg If the build is done or not
|
|
619
|
-
* @param {
|
|
620
|
-
* @param {Boolean} arg.hasFailure If the build has a failure or not
|
|
628
|
+
* @param {String[]} arg.joinListNames Join list names
|
|
621
629
|
* @param {Build} arg.newBuild Next build
|
|
622
630
|
* @param {Job} arg.job Next job
|
|
623
631
|
* @param {String|undefined} arg.pipelineId Pipeline ID
|
|
624
632
|
* @param {String|undefined} arg.stageName Stage name
|
|
625
633
|
* @param {Boolean} arg.isVirtualJob If the job is virtual or not
|
|
626
634
|
* @param {Event} arg.event Event
|
|
627
|
-
* @param {
|
|
635
|
+
* @param {BuildFactory} arg.buildFactory Build factory
|
|
628
636
|
* @returns {Promise<Build|null>} The newly updated/created build
|
|
629
637
|
*/
|
|
630
638
|
async function handleNewBuild({
|
|
631
|
-
|
|
632
|
-
hasFailure,
|
|
639
|
+
joinListNames,
|
|
633
640
|
newBuild,
|
|
634
641
|
job,
|
|
635
642
|
pipelineId,
|
|
636
643
|
stageName,
|
|
637
644
|
isVirtualJob,
|
|
638
645
|
event,
|
|
639
|
-
|
|
646
|
+
buildFactory
|
|
640
647
|
}) {
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
if (isVirtualJob && !hasFreezeWindows(job)) {
|
|
648
|
-
newBuild.meta = merge({}, newBuild.meta, currentBuild.meta);
|
|
648
|
+
const joinBuilds = await getJoinBuilds({
|
|
649
|
+
newBuild,
|
|
650
|
+
joinListNames,
|
|
651
|
+
pipelineId,
|
|
652
|
+
buildFactory
|
|
653
|
+
});
|
|
649
654
|
|
|
650
|
-
|
|
651
|
-
|
|
655
|
+
/* CHECK IF ALL PARENT BUILDS OF NEW BUILD ARE DONE */
|
|
656
|
+
const { hasFailure, done } = await getParentBuildStatus({
|
|
657
|
+
joinBuilds,
|
|
658
|
+
joinListNames
|
|
659
|
+
});
|
|
652
660
|
|
|
661
|
+
if (!done || Status.isStarted(newBuild.status)) {
|
|
653
662
|
return null;
|
|
654
663
|
}
|
|
655
664
|
|
|
@@ -668,14 +677,28 @@ async function handleNewBuild({
|
|
|
668
677
|
return null;
|
|
669
678
|
}
|
|
670
679
|
|
|
680
|
+
/* Prepare to execute the build */
|
|
681
|
+
const parentBuilds = Object.values(joinBuilds);
|
|
682
|
+
|
|
683
|
+
parentBuilds.sort((l, r) => {
|
|
684
|
+
if (l.endTime && r.endTime) {
|
|
685
|
+
return l.endTime.getTime() - r.endTime.getTime();
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
// Move to tail if endTime is not set
|
|
689
|
+
return (l.endTime ? 0 : 1) - (r.endTime ? 0 : 1);
|
|
690
|
+
});
|
|
691
|
+
newBuild.parentBuildId = parentBuilds.map(build => build.id);
|
|
692
|
+
|
|
671
693
|
// Bypass execution of the build if the job is virtual
|
|
672
694
|
if (isVirtualJob && !hasFreezeWindows(job)) {
|
|
673
695
|
newBuild.status = Status.SUCCESS;
|
|
674
696
|
newBuild.statusMessage = BUILD_STATUS_MESSAGES.SKIP_VIRTUAL_JOB.statusMessage;
|
|
675
697
|
newBuild.statusMessageType = BUILD_STATUS_MESSAGES.SKIP_VIRTUAL_JOB.statusMessageType;
|
|
698
|
+
|
|
676
699
|
// The virtual job does not inherit metadata because the Launcher is not executed.
|
|
677
700
|
// Therefore, it is necessary to take over the metadata from the previous build.
|
|
678
|
-
newBuild.meta = merge(
|
|
701
|
+
newBuild.meta = parentBuilds.reduce((acc, build) => merge(acc, build.meta), {});
|
|
679
702
|
|
|
680
703
|
return newBuild.update();
|
|
681
704
|
}
|
|
@@ -1015,38 +1038,6 @@ async function ensureStageTeardownBuildExists({
|
|
|
1015
1038
|
}
|
|
1016
1039
|
}
|
|
1017
1040
|
|
|
1018
|
-
/**
|
|
1019
|
-
* Get parentBuildId from parentBuilds object
|
|
1020
|
-
* @param {Object} arg
|
|
1021
|
-
* @param {ParentBuilds} arg.parentBuilds Builds that triggered this build
|
|
1022
|
-
* @param {String[]} arg.joinListNames Array of join job name
|
|
1023
|
-
* @param {Number} arg.pipelineId Pipeline ID
|
|
1024
|
-
* @returns {String[]} Array of parentBuildId
|
|
1025
|
-
*/
|
|
1026
|
-
function getParentBuildIds({ currentBuildId, parentBuilds, joinListNames, pipelineId }) {
|
|
1027
|
-
const parentBuildIds = joinListNames
|
|
1028
|
-
.map(name => {
|
|
1029
|
-
let parentBuildPipelineId = pipelineId;
|
|
1030
|
-
let parentBuildJobName = name;
|
|
1031
|
-
|
|
1032
|
-
if (isExternalTrigger(name)) {
|
|
1033
|
-
const { externalPipelineId, externalJobName } = getExternalPipelineAndJob(name);
|
|
1034
|
-
|
|
1035
|
-
parentBuildPipelineId = externalPipelineId;
|
|
1036
|
-
parentBuildJobName = externalJobName;
|
|
1037
|
-
}
|
|
1038
|
-
|
|
1039
|
-
if (parentBuilds[parentBuildPipelineId] && parentBuilds[parentBuildPipelineId].jobs[parentBuildJobName]) {
|
|
1040
|
-
return parentBuilds[parentBuildPipelineId].jobs[parentBuildJobName];
|
|
1041
|
-
}
|
|
1042
|
-
|
|
1043
|
-
return null;
|
|
1044
|
-
})
|
|
1045
|
-
.filter(Boolean); // Remove undefined or null values
|
|
1046
|
-
|
|
1047
|
-
return Array.from(new Set([currentBuildId, ...parentBuildIds]));
|
|
1048
|
-
}
|
|
1049
|
-
|
|
1050
1041
|
/**
|
|
1051
1042
|
* Extract a current pipeline's next jobs from pipeline join data
|
|
1052
1043
|
* (Next jobs triggered as external are not included)
|
|
@@ -1206,13 +1197,13 @@ module.exports = {
|
|
|
1206
1197
|
getSameParentEvents,
|
|
1207
1198
|
mergeParentBuilds,
|
|
1208
1199
|
updateParentBuilds,
|
|
1200
|
+
getJoinBuilds,
|
|
1209
1201
|
getParentBuildStatus,
|
|
1210
1202
|
handleNewBuild,
|
|
1211
1203
|
ensureStageTeardownBuildExists,
|
|
1212
1204
|
getBuildsForGroupEvent,
|
|
1213
1205
|
createJoinObject,
|
|
1214
1206
|
createExternalEvent,
|
|
1215
|
-
getParentBuildIds,
|
|
1216
1207
|
strToInt,
|
|
1217
1208
|
createEvent,
|
|
1218
1209
|
deleteBuild,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const logger = require('screwdriver-logger');
|
|
4
|
-
const { createInternalBuild, updateParentBuilds,
|
|
4
|
+
const { createInternalBuild, updateParentBuilds, handleNewBuild } = require('./helpers');
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* @typedef {import('screwdriver-models').EventFactory} EventFactory
|
|
@@ -41,7 +41,6 @@ class JoinBase {
|
|
|
41
41
|
* @param {Build} nextBuild
|
|
42
42
|
* @param {Job} nextJob
|
|
43
43
|
* @param {import('./helpers').ParentBuilds} parentBuilds
|
|
44
|
-
* @param {String} parentBuildId
|
|
45
44
|
* @param {String[]} joinListNames
|
|
46
45
|
* @param {Boolean} isNextJobVirtual
|
|
47
46
|
* @param {String} nextJobStageName
|
|
@@ -53,7 +52,6 @@ class JoinBase {
|
|
|
53
52
|
nextBuild,
|
|
54
53
|
nextJob,
|
|
55
54
|
parentBuilds,
|
|
56
|
-
parentBuildId,
|
|
57
55
|
joinListNames,
|
|
58
56
|
isNextJobVirtual,
|
|
59
57
|
nextJobStageName
|
|
@@ -73,7 +71,7 @@ class JoinBase {
|
|
|
73
71
|
event, // this is the parentBuild for the next build
|
|
74
72
|
baseBranch: event.baseBranch || null,
|
|
75
73
|
parentBuilds,
|
|
76
|
-
parentBuildId,
|
|
74
|
+
parentBuildId: this.currentBuild.id,
|
|
77
75
|
start: false
|
|
78
76
|
});
|
|
79
77
|
} else {
|
|
@@ -90,24 +88,15 @@ class JoinBase {
|
|
|
90
88
|
return null;
|
|
91
89
|
}
|
|
92
90
|
|
|
93
|
-
/* CHECK IF ALL PARENT BUILDS OF NEW BUILD ARE DONE */
|
|
94
|
-
const { hasFailure, done } = await getParentBuildStatus({
|
|
95
|
-
newBuild,
|
|
96
|
-
joinListNames,
|
|
97
|
-
pipelineId,
|
|
98
|
-
buildFactory: this.buildFactory
|
|
99
|
-
});
|
|
100
|
-
|
|
101
91
|
return handleNewBuild({
|
|
102
|
-
|
|
103
|
-
hasFailure,
|
|
92
|
+
joinListNames,
|
|
104
93
|
newBuild,
|
|
105
94
|
job: nextJob,
|
|
106
95
|
pipelineId,
|
|
107
96
|
isVirtualJob: isNextJobVirtual,
|
|
108
97
|
stageName: nextJobStageName,
|
|
109
98
|
event,
|
|
110
|
-
|
|
99
|
+
buildFactory: this.buildFactory
|
|
111
100
|
});
|
|
112
101
|
}
|
|
113
102
|
}
|
|
@@ -56,12 +56,16 @@ class OrBase {
|
|
|
56
56
|
return nextBuild;
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
+
nextBuild.parentBuildId = [this.currentBuild.id];
|
|
60
|
+
|
|
59
61
|
// Bypass execution of the build if the job is virtual
|
|
60
62
|
if (isNextJobVirtual && !hasWindows) {
|
|
61
63
|
nextBuild.status = Status.SUCCESS;
|
|
62
64
|
nextBuild.statusMessage = BUILD_STATUS_MESSAGES.SKIP_VIRTUAL_JOB.statusMessage;
|
|
63
65
|
nextBuild.statusMessageType = BUILD_STATUS_MESSAGES.SKIP_VIRTUAL_JOB.statusMessageType;
|
|
64
|
-
|
|
66
|
+
|
|
67
|
+
// Overwrite metadata by current build's
|
|
68
|
+
nextBuild.meta = merge({}, this.currentBuild.meta);
|
|
65
69
|
|
|
66
70
|
return nextBuild.update();
|
|
67
71
|
}
|
|
@@ -93,7 +97,9 @@ class OrBase {
|
|
|
93
97
|
nextBuild.status = Status.SUCCESS;
|
|
94
98
|
nextBuild.statusMessage = BUILD_STATUS_MESSAGES.SKIP_VIRTUAL_JOB.statusMessage;
|
|
95
99
|
nextBuild.statusMessageType = BUILD_STATUS_MESSAGES.SKIP_VIRTUAL_JOB.statusMessageType;
|
|
96
|
-
|
|
100
|
+
|
|
101
|
+
// Overwrite metadata by current build's
|
|
102
|
+
nextBuild.meta = merge({}, this.currentBuild.meta);
|
|
97
103
|
|
|
98
104
|
await nextBuild.update();
|
|
99
105
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const { mergeParentBuilds
|
|
3
|
+
const { mergeParentBuilds } = require('./helpers');
|
|
4
4
|
const { JoinBase } = require('./joinBase');
|
|
5
5
|
|
|
6
6
|
/**
|
|
@@ -45,20 +45,12 @@ class RemoteJoin extends JoinBase {
|
|
|
45
45
|
|
|
46
46
|
const newParentBuilds = mergeParentBuilds(parentBuilds, groupEventBuilds, this.currentEvent, externalEvent);
|
|
47
47
|
|
|
48
|
-
const parentBuildId = getParentBuildIds({
|
|
49
|
-
currentBuildId: this.currentBuild.id,
|
|
50
|
-
parentBuilds: newParentBuilds,
|
|
51
|
-
joinListNames,
|
|
52
|
-
pipelineId: externalEvent.pipelineId
|
|
53
|
-
});
|
|
54
|
-
|
|
55
48
|
return this.processNextBuild({
|
|
56
49
|
pipelineId: externalEvent.pipelineId,
|
|
57
50
|
event: externalEvent,
|
|
58
51
|
nextBuild,
|
|
59
52
|
nextJob,
|
|
60
53
|
parentBuilds: newParentBuilds,
|
|
61
|
-
parentBuildId,
|
|
62
54
|
joinListNames,
|
|
63
55
|
isNextJobVirtual,
|
|
64
56
|
nextJobStageName
|