screwdriver-api
Version:
API server for the Screwdriver.cd service
118 lines (100 loc) • 4.21 kB
JavaScript
;
const urlLib = require('url');
const boom = require('@hapi/boom');
const hoek = require('@hapi/hoek');
const joi = require('joi');
const schema = require('screwdriver-data-schema');
const getSchema = schema.models.event.get;
const idSchema = schema.models.event.base.extract('id');
module.exports = () => ({
method: 'PUT',
path: '/events/{id}/stop',
options: {
description: 'Stop all builds in an event',
notes: 'Stop all builds in a specific event',
tags: ['api', 'events'],
auth: {
strategies: ['token'],
scope: ['user', '!guest', 'pipeline']
},
handler: async (request, h) => {
const { eventFactory, pipelineFactory, userFactory } = request.server.app;
const { username, scmContext, scmUserId } = request.auth.credentials;
const { isValidToken } = request.server.plugins.pipelines;
const eventId = request.params.id;
const { updateAdmins } = request.server.plugins.events;
const event = await eventFactory.get(eventId);
// Check if event exists
if (!event) {
throw boom.notFound(`Event ${eventId} does not exist`);
}
// Fetch the pipeline and user models
const [pipeline, user] = await Promise.all([
pipelineFactory.get(event.pipelineId),
userFactory.get({ username, scmContext })
]);
// In pipeline scope, check if the token is allowed to the pipeline
if (!isValidToken(pipeline.id, request.auth.credentials)) {
throw boom.unauthorized('Token does not have permission to this pipeline');
}
// Check permissions
let permissions;
try {
permissions = await user.getPermissions(pipeline.scmUri);
} catch (err) {
if (err.statusCode === 403 && pipeline.scmRepo && pipeline.scmRepo.private) {
throw boom.notFound();
}
throw boom.boomify(err, { statusCode: err.statusCode });
}
const adminDetails = request.server.plugins.banners.screwdriverAdminDetails(
username,
scmContext,
scmUserId
);
const isPrOwner = hoek.reach(event, 'commit.author.username') === username;
// PR author should be able to stop their own PR event
// Screwdriver admin can also stop events
if (!((event.prNum && isPrOwner) || adminDetails.isAdmin)) {
// Check permissions and update user in admins list
await updateAdmins({
permissions,
pipeline,
username
});
}
// User has good permissions, get event builds
const builds = await event.getBuilds();
const toUpdate = [];
// Update endtime and stop running builds
// Note: COLLAPSED builds will never run
builds.forEach(b => {
if (['CREATED', 'RUNNING', 'QUEUED', 'BLOCKED', 'FROZEN'].includes(b.status)) {
if (b.status === 'RUNNING') {
b.endTime = new Date().toISOString();
}
b.status = 'ABORTED';
b.statusMessage = `Aborted by ${username}`;
toUpdate.push(b.update());
}
});
await Promise.all(toUpdate);
// everything succeeded, inform the user
const location = urlLib.format({
host: request.headers.host,
port: request.headers.port,
protocol: request.server.info.protocol,
pathname: `${request.path}/${event.id}`
});
return h.response(event.toJson()).header('Location', location).code(200);
},
response: {
schema: getSchema
},
validate: {
params: joi.object({
id: idSchema
})
}
}
});