screwdriver-api 4.1.182 → 4.1.186

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
@@ -50,6 +50,9 @@ const notificationConfig = config.get('notifications');
50
50
  // Multiple build cluster feature flag
51
51
  const multiBuildClusterEnabled = convertToBool(config.get('multiBuildCluster').enabled);
52
52
 
53
+ // Queue Webhook feature flag
54
+ const queueWebhookEnabled = convertToBool(config.get('queueWebhook').enabled);
55
+
53
56
  // Default cluster environment variable
54
57
  const clusterEnvConfig = config.get('build').environment; // readonly
55
58
  const clusterEnv = { ...clusterEnvConfig };
@@ -254,6 +257,10 @@ datastore.setup(datastoreConfig.ddlSyncEnabled).then(() =>
254
257
  validator: {
255
258
  externalJoin: true,
256
259
  notificationsValidationErr
260
+ },
261
+ queueWebhook: {
262
+ executor,
263
+ queueWebhookEnabled
257
264
  }
258
265
  })
259
266
  .then(instance => logger.info('Server running at %s', instance.info.uri))
@@ -271,6 +271,11 @@ executor:
271
271
  tls: QUEUE_REDIS_TLS_ENABLED
272
272
  database: QUEUE_REDIS_DATABASE
273
273
 
274
+
275
+ queueWebhook:
276
+ # Enabled events from webhook queue or not
277
+ enabled: QUEUE_WEBHOOK_ENABLED
278
+
274
279
  scms:
275
280
  __name: SCM_SETTINGS
276
281
  __format: json
@@ -190,6 +190,10 @@ executor:
190
190
  tls: false
191
191
  database: 0
192
192
 
193
+ queueWebhook:
194
+ # Enabled events from webhook queue or not
195
+ enabled: false
196
+
193
197
  scms: {}
194
198
  # github:
195
199
  # plugin: github
package/lib/server.js CHANGED
@@ -136,7 +136,8 @@ module.exports = async config => {
136
136
  collectionFactory: config.collectionFactory,
137
137
  buildClusterFactory: config.buildClusterFactory,
138
138
  ecosystem: config.ecosystem,
139
- release: config.release
139
+ release: config.release,
140
+ queueWebhook: config.queueWebhook
140
141
  };
141
142
 
142
143
  const bellConfigs = await config.auth.scm.getBellConfiguration();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "screwdriver-api",
