screwdriver-api 7.0.176 → 7.0.178

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.176",
3
+ "version": "7.0.178",
4
4
  "description": "API server for the Screwdriver.cd service",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -26,7 +26,7 @@ const {
26
26
  createJoinObject,
27
27
  createEvent,
28
28
  parseJobInfo,
29
- handleStageFailure,
29
+ ensureStageTeardownBuildExists,
30
30
  getJobId,
31
31
  isOrTrigger,
32
32
  extractExternalJoinData,
@@ -39,6 +39,7 @@ const {
39
39
  isStartFromMiddleOfCurrentStage,
40
40
  Status
41
41
  } = require('./triggers/helpers');
42
+ const { getFullStageJobName } = require('../helper');
42
43
 
43
44
  /**
44
45
  * Delete a build
@@ -320,6 +321,70 @@ async function triggerNextJobs(config, app) {
320
321
  return null;
321
322
  }
322
323
 
324
+ /**
325
+ * Create or update stage teardown build
326
+ * @method createOrUpdateStageTeardownBuild
327
+ * @param {Object} config Configuration object
328
+ * @param {Pipeline} config.pipeline Current pipeline
329
+ * @param {Job} config.job Current job
330
+ * @param {Build} config.build Current build
331
+ * @param {Build} config.event Current event
332
+ * @param {Build} config.stage Current stage
333
+ * @param {String} config.username Username
334
+ * @param {String} config.scmContext SCM context
335
+ * @param {String} app Server app object
336
+ * @return {Promise} Create a new build or update an existing build
337
+ */
338
+ async function createOrUpdateStageTeardownBuild(config, app) {
339
+ const { pipeline, job, build, username, scmContext, event, stage } = config;
340
+ const { buildFactory, jobFactory, eventFactory } = app;
341
+ const current = {
342
+ pipeline,
343
+ job,
344
+ build,
345
+ event,
346
+ stage
347
+ };
348
+
349
+ const stageTeardownName = getFullStageJobName({ stageName: current.stage.name, jobName: 'teardown' });
350
+
351
+ const nextJobsTrigger = [stageTeardownName];
352
+ const pipelineJoinData = await createJoinObject(nextJobsTrigger, current, eventFactory);
353
+
354
+ const resource = `pipeline:${pipeline.id}:groupEvent:${event.groupEventId}`;
355
+ let lock;
356
+ let teardownBuild;
357
+
358
+ try {
359
+ lock = await locker.lock(resource);
360
+ const { parentBuilds } = parseJobInfo({
361
+ joinObj: pipelineJoinData,
362
+ currentBuild: build,
363
+ currentPipeline: pipeline,
364
+ currentJob: job,
365
+ nextJobName: stageTeardownName
366
+ });
367
+
368
+ teardownBuild = await ensureStageTeardownBuildExists({
369
+ jobFactory,
370
+ buildFactory,
371
+ current,
372
+ parentBuilds,
373
+ stageTeardownName,
374
+ username,
375
+ scmContext
376
+ });
377
+ } catch (err) {
378
+ logger.error(
379
+ `Error in createOrUpdateStageTeardownBuild:${stageTeardownName} from pipeline:${pipeline.id}-event:${event.id} `,
380
+ err
381
+ );
382
+ }
383
+ await locker.unlock(lock, resource);
384
+
385
+ return teardownBuild;
386
+ }
387
+
323
388
  /**
324
389
  * Build API Plugin
325
390
  * @method register
@@ -338,13 +403,12 @@ const buildsPlugin = {
338
403
  * @param {Pipeline} config.pipeline Current pipeline
339
404
  * @param {Job} config.job Current job
340
405
  * @param {Build} config.build Current build
341
- * @param {String} config.username Username
342
406
  * @param {String} app Server app object
343
407
  * @return {Promise} Resolves to the removed build or null
344
408
  */
345
409
  server.expose('removeJoinBuilds', async (config, app) => {
346
- const { pipeline, job, build, username, scmContext, event, stage } = config;
347
- const { eventFactory, buildFactory, jobFactory } = app;
410
+ const { pipeline, job, build, event, stage } = config;
411
+ const { eventFactory, buildFactory } = app;
348
412
  const current = {
349
413
  pipeline,
350
414
  job,
@@ -374,20 +438,19 @@ const buildsPlugin = {
374
438
  buildConfig.eventId = hoek.reach(pipelineJoinData[pid], 'event.id');
375
439
  }
376
440
 
377
- // if nextBuild is stage teardown, just return nextBuild
378
- if (current.stage) {
379
- const buildDeletePromises = await handleStageFailure({
380
- nextJobName,
381
- current,
382
- buildConfig,
383
- jobFactory,
384
- buildFactory,
385
- username,
386
- scmContext
387
- });
388
-
389
- deletePromises.concat(buildDeletePromises);
390
- } else if (buildConfig.eventId) {
441
+ if (buildConfig.eventId) {
442
+ if (current.stage) {
443
+ const stageTeardownName = getFullStageJobName({
444
+ stageName: current.stage.name,
445
+ jobName: 'teardown'
446
+ });
447
+
448
+ // Do not remove stage teardown builds as they need to be executed on stage failure as well.
449
+ if (nextJobName !== stageTeardownName) {
450
+ deletePromises.push(deleteBuild(buildConfig, buildFactory));
451
+ }
452
+ }
453
+
391
454
  deletePromises.push(deleteBuild(buildConfig, buildFactory));
392
455
  }
393
456
  } catch (err) {
@@ -425,6 +488,11 @@ const buildsPlugin = {
425
488
  */
426
489
  server.expose('triggerNextJobs', triggerNextJobs);
427
490
 
491
+ /**
492
+ * Create or Update stage teardown build on stage failure
493
+ */
494
+ server.expose('createOrUpdateStageTeardownBuild', createOrUpdateStageTeardownBuild);
495
+
428
496
  server.route([
429
497
  getRoute(),
430
498
  getBuildStatusesRoute(),
@@ -834,6 +834,7 @@ async function createJoinObject(nextJobNames, current, eventFactory) {
834
834
  * @param {BuildFactory} arg.buildFactory Build factory
835
835
  * @param {Object} arg.current Current object
836
836
  * @param {Event} arg.current.event Current event
837
+ * @param {ParentBuilds} arg.parentBuilds Parent builds
837
838
  * @param {String} arg.stageTeardownName Stage teardown name
838
839
  * @param {String} arg.username Username
839
840
  * @param {String} arg.scmContext SCM context
@@ -842,6 +843,7 @@ async function ensureStageTeardownBuildExists({
842
843
  jobFactory,
843
844
  buildFactory,
844
845
  current,
846
+ parentBuilds,
845
847
  stageTeardownName,
846
848
  username,
847
849
  scmContext
@@ -865,54 +867,21 @@ async function ensureStageTeardownBuildExists({
865
867
  jobName: stageTeardownName,
866
868
  username,
867
869
  scmContext,
870
+ parentBuilds,
871
+ parentBuildId: current.build.id,
868
872
  event: current.event, // this is the parentBuild for the next build
869
873
  baseBranch: current.event.baseBranch || null,
870
874
  start: false
871
875
  });
876
+ } else {
877
+ await updateParentBuilds({
878
+ joinParentBuilds: parentBuilds,
879
+ nextBuild: existingStageTeardownBuild,
880
+ build: current.build
881
+ });
872
882
  }
873
883
  }
874
884
 
875
- /**
876
- * Delete nextBuild, create teardown build if it doesn't exist, and return teardown build or return null
877
- * @param {Object} arg
878
- * @param {String} arg.nextJobName Next job name
879
- * @param {Object} arg.current Object with stage, event, pipeline info
880
- * @param {Object} arg.buildConfig Build config
881
- * @param {JobFactory} arg.jobFactory Job factory
882
- * @param {BuildFactory} arg.buildFactory Build factory
883
- * @param {String} arg.username Username
884
- * @param {String} arg.scmContext Scm context
885
- * @returns {Promise<Array>} Array of promises
886
- */
887
- async function handleStageFailure({
888
- nextJobName,
889
- current,
890
- buildConfig,
891
- jobFactory,
892
- buildFactory,
893
- username,
894
- scmContext
895
- }) {
896
- const buildDeletePromises = [];
897
- const stageTeardownName = getFullStageJobName({ stageName: current.stage.name, jobName: 'teardown' });
898
-
899
- // Remove next build
900
- if (buildConfig.eventId && nextJobName !== stageTeardownName) {
901
- buildDeletePromises.push(deleteBuild(buildConfig, buildFactory));
902
- }
903
-
904
- await ensureStageTeardownBuildExists({
905
- jobFactory,
906
- buildFactory,
907
- current,
908
- stageTeardownName,
909
- username,
910
- scmContext
911
- });
912
-
913
- return buildDeletePromises;
914
- }
915
-
916
885
  /**
917
886
  * Get parentBuildId from parentBuilds object
918
887
  * @param {Object} arg
@@ -1107,7 +1076,7 @@ module.exports = {
1107
1076
  updateParentBuilds,
1108
1077
  getParentBuildStatus,
1109
1078
  handleNewBuild,
1110
- handleStageFailure,
1079
+ ensureStageTeardownBuildExists,
1111
1080
  getBuildsForGroupEvent,
1112
1081
  createJoinObject,
1113
1082
  createExternalEvent,
@@ -221,7 +221,8 @@ module.exports = () => ({
221
221
  const { statusMessage, stats, status: desiredStatus } = request.payload;
222
222
  const { username, scmContext, scope } = request.auth.credentials;
223
223
  const isBuild = scope.includes('build') || scope.includes('temporal');
224
- const { triggerNextJobs, removeJoinBuilds } = request.server.plugins.builds;
224
+ const { triggerNextJobs, removeJoinBuilds, createOrUpdateStageTeardownBuild } =
225
+ request.server.plugins.builds;
225
226
 
226
227
  // Check token permissions
227
228
  if (isBuild && username !== id) {
@@ -326,16 +327,20 @@ module.exports = () => ({
326
327
  // Check for failed jobs and remove any child jobs in created state
327
328
  if (newBuild.status === 'FAILURE') {
328
329
  await removeJoinBuilds(
329
- { pipeline, job, build: newBuild, username, scmContext, event: newEvent, stage },
330
+ { pipeline, job, build: newBuild, event: newEvent, stage },
330
331
  request.server.app
331
332
  );
333
+
334
+ if (stage && !isStageTeardown) {
335
+ await createOrUpdateStageTeardownBuild(
336
+ { pipeline, job, build, username, scmContext, event, stage },
337
+ request.server.app
338
+ );
339
+ }
332
340
  }
333
341
  // Do not continue downstream is current job is stage teardown and statusBuild has failure
334
342
  } else if (newBuild.status === 'SUCCESS' && isStageTeardown && stageBuildHasFailure) {
335
- await removeJoinBuilds(
336
- { pipeline, job, build: newBuild, username, scmContext, event: newEvent, stage },
337
- request.server.app
338
- );
343
+ await removeJoinBuilds({ pipeline, job, build: newBuild, event: newEvent, stage }, request.server.app);
339
344
  } else {
340
345
  await triggerNextJobs(
341
346
  { pipeline, job, build: newBuild, username, scmContext, event: newEvent },