Skip to content

Commit

Permalink
feat(3143): Prevent event creation when started from a stage teardown (
Browse files Browse the repository at this point in the history
  • Loading branch information
ThehamzaIftikhar authored Jul 31, 2024
1 parent a324bbc commit f6aeb81
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 3 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@
"screwdriver-scm-github": "^12.6.0",
"screwdriver-scm-gitlab": "^3.1.0",
"screwdriver-scm-router": "^7.1.0",
"screwdriver-template-validator": "^8.0.0",
"screwdriver-template-validator": "^8.1.0",
"screwdriver-workflow-parser": "^4.1.1",
"sqlite3": "^5.1.4",
"stream": "0.0.2",
Expand Down
7 changes: 6 additions & 1 deletion plugins/events/create.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ const urlLib = require('url');
const boom = require('@hapi/boom');
const validationSchema = require('screwdriver-data-schema');
const ANNOT_RESTRICT_PR = 'screwdriver.cd/restrictPR';
const { getScmUri } = require('../helper');
const { getScmUri, isStageTeardown } = require('../helper');

module.exports = () => ({
method: 'POST',
Expand All @@ -29,6 +29,11 @@ module.exports = () => ({
let { pipelineId, startFrom, parentBuildId, parentBuilds, groupEventId, parentEventId, prNum } =
request.payload;

// Validation: Prevent event creation if startFrom is a stage teardown and parentEventID does not exist (start case)
if (isStageTeardown(startFrom) && !parentEventId) {
throw boom.badRequest('Event cannot be started from a stage teardown');
}

// restart case
if (buildId) {
const b = await buildFactory.get(buildId);
Expand Down
13 changes: 12 additions & 1 deletion plugins/helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
const boom = require('@hapi/boom');
const dayjs = require('dayjs');
const STAGE_PREFIX = 'stage@';
const STAGE_TEARDOWN_PATTERN = /^stage@([\w-]+):teardown$/;

/**
* Set default start time and end time
Expand Down Expand Up @@ -113,11 +114,21 @@ function getFullStageJobName({ stageName, jobName }) {
return `${STAGE_PREFIX}${stageName}:${jobName}`;
}

/**
* Check if the job is teardown job with teardown suffix
* @param {String} jobName Job name
* @return {Boolean}
*/
function isStageTeardown(jobName) {
return STAGE_TEARDOWN_PATTERN.test(jobName);
}

module.exports = {
getReadOnlyInfo,
getScmUri,
getUserPermissions,
setDefaultTimeRange,
validTimeRange,
getFullStageJobName
getFullStageJobName,
isStageTeardown
};
52 changes: 52 additions & 0 deletions test/plugins/events.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -632,6 +632,58 @@ describe('event plugin test', () => {
});
});

it('returns 400 bad request error when startFrom is stage teardown and parent event is not specified', () => {
options.payload.startFrom = 'stage@integration:teardown';

return server.inject(options).then(reply => {
assert.equal(reply.statusCode, 400);
});
});

it('returns 201 when it successfully creates an event with parent event and the startFrom is a stage teardown', () => {
eventConfig.parentEventId = parentEventId;
eventConfig.workflowGraph = getEventMock(testEvent).workflowGraph;
eventConfig.sha = getEventMock(testEvent).sha;
eventConfig.baseBranch = 'master';
eventConfig.startFrom = 'stage@integration:teardown';
options.payload.parentEventId = parentEventId;
options.payload.startFrom = 'stage@integration:teardown';

return server.inject(options).then(reply => {
expectedLocation = {
host: reply.request.headers.host,
port: reply.request.headers.port,
protocol: reply.request.server.info.protocol,
pathname: `${options.url}/12345`
};
assert.equal(reply.statusCode, 201);
assert.calledWith(eventFactoryMock.create, eventConfig);
assert.strictEqual(reply.headers.location, urlLib.format(expectedLocation));
assert.notCalled(eventFactoryMock.scm.getPrInfo);
});
});

it('returns 201 when it successfully creates an event with parent event and the startFrom is not a stage teardown', () => {
eventConfig.parentEventId = parentEventId;
eventConfig.workflowGraph = getEventMock(testEvent).workflowGraph;
eventConfig.sha = getEventMock(testEvent).sha;
eventConfig.baseBranch = 'master';
options.payload.parentEventId = parentEventId;

return server.inject(options).then(reply => {
expectedLocation = {
host: reply.request.headers.host,
port: reply.request.headers.port,
protocol: reply.request.server.info.protocol,
pathname: `${options.url}/12345`
};
assert.equal(reply.statusCode, 201);
assert.calledWith(eventFactoryMock.create, eventConfig);
assert.strictEqual(reply.headers.location, urlLib.format(expectedLocation));
assert.notCalled(eventFactoryMock.scm.getPrInfo);
});
});

it('returns 201 when it creates an event with parent event for child pipeline', () => {
eventConfig.parentEventId = parentEventId;
eventConfig.workflowGraph = getEventMock(testEvent).workflowGraph;
Expand Down

0 comments on commit f6aeb81

Please sign in to comment.