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 +1 -1
- package/plugins/builds/triggers/helpers.js +13 -1
- package/plugins/builds/triggers/orBase.js +5 -4
- package/plugins/events/helper/createEvent.js +12 -0
- package/plugins/events/stopBuilds.js +11 -8
- package/plugins/helper.js +5 -1
- package/plugins/jobs/update.js +8 -2
- package/plugins/pipelines/remove.js +17 -14
package/package.json
CHANGED
|
@@ -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
|
-
|
|
57
|
-
|
|
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 ||
|
|
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
|
|
package/plugins/jobs/update.js
CHANGED
|
@@ -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
|
-
|
|
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);
|