3
- "version": "4.1.182",
3
+ "version": "4.1.186",
4
4
  "description": "API server for the Screwdriver.cd service",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -410,11 +410,6 @@ function parseJobInfo({ joinObj = {}, current, nextJobName, nextPipelineId }) {
410
410
  * @return {Promise} All finished builds
411
411
  */
412
412
  async function getFinishedBuilds(event, buildFactory) {
413
- if (!event.parentEventId) {
414
- // FIXME: remove this flow to always use buildFactory.getLatestBuilds
415
- return event.getBuilds();
416
- }
417
-
418
413
  // FIXME: buildFactory.getLatestBuilds doesn't return build model
419
414
  const builds = await buildFactory.getLatestBuilds({ groupEventId: event.groupEventId });
420
415
 
@@ -529,11 +524,13 @@ async function handleNewBuild({ done, hasFailure, newBuild, jobName, pipelineId
529
524
  return null;
530
525
  }
531
526
 
532
- // If all join builds finished successfully, start new build
533
- newBuild.status = 'QUEUED';
534
- const queuedBuild = await newBuild.update();
527
+ // If all join builds finished successfully and it's clear that a new build has not been started before, start new build
528
+ if ([ 'CREATED', null, undefined ].includes(newBuild.status)) {
529
+ newBuild.status = 'QUEUED';
530
+ const queuedBuild = await newBuild.update();
535
531
 
536
- return queuedBuild.start();
532
+ return queuedBuild.start();
533
+ }
537
534
  }
538
535
 
539
536
  return null;
@@ -32,6 +32,9 @@ server.register({
32
32
  #### Returns a list of builds associated with the event
33
33
  `GET /events/{id}/builds`
34
34
 
35
+ `GET /events/{id}/builds?fetchSteps=false&readOnly=true`
36
+
37
+
35
38
  #### Get build metrics for a single event
36
39
  `GET /events/{id}/metrics`
37
40
 
@@ -24,14 +24,23 @@ module.exports = () => ({
24
24
  handler: async (request, h) => {
25
25
  const { eventFactory } = request.server.app;
26
26
  const event = await eventFactory.get(request.params.id);
27
+ const { fetchSteps, readOnly } = request.query;
27
28
 
28
29
  if (!event) {
29
30
  throw boom.notFound('Event does not exist');
30
31
  }
31
32
 
32
- const buildsModel = await event.getBuilds();
33
+ const config = readOnly ? { readOnly: true } : {};
33
34
 
34
- const data = await Promise.all(buildsModel.map(async buildModel => buildModel.toJsonWithSteps()));
35
+ const buildsModel = await event.getBuilds(config);
36
+
37
+ let data;
38
+
39
+ if (fetchSteps) {
40
+ data = await Promise.all(buildsModel.map(async buildModel => buildModel.toJsonWithSteps()));
41
+ } else {
42
+ data = await Promise.all(buildsModel.map(async buildModel => buildModel.toJson()));
43
+ }
35
44
 
36
45
  return h.response(data);
37
46
  },
@@ -41,7 +50,21 @@ module.exports = () => ({
41
50
  validate: {
42
51
  params: joi.object({
43
52
  id: eventIdSchema
44
- })
53
+ }),
54
+ query: schema.api.pagination.concat(
55
+ joi.object({
56
+ readOnly: joi
57
+ .boolean()
58
+ .truthy('true')
59
+ .falsy('false')
60
+ .default(false),
61
+ fetchSteps: joi
62
+ .boolean()
63
+ .truthy('true')
64
+ .falsy('false')
65
+ .default(true)
66
+ })
67
+ )
45
68
  }
46
69
  }
47
70
  });
@@ -46,6 +46,8 @@ Example payload:
46
46
  #### Get list of builds for a single job
47
47
  `GET /jobs/{id}/builds`
48
48
 
49
+ `GET /jobs/{id}/builds?fetchSteps=false&readOnly=true`
50
+
49
51
  `GET /jobs/{id}/builds?page=2&count=30&sort=ascending`
50
52
 
51
53
  `GET /jobs/{id}/builds?page=2&count=30&sort=ascending&sortBy=id`
@@ -23,7 +23,7 @@ module.exports = () => ({
23
23
 
24
24
  handler: async (request, h) => {
25
25
  const factory = request.server.app.jobFactory;
26
- const { sort, sortBy, page, count } = request.query;
26
+ const { sort, sortBy, page, count, fetchSteps, readOnly } = request.query;
27
27
 
28
28
  return factory
29
29
  .get(request.params.id)
@@ -32,7 +32,9 @@ module.exports = () => ({
32
32
  throw boom.notFound('Job does not exist');
33
33
  }
34
34
 
35
- const config = { sort, sortBy: 'createTime' };
35
+ const config = readOnly
36
+ ? { sort, sortBy: 'createTime', readOnly: true }
37
+ : { sort, sortBy: 'createTime' };
36
38
 
37
39
  if (sortBy) {
38
40
  config.sortBy = sortBy;
@@ -45,7 +47,13 @@ module.exports = () => ({
45
47
  return job.getBuilds(config);
46
48
  })
47
49
  .then(async builds => {
48
- const data = await Promise.all(builds.map(b => b.toJsonWithSteps()));
50
+ let data;
51
+
52
+ if (fetchSteps) {
53
+ data = await Promise.all(builds.map(b => b.toJsonWithSteps()));
54
+ } else {
55
+ data = await Promise.all(builds.map(b => b.toJson()));
56
+ }
49
57
 
50
58
  return h.response(data);
51
59
  })
@@ -60,7 +68,20 @@ module.exports = () => ({
60
68
  params: joi.object({
61
69
  id: jobIdSchema
62
70
  }),
63
- query: schema.api.pagination
71
+ query: schema.api.pagination.concat(
72
+ joi.object({
73
+ readOnly: joi
74
+ .boolean()
75
+ .truthy('true')
76
+ .falsy('false')
77
+ .default(false),
78
+ fetchSteps: joi
79
+ .boolean()
80
+ .truthy('true')
81
+ .falsy('false')
82
+ .default(true)
83
+ })
84
+ )
64
85
  }
65
86
  }
66
87
  });
@@ -62,9 +62,11 @@ const webhooksPlugin = {
62
62
  maxBytes: parseInt(pluginOptions.maxBytes, 10) || DEFAULT_MAX_BYTES
63
63
  },
64
64
  handler: async (request, h) => {
65
- const { pipelineFactory } = request.server.app;
65
+ const { pipelineFactory, queueWebhook } = request.server.app;
66
66
  const { scm } = pipelineFactory;
67
+ const { executor, queueWebhookEnabled } = queueWebhook;
67
68
  let message = 'Unable to process this kind of event';
69
+ let hookId;
68
70
 
69
71
  try {
70
72
  const parsed = await scm.parseHook(request.headers, request.payload);
@@ -76,10 +78,26 @@ const webhooksPlugin = {
76
78
 
77
79
  parsed.pluginOptions = pluginOptions;
78
80
 
79
- const { type, hookId } = parsed;
81
+ const { type } = parsed;
82
+ hookId = parsed.hookId;
80
83
 
81
84
  request.log(['webhook', hookId], `Received event type ${type}`);
82
85
 
86
+ if (queueWebhookEnabled) {
87
+ parsed.token = request.server.plugins.auth.generateToken({
88
+ scope: ['sdapi']
89
+ });
90
+
91
+ try {
92
+ return await executor.enqueueWebhook(parsed);
93
+ } catch (err) {
94
+ // if enqueueWebhook is not implemented, an event starts without enqueuing
95
+ if (err.message != 'Not implemented') {
96
+ throw err;
97
+ }
98
+ }
99
+ }
100
+
83
101
  return await startHookEvent(request, h, parsed);
84
102
 
85
103
  } catch (err) {