screwdriver-api 8.0.115 → 8.0.117

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": "8.0.115",
3
+ "version": "8.0.117",
4
4
  "description": "API server for the Screwdriver.cd service",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -139,6 +139,17 @@ function hasFreezeWindows(job) {
139
139
  return freezeWindows ? freezeWindows.length > 0 : false;
140
140
  }
141
141
 
142
+ /**
143
+ * Checks if job has blockedBy
144
+ * @param {Job} job Job object
145
+ * @returns {Boolean}
146
+ */
147
+ function hasBlockedBy(job) {
148
+ const { blockedBy } = job.permutations[0];
149
+
150
+ return blockedBy ? blockedBy.length > 0 : false;
151
+ }
152
+
142
153
  /**
143
154
  * Get external pipelineId and job name from the `name`
144
155
  * @param {String} name Job name
@@ -771,7 +782,7 @@ async function handleNewBuild({
771
782
  newBuild.parentBuildId = parentBuilds.map(build => build.id);
772
783
 
773
784
  // Bypass execution of the build if the job is virtual
774
- if (isVirtualJob && !hasFreezeWindows(job)) {
785
+ if (isVirtualJob && !hasFreezeWindows(job) && !hasBlockedBy(job)) {
775
786
  return updateVirtualBuildSuccess({ server, build: newBuild, event, job });
776
787
  }
777
788
 
@@ -1310,6 +1321,7 @@ module.exports = {
1310
1321
  trimJobName,
1311
1322
  isStartFromMiddleOfCurrentStage,
1312
1323
  hasFreezeWindows,
1324
+ hasBlockedBy,
1313
1325
  getNextJobStageName,
1314
1326
  updateVirtualBuildSuccess,
1315
1327
  BUILD_STATUS_MESSAGES
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- const { createInternalBuild, Status, updateVirtualBuildSuccess, hasFreezeWindows } = require('./helpers');
3
+ const { createInternalBuild, Status, updateVirtualBuildSuccess, hasFreezeWindows, hasBlockedBy } = require('./helpers');
4
4
 
5
5
  /**
6
6
  * @typedef {import('screwdriver-models').BuildFactory} BuildFactory
@@ -49,6 +49,7 @@ class OrBase {
49
49
  });
50
50
 
51
51
  const hasWindows = hasFreezeWindows(nextJob);
52
+ const hasBlocked = hasBlockedBy(nextJob);
52
53
  const causeMessage = nextJob.name === event.startFrom ? event.causeMessage : '';
53
54
 
54
55
  if (nextBuild !== null) {
@@ -59,7 +60,7 @@ class OrBase {
59
60
  nextBuild.parentBuildId = [this.currentBuild.id];
60
61
 
61
62
  // Bypass execution of the build if the job is virtual
62
- if (isNextJobVirtual && !hasWindows) {
63
+ if (isNextJobVirtual && !hasWindows && !hasBlocked) {
63
64
  return updateVirtualBuildSuccess({ server: this.server, build: nextBuild, event, job: nextJob });
64
65
  }
65
66
 
@@ -81,12 +82,12 @@ class OrBase {
81
82
  baseBranch: event.baseBranch || null,
82
83
  parentBuilds,
83
84
  parentBuildId: this.currentBuild.id,
84
- start: hasWindows || !isNextJobVirtual,
85
+ start: hasBlocked || hasWindows || !isNextJobVirtual,
85
86
  causeMessage
86
87
  });
87
88
 
88
89
  // Bypass execution of the build if the job is virtual
89
- if (isNextJobVirtual && !hasWindows) {
90
+ if (isNextJobVirtual && !hasWindows && !hasBlocked) {
90
91
  await updateVirtualBuildSuccess({ server: this.server, build: nextBuild, event, job: nextJob });
91
92
  }
92
93
 
@@ -21,7 +21,19 @@ function getVirtualJobIds(virtualNodeNames, prJobs) {
21
21
  const prJobName = prJob.name.match(PR_JOB_NAME);
22
22
  const nodeName = prJobName ? prJobName[2] : prJob.name;
23
23
 
24
+ // if prJob has blockedBy or freezeWindows annotation
25
+ // then it needs to be queued for scheduling
24
26
  if (virtualNodeNames.includes(nodeName)) {
27
+ const permutations = prJob.permutations || [];
28
+ const hasBlockedBy = permutations[0] && permutations[0].blockedBy;
29
+ const hasFreezeWindows = permutations[0] && permutations[0].freezeWindows;
30
+
31
+ const needsScheduling = Boolean(hasBlockedBy || hasFreezeWindows);
32
+
33
+ if (needsScheduling) {
34
+ return;
35
+ }
36
+
25
37
  virtualJobIds.push(prJob.id);
26
38
  }
27
39
  });
@@ -49,21 +49,24 @@ module.exports = () => ({
49
49
 
50
50
  // Check permissions
51
51
  let permissions;
52
+ const adminDetails = request.server.plugins.banners.screwdriverAdminDetails(
53
+ username,
54
+ scmContext,
55
+ scmUserId
56
+ );
52
57
 
53
58
  try {
54
59
  permissions = await user.getPermissions(pipeline.scmUri);
55
60
  } catch (err) {
56
- if (err.statusCode === 403 && pipeline.scmRepo && pipeline.scmRepo.private) {
57
- throw boom.notFound();
61
+ // Screwdriver admin can stop all events
62
+ if (!adminDetails.isAdmin) {
63
+ if (err.statusCode === 403 && pipeline.scmRepo && pipeline.scmRepo.private) {
64
+ throw boom.notFound();
65
+ }
66
+ throw boom.boomify(err, { statusCode: err.statusCode });
58
67
  }
59
- throw boom.boomify(err, { statusCode: err.statusCode });
60
68
  }
61
69
 
62
- const adminDetails = request.server.plugins.banners.screwdriverAdminDetails(
63
- username,
64
- scmContext,
65
- scmUserId
66
- );
67
70
  const isPrOwner = hoek.reach(event, 'commit.author.username') === username;
68
71
 
69
72
  // PR author should be able to stop their own PR event
package/plugins/helper.js CHANGED
@@ -48,13 +48,17 @@ async function getUserPermissions({ user, scmUri, level = 'admin', isAdmin = fal
48
48
  // Check if user has push access or is a Screwdriver admin
49
49
  let permissions;
50
50
 
51
+ if (isAdmin) {
52
+ return null;
53
+ }
54
+
51
55
  try {
52
56
  permissions = await user.getPermissions(scmUri);
53
57
  } catch (err) {
54
58
  permissions = null;
55
59
  }
56
60
 
57
- if (!permissions || (!permissions[level] && !isAdmin)) {
61
+ if (!permissions || !permissions[level]) {
58
62
  throw boom.forbidden(`User ${user.getFullDisplayName()} does not have ${level} permission for this repo`);
59
63
  }
60
64
 
@@ -21,7 +21,7 @@ module.exports = () => ({
21
21
  handler: async (request, h) => {
22
22
  const { jobFactory, pipelineFactory, userFactory } = request.server.app;
23
23
  const { id } = request.params;
24
- const { username, scmContext } = request.auth.credentials;
24
+ const { username, scmContext, scmUserId } = request.auth.credentials;
25
25
  const { isValidToken } = request.server.plugins.pipelines;
26
26
 
27
27
  const job = await jobFactory.get(id);
@@ -51,7 +51,13 @@ module.exports = () => ({
51
51
  const scmUri = await getScmUri({ pipeline, pipelineFactory });
52
52
 
53
53
  // Check the user's permission
54
- await getUserPermissions({ user, scmUri, level: 'push' });
54
+ const adminDetails = request.server.plugins.banners.screwdriverAdminDetails(
55
+ username,
56
+ scmContext,
57
+ scmUserId
58
+ );
59
+
60
+ await getUserPermissions({ user, scmUri, level: 'push', isAdmin: adminDetails.isAdmin });
55
61
 
56
62
  Object.keys(request.payload).forEach(key => {
57
63
  job[key] = request.payload[key];
@@ -32,16 +32,27 @@ module.exports = () => ({
32
32
  if (pipeline.state === 'DELETING') {
33
33
  throw boom.conflict('This pipeline is already being deleted.');
34
34
  }
35
- if (pipeline.configPipelineId && pipeline.state !== 'INACTIVE') {
36
- throw boom.forbidden(
37
- 'Child pipeline can only be removed' +
38
- ` after removing it from scmUrls in config pipeline ${pipeline.configPipelineId}`
39
- );
40
- }
41
35
  if (!user) {
42
36
  throw boom.notFound(`User ${username} does not exist`);
43
37
  }
44
38
 
39
+ const scmDisplayName = bannerFactory.scm.getDisplayName({ scmContext });
40
+ // Lookup whether user is admin
41
+ const adminDetails = request.server.plugins.banners.screwdriverAdminDetails(
42
+ username,
43
+ scmDisplayName,
44
+ scmUserId
45
+ );
46
+
47
+ if (pipeline.configPipelineId && pipeline.state !== 'INACTIVE') {
48
+ if (!adminDetails.isAdmin) {
49
+ throw boom.forbidden(
50
+ 'Child pipeline can only be removed' +
51
+ ` after removing it from scmUrls in config pipeline ${pipeline.configPipelineId}`
52
+ );
53
+ }
54
+ }
55
+
45
56
  // ask the user for permissions on this repo
46
57
  return (
47
58
  user
@@ -55,14 +66,6 @@ module.exports = () => ({
55
66
  }
56
67
  })
57
68
  .catch(error => {
58
- const scmDisplayName = bannerFactory.scm.getDisplayName({ scmContext });
59
- // Lookup whether user is admin
60
- const adminDetails = request.server.plugins.banners.screwdriverAdminDetails(
61
- username,
62
- scmDisplayName,
63
- scmUserId
64
- );
65
-
66
69
  // Allow cluster admins to remove pipeline
67
70
  if (adminDetails.isAdmin) {
68
71
  return Promise.resolve(null);