screwdriver-api 7.0.24 → 7.0.26

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/bin/server CHANGED
@@ -216,6 +216,10 @@ const stageFactory = Models.StageFactory.getInstance({
216
216
  datastore,
217
217
  datastoreRO
218
218
  });
219
+ const stageBuildFactory = Models.StageBuildFactory.getInstance({
220
+ datastore,
221
+ datastoreRO
222
+ });
219
223
  const triggerFactory = Models.TriggerFactory.getInstance({
220
224
  datastore,
221
225
  datastoreRO
@@ -225,6 +229,16 @@ const buildClusterFactory = Models.BuildClusterFactory.getInstance({
225
229
  datastoreRO,
226
230
  scm
227
231
  });
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
+ });
228
242
 
229
243
  // @TODO run setup for SCM and Executor
230
244
  // datastoreConfig.ddlSync => sync datastore schema (ddl) via api (default: true)
@@ -246,6 +260,8 @@ datastore.setup(datastoreConfig.ddlSyncEnabled).then(() =>
246
260
  userFactory,
247
261
  buildFactory,
248
262
  buildClusterFactory,
263
+ pipelineTemplateFactory,
264
+ pipelineTemplateVersionFactory,
249
265
  stepFactory,
250
266
  bannerFactory,
251
267
  secretFactory,
@@ -253,6 +269,7 @@ datastore.setup(datastoreConfig.ddlSyncEnabled).then(() =>
253
269
  eventFactory,
254
270
  collectionFactory,
255
271
  stageFactory,
272
+ stageBuildFactory,
256
273
  triggerFactory,
257
274
  banners: authConfig,
258
275
  builds: {
@@ -315,6 +315,7 @@ bookends:
315
315
  - screwdriver-cache-bookend
316
316
  teardown:
317
317
  - screwdriver-artifact-bookend
318
+ - screwdriver-coverage-bookend
318
319
  - screwdriver-cache-bookend
319
320
 
320
321
  notifications:
package/lib/server.js CHANGED
@@ -75,6 +75,7 @@ function prettyPrintErrors(request, h) {
75
75
  * @param {Factory} config.eventFactory Event Factory instance
76
76
  * @param {Factory} config.collectionFactory Collection Factory instance
77
77
  * @param {Factory} config.stageFactory Stage Factory instance
78
+ * @param {Factory} config.stageBuildFactory Stage Build Factory instance
78
79
  * @param {Factory} config.triggerFactory Trigger Factory instance
79
80
  * @param {Object} config.builds Config to include for builds plugin
80
81
  * @param {Object} config.builds.ecosystem List of hosts in the ecosystem
@@ -125,7 +126,13 @@ module.exports = async config => {
125
126
  commandTagFactory: config.commandTagFactory,
126
127
  templateFactory: config.templateFactory,
127
128
  templateTagFactory: config.templateTagFactory,
129
+ pipelineTemplateFactory: config.pipelineTemplateFactory,
130
+ pipelineTemplateVersionFactory: config.pipelineTemplateVersionFactory,
131
+ templateMetaFactory: config.templateMetaFactory,
132
+ jobTemplateTagFactory: config.jobTemplateTagFactory,
133
+ pipelineTemplateTagFactory: config.pipelineTemplateTagFactory,
128
134
  stageFactory: config.stageFactory,
135
+ stageBuildFactory: config.stageBuildFactory,
129
136
  triggerFactory: config.triggerFactory,
130
137
  pipelineFactory: config.pipelineFactory,
131
138
  jobFactory: config.jobFactory,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "screwdriver-api",
3
- "version": "7.0.24",
3
+ "version": "7.0.26",
4
4
  "description": "API server for the Screwdriver.cd service",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -114,7 +114,7 @@
114
114
  "screwdriver-executor-queue": "^4.0.0",
115
115
  "screwdriver-executor-router": "^3.0.0",
116
116
  "screwdriver-logger": "^2.0.0",
117
- "screwdriver-models": "^29.7.0",
117
+ "screwdriver-models": "^29.11.0",
118
118
  "screwdriver-notifications-email": "^3.0.0",
119
119
  "screwdriver-notifications-slack": "^5.0.0",
120
120
  "screwdriver-request": "^2.0.1",
@@ -123,7 +123,7 @@
123
123
  "screwdriver-scm-github": "^12.1.1",
124
124
  "screwdriver-scm-gitlab": "^3.1.0",
125
125
  "screwdriver-scm-router": "^7.0.0",
126
- "screwdriver-template-validator": "^6.0.0",
126
+ "screwdriver-template-validator": "^7.0.0",
127
127
  "screwdriver-workflow-parser": "^4.1.1",
128
128
  "sqlite3": "^5.1.4",
129
129
  "stream": "0.0.2",
@@ -4,6 +4,7 @@ const boom = require('@hapi/boom');
4
4
  const createRoute = require('./create');
5
5
  const getRoute = require('./get');
6
6
  const listBuildsRoute = require('./listBuilds');
7
+ const listStageBuildsRoute = require('./listStageBuilds');
7
8
  const stopBuildsRoute = require('./stopBuilds');
8
9
  const metricsRoute = require('./metrics');
9
10
 
@@ -51,7 +52,14 @@ const eventsPlugin = {
51
52
  return Promise.resolve();
52
53
  });
53
54
 
54
- server.route([createRoute(), getRoute(), listBuildsRoute(), stopBuildsRoute(), metricsRoute()]);
55
+ server.route([
56
+ createRoute(),
57
+ getRoute(),
58
+ listBuildsRoute(),
59
+ listStageBuildsRoute(),
60
+ stopBuildsRoute(),
61
+ metricsRoute()
62
+ ]);
55
63
  }
56
64
  };
57
65
 
@@ -0,0 +1,45 @@
1
+ 'use strict';
2
+
3
+ const boom = require('@hapi/boom');
4
+ const joi = require('joi');
5
+ const schema = require('screwdriver-data-schema');
6
+ const stageBuildListSchema = joi.array().items(schema.models.stageBuild.get).label('List of stage builds');
7
+ const eventIdSchema = schema.models.event.base.extract('id');
8
+
9
+ module.exports = () => ({
10
+ method: 'GET',
11
+ path: '/events/{id}/stageBuilds',
12
+ options: {
13
+ description: 'Get stage builds for a given event',
14
+ notes: 'Returns stage builds for a given event',
15
+ tags: ['api', 'events', 'stageBuilds'],
16
+ auth: {
17
+ strategies: ['token'],
18
+ scope: ['user', 'pipeline']
19
+ },
20
+
21
+ handler: async (request, h) => {
22
+ const { eventFactory } = request.server.app;
23
+ const event = await eventFactory.get(request.params.id);
24
+
25
+ if (!event) {
26
+ throw boom.notFound('Event does not exist');
27
+ }
28
+
29
+ return event
30
+ .getStageBuilds()
31
+ .then(stageBuilds => h.response(stageBuilds.map(c => c.toJson())))
32
+ .catch(err => {
33
+ throw err;
34
+ });
35
+ },
36
+ response: {
37
+ schema: stageBuildListSchema
38
+ },
39
+ validate: {
40
+ params: joi.object({
41
+ id: eventIdSchema
42
+ })
43
+ }
44
+ }
45
+ });
@@ -121,9 +121,6 @@ Only PR events of specified PR number will be searched when `prNum` is set
121
121
  #### Get all stages for a single pipeline
122
122
 
123
123
  `GET /pipelines/{id}/stages`
124
- Will get latest commit event's stages if no event ID or group event ID is provided
125
-
126
- `GET /pipelines/{id}/stages?groupEventId={groupEventId}`
127
124
 
128
125
  `GET /pipelines/{id}/stages?eventId={eventId}`
129
126
 
@@ -29,6 +29,8 @@ const latestCommitEvent = require('./latestCommitEvent');
29
29
  const getAdmin = require('./admins/get');
30
30
  const deleteCache = require('./caches/delete');
31
31
  const openPrRoute = require('./openPr');
32
+ const createTemplate = require('./templates/create');
33
+ const validateTemplate = require('./templates/validate');
32
34
 
33
35
  /**
34
36
  * Pipeline API Plugin
@@ -195,7 +197,9 @@ const pipelinesPlugin = {
195
197
  latestCommitEvent(),
196
198
  getAdmin(),
197
199
  deleteCache(),
198
- openPrRoute()
200
+ openPrRoute(),
201
+ createTemplate(),
202
+ validateTemplate()
199
203
  ]);
200
204
  }
201
205
  };
@@ -49,8 +49,6 @@ module.exports = () => ({
49
49
  throw boom.notFound(`Latest event does not exist for pipeline ${pipelineId}`);
50
50
  }
51
51
 
52
- config.params.eventId = latestCommitEvents[0].id;
53
-
54
52
  return stageFactory.list(config);
55
53
  })
56
54
  .then(stages => h.response(stages.map(s => s.toJson())))
@@ -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
+ });
@@ -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
+ });
@@ -0,0 +1,32 @@
1
+ # Stages Plugin
2
+ > API stages plugin for the Screwdriver API
3
+
4
+ ## Usage
5
+
6
+ ### Register plugin
7
+
8
+ ```javascript
9
+ const Hapi = require('@hapi/hapi');
10
+ const server = new Hapi.Server();
11
+ const stagesPlugin = require('./');
12
+
13
+ server.connection({ port: 3000 });
14
+
15
+ server.register({
16
+ register: stagesPlugin,
17
+ options: {}
18
+ }, () => {
19
+ server.start((err) => {
20
+ if (err) {
21
+ throw err;
22
+ }
23
+ console.log('Server running at:', server.info.uri);
24
+ });
25
+ });
26
+ ```
27
+
28
+ ### Routes
29
+
30
+ #### Get a listing of all stage builds for a stage
31
+
32
+ `GET /stages/{id}/stageBuilds`
@@ -0,0 +1,19 @@
1
+ 'use strict';
2
+
3
+ const getStageBuildsRoute = require('./stageBuilds/list');
4
+
5
+ /**
6
+ * Stage API Plugin
7
+ * @method register
8
+ * @param {Hapi} server Hapi Server
9
+ * @param {Object} options Configuration
10
+ * @param {Function} next Function to call when done
11
+ */
12
+ const stagesPlugin = {
13
+ name: 'stages',
14
+ async register(server) {
15
+ server.route([getStageBuildsRoute()]);
16
+ }
17
+ };
18
+
19
+ module.exports = stagesPlugin;
@@ -0,0 +1,68 @@
1
+ 'use strict';
2
+
3
+ const boom = require('@hapi/boom');
4
+ const joi = require('joi');
5
+ const schema = require('screwdriver-data-schema');
6
+ const listSchema = joi.array().items(schema.models.stageBuild.get).label('List of stage builds for a stage');
7
+ const idSchema = schema.models.stage.base.extract('id');
8
+ const eventIdSchema = schema.models.stageBuild.base.extract('eventId');
9
+
10
+ module.exports = () => ({
11
+ method: 'GET',
12
+ path: '/stages/{id}/stageBuilds',
13
+ options: {
14
+ description: 'Get stage builds for a stage',
15
+ notes: 'Returns all stage builds for a stage',
16
+ tags: ['api', 'stageBuilds'],
17
+ auth: {
18
+ strategies: ['token'],
19
+ scope: ['user', '!guest']
20
+ },
21
+
22
+ handler: async (request, h) => {
23
+ const { stageFactory, stageBuildFactory } = request.server.app;
24
+ const { page, count } = request.query;
25
+ const config = {
26
+ sort: request.query.sort,
27
+ params: {
28
+ stageId: request.params.id
29
+ }
30
+ };
31
+
32
+ return stageFactory.get(config.params.stageId).then(async stage => {
33
+ if (!stage) {
34
+ throw boom.notFound(`Stage ${config.params.stageId} does not exist`);
35
+ }
36
+
37
+ if (page || count) {
38
+ config.paginate = { page, count };
39
+ }
40
+
41
+ // Set eventId if provided
42
+ if (request.query.eventId) {
43
+ config.params.eventId = request.query.eventId;
44
+ }
45
+
46
+ return stageBuildFactory
47
+ .list(config)
48
+ .then(stageBuilds => h.response(stageBuilds.map(c => c.toJson())))
49
+ .catch(err => {
50
+ throw err;
51
+ });
52
+ });
53
+ },
54
+ response: {
55
+ schema: listSchema
56
+ },
57
+ validate: {
58
+ params: joi.object({
59
+ id: idSchema
60
+ }),
61
+ query: schema.api.pagination.concat(
62
+ joi.object({
63
+ eventId: eventIdSchema
64
+ })
65
+ )
66
+ }
67
+ }
68
+ });
@@ -3,7 +3,7 @@
3
3
  const boom = require('@hapi/boom');
4
4
  const schema = require('screwdriver-data-schema');
5
5
  const templateSchema = schema.api.templateValidator;
6
- const validator = require('screwdriver-template-validator');
6
+ const validator = require('screwdriver-template-validator').parseJobTemplate;
7
7
 
8
8
  /**
9
9
  * Hapi Template Validator Plugin
@@ -3,7 +3,7 @@
3
3
  const urlLib = require('url');
4
4
  const boom = require('@hapi/boom');
5
5
  const schema = require('screwdriver-data-schema');
6
- const validator = require('screwdriver-template-validator');
6
+ const validator = require('screwdriver-template-validator').parseJobTemplate;
7
7
  const templateSchema = schema.api.templateValidator;
8
8
  const hoek = require('@hapi/hoek');
9
9