screwdriver-api 7.0.204 → 7.0.206

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "screwdriver-api",
3
- "version": "7.0.204",
3
+ "version": "7.0.206",
4
4
  "description": "API server for the Screwdriver.cd service",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -10,12 +10,10 @@
10
10
  "start": "./bin/server",
11
11
  "debug": "node --nolazy ./bin/server",
12
12
  "profile": "node --prof ./bin/server",
13
- "functional": "cucumber-js --format=progress --tags '(not @ignore) and (not @beta) and (not @x1) and (not @parallel)' --retry 2 --fail-fast --exit",
14
- "functional-parallel": "cucumber-js --format=progress --tags '(not @ignore) and (not @beta) and (not @x1) and @parallel' --retry 2 --fail-fast --exit --parallel 7",
15
- "functional-x1-parallel": "cucumber-js --format=progress --tags '(not @ignore) and (not @beta) and @x1 and @parallel' --retry 2 --fail-fast --exit --parallel 7",
13
+ "functional": "cucumber-js --format=progress --tags '(not @ignore) and @prod' --retry 2 --fail-fast --exit",
16
14
  "functional-beta": "cucumber-js --format=progress --tags '(not @ignore) and (not @prod) and (not @x1) and (not @parallel)' --retry 2 --fail-fast --exit",
17
- "functional-beta-parallel": "cucumber-js --format=progress --tags '(not @ignore) and (not @prod) and (not @x1) and @parallel' --retry 2 --fail-fast --exit --parallel 7",
18
- "functional-beta-x1-parallel": "cucumber-js --format=progress --tags '(not @ignore) and (not @prod) and @x1 and @parallel' --retry 2 --fail-fast --exit --parallel 7",
15
+ "functional-beta-parallel": "cucumber-js --format=progress --tags '(not @ignore) and (not @prod) and (not @x1) and @parallel' --retry 2 --fail-fast --exit --parallel 4",
16
+ "functional-beta-x1-parallel": "cucumber-js --format=progress --tags '(not @ignore) and (not @prod) and @x1 and @parallel' --retry 2 --fail-fast --exit --parallel 4",
19
17
  "functional-dev": "cucumber-js --format=progress --tags '(not @ignore) and (not @prod)' --retry 2 --fail-fast --exit",
20
18
  "create-test-user": "node -e 'require(\"./features/scripts/create-test-user.js\")()'",
21
19
  "diagrams": "find ./design/diagrams -type f -name \\*.puml -print0 | xargs -0 -n 1 -I DIAGRAM puml generate DIAGRAM -o DIAGRAM.png",
