Skip to content

Commit 2bf13ed

Browse files
authoredNov 28, 2023
feat(2135): New endpoint to create and validate pipeline template configuration (#2958)
1 parent ad11430 commit 2bf13ed

13 files changed

+401
-4
lines changed
 

‎bin/server

+12
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,16 @@ const buildClusterFactory = Models.BuildClusterFactory.getInstance({
229229
datastoreRO,
230230
scm
231231
});
232+
const pipelineTemplateFactory = Models.PipelineTemplateFactory.getInstance({
233+
datastore,
234+
datastoreRO,
235+
scm
236+
});
237+
const pipelineTemplateVersionFactory = Models.PipelineTemplateVersionFactory.getInstance({
238+
datastore,
239+
datastoreRO,
240+
scm
241+
});
232242

233243
// @TODO run setup for SCM and Executor
234244
// datastoreConfig.ddlSync => sync datastore schema (ddl) via api (default: true)
@@ -250,6 +260,8 @@ datastore.setup(datastoreConfig.ddlSyncEnabled).then(() =>
250260
userFactory,
251261
buildFactory,
252262
buildClusterFactory,
263+
pipelineTemplateFactory,
264+
pipelineTemplateVersionFactory,
253265
stepFactory,
254266
bannerFactory,
255267
secretFactory,

‎lib/server.js

+5
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,11 @@ module.exports = async config => {
126126
commandTagFactory: config.commandTagFactory,
127127
templateFactory: config.templateFactory,
128128
templateTagFactory: config.templateTagFactory,
129+
pipelineTemplateFactory: config.pipelineTemplateFactory,
130+
pipelineTemplateVersionFactory: config.pipelineTemplateVersionFactory,
131+
templateMetaFactory: config.templateMetaFactory,
132+
jobTemplateTagFactory: config.jobTemplateTagFactory,
133+
pipelineTemplateTagFactory: config.pipelineTemplateTagFactory,
129134
stageFactory: config.stageFactory,
130135
stageBuildFactory: config.stageBuildFactory,
131136
triggerFactory: config.triggerFactory,

‎package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@
123123
"screwdriver-scm-github": "^12.1.1",
124124
"screwdriver-scm-gitlab": "^3.1.0",
125125
"screwdriver-scm-router": "^7.0.0",
126-
"screwdriver-template-validator": "^6.0.0",
126+
"screwdriver-template-validator": "^7.0.0",
127127
"screwdriver-workflow-parser": "^4.1.1",
128128
"sqlite3": "^5.1.4",
129129
"stream": "0.0.2",

‎plugins/pipelines/index.js

+5-1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ const latestCommitEvent = require('./latestCommitEvent');
2929
const getAdmin = require('./admins/get');
3030
const deleteCache = require('./caches/delete');
3131
const openPrRoute = require('./openPr');
32+
const createTemplate = require('./templates/create');
33+
const validateTemplate = require('./templates/validate');
3234

3335
/**
3436
* Pipeline API Plugin
@@ -195,7 +197,9 @@ const pipelinesPlugin = {
195197
latestCommitEvent(),
196198
getAdmin(),
197199
deleteCache(),
198-
openPrRoute()
200+
openPrRoute(),
201+
createTemplate(),
202+
validateTemplate()
199203
]);
200204
}
201205
};

‎plugins/pipelines/templates/create.js

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
'use strict';
2+
3+
const boom = require('@hapi/boom');
4+
const schema = require('screwdriver-data-schema');
5+
const validator = require('screwdriver-template-validator').parsePipelineTemplate;
6+
const templateSchema = schema.api.templateValidator;
7+
8+
module.exports = () => ({
9+
method: 'POST',
10+
path: '/pipeline/template',
11+
options: {
12+
description: 'Create a new pipeline template',
13+
notes: 'Create a specific pipeline template',
14+
tags: ['api', 'pipelineTemplate'],
15+
auth: {
16+
strategies: ['token'],
17+
scope: ['build']
18+
},
19+
20+
handler: async (request, h) => {
21+
const { pipelineTemplateVersionFactory, pipelineTemplateFactory } = request.server.app;
22+
23+
const config = await validator(request.payload.yaml);
24+
25+
if (config.errors.length > 0) {
26+
throw boom.badRequest(`Template has invalid format: ${config.errors.length} error(s).`, config.errors);
27+
}
28+
29+
const pipelineTemplate = await pipelineTemplateFactory.get({
30+
name: config.template.name,
31+
namespace: config.template.namespace
32+
});
33+
34+
const { isPR, pipelineId } = request.auth.credentials;
35+
36+
// If template name exists, but this build's pipelineId is not the same as template's pipelineId
37+
// Then this build does not have permission to publish
38+
if (isPR || (pipelineTemplate && pipelineId !== pipelineTemplate.pipelineId)) {
39+
throw boom.forbidden('Not allowed to publish this template');
40+
}
41+
42+
const template = await pipelineTemplateVersionFactory.create(
43+
{
44+
...config.template,
45+
pipelineId
46+
},
47+
pipelineTemplateFactory
48+
);
49+
50+
const location = new URL(
51+
`${request.path}/${template.id}`,
52+
`${request.server.info.protocol}://${request.headers.host}`
53+
).toString();
54+
55+
return h.response(template.toJson()).header('Location', location).code(201);
56+
},
57+
validate: {
58+
payload: templateSchema.input
59+
}
60+
}
61+
});
+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
'use strict';
2+
3+
const boom = require('@hapi/boom');
4+
const schema = require('screwdriver-data-schema');
5+
const templateSchema = schema.api.templateValidator;
6+
const pipelineValidator = require('screwdriver-template-validator').parsePipelineTemplate;
7+
8+
module.exports = () => ({
9+
method: 'POST',
10+
path: '/pipeline/template/validate',
11+
options: {
12+
description: 'Validate a given sd-template.yaml',
13+
notes: 'returns the parsed config, validation errors, or both',
14+
tags: ['api', 'validation', 'yaml'],
15+
auth: {
16+
strategies: ['token'],
17+
scope: ['user', 'pipeline']
18+
},
19+
20+
handler: async (request, h) => {
21+
try {
22+
const { yaml: templateString } = request.payload;
23+
24+
const result = await pipelineValidator(templateString);
25+
26+
return h.response(result);
27+
} catch (err) {
28+
throw boom.badRequest(err.toString());
29+
}
30+
},
31+
validate: {
32+
payload: templateSchema.input
33+
},
34+
response: {
35+
schema: templateSchema.output
36+
}
37+
}
38+
});

‎plugins/template-validator.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
const boom = require('@hapi/boom');
44
const schema = require('screwdriver-data-schema');
55
const templateSchema = schema.api.templateValidator;
6-
const validator = require('screwdriver-template-validator');
6+
const validator = require('screwdriver-template-validator').parseJobTemplate;
77

88
/**
99
* Hapi Template Validator Plugin

‎plugins/templates/create.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
const urlLib = require('url');
44
const boom = require('@hapi/boom');
55
const schema = require('screwdriver-data-schema');
6-
const validator = require('screwdriver-template-validator');
6+
const validator = require('screwdriver-template-validator').parseJobTemplate;
77
const templateSchema = schema.api.templateValidator;
88
const hoek = require('@hapi/hoek');
99

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"yaml": "{ \"namespace\": \"template_namespace\", \"name\": \"template_name\", \"version\": \"1.2\", \"description\": \"template description\", \"maintainer\": \"name@domain.org\", \"config\": { \"jobs\": { \"main\": { \"steps\": [ { \"init\": \"npm install\" }, { \"test\": \"npm test\" } ] } } } }"
3+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"yaml": "{ \"namespace\": \"template_namespace\", \"name\": \"template_name\", \"version\": \"1.2.3\", \"description\": \"template description\", \"maintainer\": \"name@domain.org\", \"config\": { \"jobs\": { \"main\": { \"steps\": [ { \"init\": \"npm install\" }, { \"test\": \"npm test\" } ] } } } }"
3+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"yaml": "{ \"namespace\": \"template_namespace\", \"name\": \"template_name\", \"description\": \"template description\", \"maintainer\": \"name@domain.org\", \"config\": { \"jobs\": { \"main\": { \"steps\": [ { \"init\": \"npm install\" }, { \"test\": \"npm test\" } ] } } } }"
3+
}
+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"id": 123,
3+
"pipelineId": 123,
4+
"namespace": "my-namespace",
5+
"name": "example-template",
6+
"description": "An example template",
7+
"maintainer": "example@gmail.com",
8+
"trustedSinceVersion": "1.3.2",
9+
"latestVersion": "1.3.2",
10+
"createTime": "2023-06-12T21:52:22.706Z",
11+
"updateTime": "2023-06-29T11:23:45.706Z"
12+
}
13+

0 commit comments

Comments
 (0)
Please sign in to comment.