@@ -28,7 +28,7 @@ const {
28
28
  createEvent,
29
29
  parseJobInfo,
30
30
  ensureStageTeardownBuildExists,
31
- getJobId,
31
+ getJob,
32
32
  isOrTrigger,
33
33
  extractExternalJoinData,
34
34
  extractCurrentPipelineJoinData,
@@ -94,9 +94,9 @@ async function triggerNextJobs(config, app) {
94
94
 
95
95
  const downstreamOfNextJobsToBeProcessed = [];
96
96
 
97
- for (const [nextJobName, nextJob] of Object.entries(currentPipelineNextJobs)) {
98
- const nextJobId = nextJob.id || (await getJobId(nextJobName, currentPipeline.id, jobFactory));
99
- const { isVirtual: isNextJobVirtual, stageName: nextJobStageName } = nextJob;
97
+ for (const [nextJobName, nextJobInfo] of Object.entries(currentPipelineNextJobs)) {
98
+ const nextJob = await getJob(nextJobName, currentPipeline.id, jobFactory);
99
+ const { isVirtual: isNextJobVirtual, stageName: nextJobStageName } = nextJobInfo;
100
100
  const resource = `pipeline:${currentPipeline.id}:groupEvent:${currentEvent.groupEventId}`;
101
101
  let lock;
102
102
  let nextBuild;
@@ -125,15 +125,13 @@ async function triggerNextJobs(config, app) {
125
125
  nextBuild = await orTrigger.execute(
126
126
  currentEvent,
127
127
  currentPipeline.id,
128
- nextJobName,
129
- nextJobId,
128
+ nextJob,
130
129
  parentBuilds,
131
130
  isNextJobVirtual
132
131
  );
133
132
  } else {
134
133
  nextBuild = await andTrigger.execute(
135
- nextJobName,
136
- nextJobId,
134
+ nextJob,
137
135
  parentBuilds,
138
136
  joinListNames,
139
137
  isNextJobVirtual,
@@ -145,7 +143,7 @@ async function triggerNextJobs(config, app) {
145
143
  downstreamOfNextJobsToBeProcessed.push({
146
144
  build: nextBuild,
147
145
  event: currentEvent,
148
- job: await nextBuild.job,
146
+ job: nextJob,
149
147
  pipeline: currentPipeline,
150
148
  scmContext: config.scmContext,
151
149
  username: config.username
@@ -244,9 +242,9 @@ async function triggerNextJobs(config, app) {
244
242
 
245
243
  // Skip trigger process if createExternalEvent fails
246
244
  if (externalEvent) {
247
- for (const [nextJobName, nextJob] of Object.entries(joinedPipeline.jobs)) {
248
- const nextJobId = nextJob.id || (await getJobId(nextJobName, currentPipeline.id, jobFactory));
249
- const { isVirtual: isNextJobVirtual, stageName: nextJobStageName } = nextJob;
245
+ for (const [nextJobName, nextJobInfo] of Object.entries(joinedPipeline.jobs)) {
246
+ const nextJob = await getJob(nextJobName, joinedPipelineId, jobFactory);
247
+ const { isVirtual: isNextJobVirtual, stageName: nextJobStageName } = nextJobInfo;
250
248
 
251
249
  const { parentBuilds } = parseJobInfo({
252
250
  joinObj: joinedPipeline.jobs,
@@ -266,23 +264,21 @@ async function triggerNextJobs(config, app) {
266
264
  nextBuild = await remoteTrigger.execute(
267
265
  externalEvent,
268
266
  externalEvent.pipelineId,
269
- nextJobName,
270
- nextJobId,
267
+ nextJob,
271
268
  parentBuilds,
272
269
  isNextJobVirtual
273
270
  );
274
271
  } else {
275
272
  // Re get join list when first time remote trigger since external event was empty and cannot get workflow graph then
276
273
  const joinList =
277
- nextJob.join.length > 0
278
- ? nextJob.join
274
+ nextJobInfo.join.length > 0
275
+ ? nextJobInfo.join
279
276
  : workflowParser.getSrcForJoin(externalEvent.workflowGraph, { jobName: nextJobName });
280
277
  const joinListNames = joinList.map(j => j.name);
281
278
 
282
279
  nextBuild = await remoteJoin.execute(
283
280
  externalEvent,
284
- nextJobName,
285
- nextJobId,
281
+ nextJob,
286
282
  parentBuilds,
287
283
  groupEventBuilds,
288
284
  joinListNames,
@@ -292,13 +288,11 @@ async function triggerNextJobs(config, app) {
292
288
  }
293
289
 
294
290
  if (isNextJobVirtual && nextBuild.status === Status.SUCCESS) {
295
- const nextJobModel = await nextBuild.job;
296
-
297
291
  downstreamOfNextJobsToBeProcessed.push({
298
292
  build: nextBuild,
299
293
  event: currentEvent,
300
- job: nextJobModel,
301
- pipeline: await nextJobModel.pipeline,
294
+ job: nextJob,
295
+ pipeline: await nextJob.pipeline,
302
296
  scmContext: config.scmContext,
303
297
  username: config.username
304
298
  });
@@ -52,21 +52,20 @@ class AndTrigger extends JoinBase {
52
52
 
53
53
  /**
54
54
  * Trigger the next jobs of the current job
55
- * @param {String} nextJobName
56
- * @param {String} nextJobId
55
+ * @param {Job} nextJob
57
56
  * @param {Record<String, Object>} parentBuilds
58
57
  * @param {String[]} joinListNames
59
58
  * @param {Boolean} isNextJobVirtual
60
59
  * @param {String} nextJobStageName
61
60
  * @returns {Promise<Build>}
62
61
  */
63
- async execute(nextJobName, nextJobId, parentBuilds, joinListNames, isNextJobVirtual, nextJobStageName) {
62
+ async execute(nextJob, parentBuilds, joinListNames, isNextJobVirtual, nextJobStageName) {
64
63
  logger.info(`Fetching finished builds for event ${this.currentEvent.id}`);
65
64
 
66
65
  const relatedBuilds = await this.fetchRelatedBuilds();
67
66
 
68
67
  // Find the next build from the related builds for this event
69
- let nextBuild = relatedBuilds.find(b => b.jobId === nextJobId && b.eventId === this.currentEvent.id);
68
+ let nextBuild = relatedBuilds.find(b => b.jobId === nextJob.id && b.eventId === this.currentEvent.id);
70
69
 
71
70
  if (!nextBuild) {
72
71
  // If the build to join fails and it succeeds on restart, depending on the timing, the latest build will be that of a child event.
@@ -74,7 +73,7 @@ class AndTrigger extends JoinBase {
74
73
  // Now we need to check for the existence of a build that should be triggered in its own event.
75
74
  nextBuild = await this.buildFactory.get({
76
75
  eventId: this.currentEvent.id,
77
- jobId: nextJobId
76
+ jobId: nextJob.id
78
77
  });
79
78
 
80
79
  if (nextBuild) {
@@ -84,7 +83,7 @@ class AndTrigger extends JoinBase {
84
83
 
85
84
  if (!nextBuild) {
86
85
  // If the build to join is in the child event, its event id is greater than current event.
87
- nextBuild = relatedBuilds.find(b => b.jobId === nextJobId && b.eventId > this.currentEvent.id);
86
+ nextBuild = relatedBuilds.find(b => b.jobId === nextJob.id && b.eventId > this.currentEvent.id);
88
87
  }
89
88
  const newParentBuilds = mergeParentBuilds(parentBuilds, relatedBuilds, this.currentEvent, undefined);
90
89
  let nextEvent = this.currentEvent;
@@ -97,8 +96,7 @@ class AndTrigger extends JoinBase {
97
96
  pipelineId: this.pipelineId,
98
97
  event: nextEvent,
99
98
  nextBuild,
100
- nextJobName,
101
- nextJobId,
99
+ nextJob,
102
100
  parentBuilds: newParentBuilds,
103
101
  parentBuildId: this.currentBuild.id,
104
102
  joinListNames,
@@ -599,13 +599,13 @@ async function getParentBuildStatus({ newBuild, joinListNames, pipelineId, build
599
599
  * @param {Boolean} arg.done If the build is done or not
600
600
  * @param {Boolean} arg.hasFailure If the build has a failure or not
601
601
  * @param {Build} arg.newBuild Next build
602
- * @param {String|undefined} arg.jobName Job name
602
+ * @param {Job} arg.job Next job
603
603
  * @param {String|undefined} arg.pipelineId Pipeline ID
604
604
  * @param {String|undefined} arg.stageName Stage name
605
605
  * @param {Boolean} arg.isVirtualJob If the job is virtual or not
606
606
  * @returns {Promise<Build|null>} The newly updated/created build
607
607
  */
608
- async function handleNewBuild({ done, hasFailure, newBuild, jobName, pipelineId, stageName, isVirtualJob }) {
608
+ async function handleNewBuild({ done, hasFailure, newBuild, job, pipelineId, stageName, isVirtualJob }) {
609
609
  if (!done || Status.isStarted(newBuild.status)) {
610
610
  return null;
611
611
  }
@@ -615,9 +615,9 @@ async function handleNewBuild({ done, hasFailure, newBuild, jobName, pipelineId,
615
615
  const stageTeardownName = stageName ? getFullStageJobName({ stageName, jobName: 'teardown' }) : '';
616
616
 
617
617
  // New build is not stage teardown job
618
- if (jobName !== stageTeardownName) {
618
+ if (job.name !== stageTeardownName) {
619
619
  logger.info(
620
- `Failure occurred in upstream job, removing new build - build:${newBuild.id} pipeline:${pipelineId}-${jobName} event:${newBuild.eventId} `
620
+ `Failure occurred in upstream job, removing new build - build:${newBuild.id} pipeline:${pipelineId}-${job.name} event:${newBuild.eventId} `
621
621
  );
622
622
  await newBuild.remove();
623
623
  }
@@ -626,7 +626,9 @@ async function handleNewBuild({ done, hasFailure, newBuild, jobName, pipelineId,
626
626
  }
627
627
 
628
628
  // Bypass execution of the build if the job is virtual
629
- if (isVirtualJob) {
629
+ const hasFreezeWindows = job.permutations[0].freezeWindows && job.permutations[0].freezeWindows.length > 0;
630
+
631
+ if (isVirtualJob && !hasFreezeWindows) {
630
632
  newBuild.status = Status.SUCCESS;
631
633
 
632
634
  return newBuild.update();
@@ -1035,19 +1037,17 @@ function extractExternalJoinData(joinedPipelines, currentPipelineId) {
1035
1037
  }
1036
1038
 
1037
1039
  /**
1038
- * Get job id from job name
1040
+ * Get job from job name
1039
1041
  * @param {String} jobName Job name
1040
1042
  * @param {String} pipelineId Pipeline id
1041
1043
  * @param {JobFactory} jobFactory Job factory
1042
- * @returns {Promise<Number>}
1044
+ * @returns {Promise<Job>}
1043
1045
  */
1044
- async function getJobId(jobName, pipelineId, jobFactory) {
1045
- const job = await jobFactory.get({
1046
+ async function getJob(jobName, pipelineId, jobFactory) {
1047
+ return jobFactory.get({
1046
1048
  name: jobName,
1047
1049
  pipelineId
1048
1050
  });
1049
-
1050
- return job.id;
1051
1051
  }
1052
1052
 
1053
1053
  /**
@@ -1152,7 +1152,7 @@ module.exports = {
1152
1152
  strToInt,
1153
1153
  createEvent,
1154
1154
  deleteBuild,
1155
- getJobId,
1155
+ getJob,
1156
1156
  isOrTrigger,
1157
1157
  extractCurrentPipelineJoinData,
1158
1158
  extractExternalJoinData,
@@ -39,8 +39,7 @@ class JoinBase {
39
39
  * @param {Number} pipelineId
40
40
  * @param {Event} event
41
41
  * @param {Build} nextBuild
42
- * @param {String} nextJobName
43
- * @param {String} nextJobId
42
+ * @param {Job} nextJob
44
43
  * @param {import('./helpers').ParentBuilds} parentBuilds
45
44
  * @param {String} parentBuildId
46
45
  * @param {String[]} joinListNames
@@ -52,8 +51,7 @@ class JoinBase {
52
51
  pipelineId,
53
52
  event,
54
53
  nextBuild,
55
- nextJobName,
56
- nextJobId,
54
+ nextJob,
57
55
  parentBuilds,
58
56
  parentBuildId,
59
57
  joinListNames,
@@ -68,8 +66,8 @@ class JoinBase {
68
66
  jobFactory: this.jobFactory,
69
67
  buildFactory: this.buildFactory,
70
68
  pipelineId,
71
- jobName: nextJobName,
72
- jobId: nextJobId,
69
+ jobName: nextJob.name,
70
+ jobId: nextJob.id,
73
71
  username: this.username,
74
72
  scmContext: this.scmContext,
75
73
  event, // this is the parentBuild for the next build
@@ -87,7 +85,7 @@ class JoinBase {
87
85
  }
88
86
 
89
87
  if (!newBuild) {
90
- logger.error(`No build found for ${pipelineId}:${nextJobName}`);
88
+ logger.error(`No build found for ${pipelineId}:${nextJob.name}`);
91
89
 
92
90
  return null;
93
91
  }
@@ -104,7 +102,7 @@ class JoinBase {
104
102
  done,
105
103
  hasFailure,
106
104
  newBuild,
107
- jobName: nextJobName,
105
+ job: nextJob,
108
106
  pipelineId,
109
107
  isVirtualJob: isNextJobVirtual,
110
108
  stageName: nextJobStageName
@@ -12,14 +12,13 @@ class OrTrigger extends OrBase {
12
12
  * Trigger the next jobs of the current job
13
13
  * @param {Event} event
14
14
  * @param {Number} pipelineId
15
- * @param {String} nextJobName
16
- * @param {Number} nextJobId
15
+ * @param {Job} nextJob
17
16
  * @param {import('./helpers').ParentBuilds} parentBuilds
18
17
  * @param {Boolean} isNextJobVirtual
19
18
  * @return {Promise<Build|null>}
20
19
  */
21
- async execute(event, pipelineId, nextJobName, nextJobId, parentBuilds, isNextJobVirtual) {
22
- return this.trigger(event, pipelineId, nextJobName, nextJobId, parentBuilds, isNextJobVirtual);
20
+ async execute(event, pipelineId, nextJob, parentBuilds, isNextJobVirtual) {
21
+ return this.trigger(event, pipelineId, nextJob, parentBuilds, isNextJobVirtual);
23
22
  }
24
23
  }
25
24
 
@@ -36,25 +36,27 @@ class OrBase {
36
36
  * Trigger the next jobs of the current job
37
37
  * @param {Event} event
38
38
  * @param {Number} pipelineId
39
- * @param {String} nextJobName
40
- * @param {Number} nextJobId
39
+ * @param {Job} nextJob
41
40
  * @param {import('./helpers').ParentBuilds} parentBuilds
42
41
  * @param {Boolean} isNextJobVirtual
43
42
  * @return {Promise<Build|null>}
44
43
  */
45
- async trigger(event, pipelineId, nextJobName, nextJobId, parentBuilds, isNextJobVirtual) {
44
+ async trigger(event, pipelineId, nextJob, parentBuilds, isNextJobVirtual) {
46
45
  let nextBuild = await this.buildFactory.get({
47
46
  eventId: event.id,
48
- jobId: nextJobId
47
+ jobId: nextJob.id
49
48
  });
50
49
 
50
+ const hasFreezeWindows =
51
+ nextJob.permutations[0].freezeWindows && nextJob.permutations[0].freezeWindows.length > 0;
52
+
51
53
  if (nextBuild !== null) {
52
54
  if (Status.isStarted(nextBuild.status)) {
53
55
  return nextBuild;
54
56
  }
55
57
 
56
58
  // Bypass execution of the build if the job is virtual
57
- if (isNextJobVirtual) {
59
+ if (isNextJobVirtual && !hasFreezeWindows) {
58
60
  nextBuild.status = Status.SUCCESS;
59
61
 
60
62
  return nextBuild.update();
@@ -70,19 +72,19 @@ class OrBase {
70
72
  jobFactory: this.jobFactory,
71
73
  buildFactory: this.buildFactory,
72
74
  pipelineId,
73
- jobName: nextJobName,
74
- jobId: nextJobId,
75
+ jobName: nextJob.name,
76
+ jobId: nextJob.id,
75
77
  username: this.username,
76
78
  scmContext: this.scmContext,
77
79
  event,
78
80
  baseBranch: event.baseBranch || null,
79
81
  parentBuilds,
80
82
  parentBuildId: this.currentBuild.id,
81
- start: !isNextJobVirtual
83
+ start: hasFreezeWindows || !isNextJobVirtual
82
84
  });
83
85
 
84
86
  // Bypass execution of the build if the job is virtual
85
- if (isNextJobVirtual) {
87
+ if (isNextJobVirtual && !hasFreezeWindows) {
86
88
  nextBuild.status = Status.SUCCESS;
87
89
 
88
90
  nextBuild = nextBuild.update();
@@ -23,8 +23,7 @@ class RemoteJoin extends JoinBase {
23
23
  /**
24
24
  * Trigger the next external jobs of the current job
25
25
  * @param {Event} externalEvent Downstream pipeline's event
26
- * @param {String} nextJobName
27
- * @param {Number} nextJobId
26
+ * @param {Job} nextJob
28
27
  * @param {import('./helpers').ParentBuilds} parentBuilds
29
28
  * @param {Build[]} groupEventBuilds Builds of the downstream pipeline, where only the latest ones for each job are included that have the same groupEventId as the externalEvent
30
29
  * @param {String[]} joinListNames
@@ -34,8 +33,7 @@ class RemoteJoin extends JoinBase {
34
33
  */
35
34
  async execute(
36
35
  externalEvent,
37
- nextJobName,
38
- nextJobId,
36
+ nextJob,
39
37
  parentBuilds,
40
38
  groupEventBuilds,
41
39
  joinListNames,
@@ -43,7 +41,7 @@ class RemoteJoin extends JoinBase {
43
41
  nextJobStageName
44
42
  ) {
45
43
  // When restart case, should we create a new build ?
46
- const nextBuild = groupEventBuilds.find(b => b.jobId === nextJobId && b.eventId === externalEvent.id);
44
+ const nextBuild = groupEventBuilds.find(b => b.jobId === nextJob.id && b.eventId === externalEvent.id);
47
45
 
48
46
  const newParentBuilds = mergeParentBuilds(parentBuilds, groupEventBuilds, this.currentEvent, externalEvent);
49
47
 
@@ -58,8 +56,7 @@ class RemoteJoin extends JoinBase {
58
56
  pipelineId: externalEvent.pipelineId,
59
57
  event: externalEvent,
60
58
  nextBuild,
61
- nextJobName,
62
- nextJobId,
59
+ nextJob,
63
60
  parentBuilds: newParentBuilds,
64
61
  parentBuildId,
65
62
  joinListNames,
@@ -12,14 +12,13 @@ class RemoteTrigger extends OrBase {
12
12
  * Trigger the next jobs of the current job
13
13
  * @param {Event} event
14
14
  * @param {Number} pipelineId
15
- * @param {String} nextJobName
16
- * @param {String} nextJobId
15
+ * @param {Job} nextJob
17
16
  * @param {import('./helpers').ParentBuilds} parentBuilds
18
17
  * @param {Boolean} isNextJobVirtual
19
18
  * @returns {Promise<Build|null>}
20
19
  */
21
- async execute(event, pipelineId, nextJobName, nextJobId, parentBuilds, isNextJobVirtual) {
22
- return this.trigger(event, pipelineId, nextJobName, nextJobId, parentBuilds, isNextJobVirtual);
20
+ async execute(event, pipelineId, nextJob, parentBuilds, isNextJobVirtual) {
21
+ return this.trigger(event, pipelineId, nextJob, parentBuilds, isNextJobVirtual);
23
22
  }
24
23
  }
25
24