screwdriver-api 5.0.3 → 5.0.5

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "screwdriver-api",
3
- "version": "5.0.3",
3
+ "version": "5.0.5",
4
4
  "description": "API server for the Screwdriver.cd service",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -81,7 +81,7 @@ module.exports = () => ({
81
81
 
82
82
  // check if the call wants compact data
83
83
  if (compact === 'true') {
84
- // removing `config` trims most of the bytes
84
+ // removing these fields trims most of the bytes
85
85
  config.exclude = ['usage', 'docker', 'habitat', 'binary'];
86
86
  // using spread operator because params could be null
87
87
  config.params = {
@@ -53,7 +53,11 @@ module.exports = () => ({
53
53
  namespace: namespaceSchema,
54
54
  name: nameSchema
55
55
  }),
56
- query: schema.api.pagination
56
+ query: schema.api.pagination.concat(
57
+ joi.object({
58
+ search: joi.forbidden() // we don't support search for Command list tag
59
+ })
60
+ )
57
61
  }
58
62
  }
59
63
  });
@@ -60,7 +60,11 @@ module.exports = () => ({
60
60
  namespace: namespaceSchema,
61
61
  name: nameSchema
62
62
  }),
63
- query: schema.api.pagination
63
+ query: schema.api.pagination.concat(
64
+ joi.object({
65
+ search: joi.forbidden() // we don't support search for Command list versions
66
+ })
67
+ )
64
68
  }
65
69
  }
66
70
  });
@@ -62,7 +62,8 @@ module.exports = () => ({
62
62
  .boolean()
63
63
  .truthy('true')
64
64
  .falsy('false')
65
- .default(true)
65
+ .default(true),
66
+ search: joi.forbidden() // we don't support search for Event list builds
66
67
  })
67
68
  )
68
69
  }
@@ -86,7 +86,7 @@ module.exports = () => ({
86
86
  .falsy('false')
87
87
  .default(true),
88
88
  status: statusSchema,
89
- search: joi.forbidden() // we don't support search for list builds
89
+ search: joi.forbidden() // we don't support search for Job list builds
90
90
  })
91
91
  )
92
92
  }
@@ -2,44 +2,10 @@
2
2
 
3
3
  const joi = require('joi');
4
4
  const schema = require('screwdriver-data-schema');
5
- const workflowParser = require('screwdriver-workflow-parser');
6
5
  const idSchema = schema.models.pipeline.base.extract('id');
6
+ const logger = require('screwdriver-logger');
7
7
  const { getPipelineBadge } = require('./helper');
8
-
9
- /**
10
- * DFS the workflowGraph from the start point
11
- * @method dfs
12
- * @param {Object} workflowGraph workflowGraph
13
- * @param {String} start Start job name
14
- * @param {String} prNum PR number in case of PR trigger
15
- * @return {Set} A set of build ids that are visited
16
- */
17
- function dfs(workflowGraph, start, prNum) {
18
- let nextJobsConfig;
19
-
20
- if (start === '~pr') {
21
- nextJobsConfig = {
22
- trigger: start,
23
- prNum
24
- };
25
- } else {
26
- nextJobsConfig = {
27
- trigger: start
28
- };
29
- }
30
-
31
- const nextJobs = workflowParser.getNextJobs(workflowGraph, nextJobsConfig);
32
-
33
- let visited = new Set(nextJobs);
34
-
35
- nextJobs.forEach(job => {
36
- const subJobs = dfs(workflowGraph, job);
37
-
38
- visited = new Set([...visited, ...subJobs]);
39
- });
40
-
41
- return visited;
42
- }
8
+ const BUILD_META_KEYWORD = '%"build":%';
43
9
 
44
10
  module.exports = config => ({
45
11
  method: 'GET',
@@ -54,64 +20,72 @@ module.exports = config => ({
54
20
  }
55
21
  },
56
22
  handler: async (request, h) => {
57
- const factory = request.server.app.pipelineFactory;
23
+ const { pipelineFactory, eventFactory } = request.server.app;
24
+ const pipelineId = request.params.id;
58
25
  const { statusColor } = config;
59
26
  const badgeConfig = {
60
27
  statusColor
61
28
  };
62
29
  const contentType = 'image/svg+xml;charset=utf-8';
63
30
 
64
- return factory
65
- .get(request.params.id)
66
- .then(pipeline => {
67
- if (!pipeline) {
68
- return h.response(getPipelineBadge(badgeConfig)).header('Content-Type', contentType);
69
- }
70
-
71
- return pipeline.getEvents({ sort: 'ascending' }).then(allEvents => {
72
- const getLastEffectiveEvent = events => {
73
- const lastEvent = events.pop();
74
-
75
- if (!lastEvent) {
76
- return h.response(getPipelineBadge(badgeConfig)).header('Content-Type', contentType);
77
- }
78
-
79
- return lastEvent.getBuilds().then(builds => {
80
- if (!builds || builds.length < 1) {
81
- return getLastEffectiveEvent(events);
82
- }
83
-
84
- const buildsStatus = builds.reverse().map(build => build.status.toLowerCase());
85
-
86
- let workflowLength = 0;
87
-
88
- if (lastEvent.workflowGraph) {
89
- const nextJobs = dfs(lastEvent.workflowGraph, lastEvent.startFrom, lastEvent.prNum);
90
-
91
- workflowLength = nextJobs.size;
92
- }
93
-
94
- for (let i = builds.length; i < workflowLength; i += 1) {
95
- buildsStatus[i] = 'unknown';
96
- }
97
-
98
- return h
99
- .response(
100
- getPipelineBadge(
101
- Object.assign(badgeConfig, {
102
- buildsStatus,
103
- label: pipeline.name
104
- })
105
- )
106
- )
107
- .header('Content-Type', contentType);
108
- });
109
- };
110
-
111
- return getLastEffectiveEvent(allEvents);
112
- });
113
- })
114
- .catch(() => h.response(getPipelineBadge(badgeConfig)));
31
+ try {
32
+ // Get pipeline
33
+ const pipeline = await pipelineFactory.get(pipelineId);
34
+
35
+ if (!pipeline) {
36
+ return h.response(getPipelineBadge(badgeConfig)).header('Content-Type', contentType);
37
+ }
38
+
39
+ // Get latest pipeline events
40
+ const latestEvents = await eventFactory.list({
41
+ params: {
42
+ pipelineId,
43
+ parentEventId: null,
44
+ type: 'pipeline'
45
+ },
46
+ // Make sure build exists for event, meta will be {} for skipped builds
47
+ search: {
48
+ field: 'meta',
49
+ keyword: BUILD_META_KEYWORD
50
+ },
51
+ // removing these fields trims most of the bytes
52
+ exclude: ['workflowGraph', 'meta', 'commit'],
53
+ paginate: {
54
+ count: 1
55
+ },
56
+ sort: 'descending'
57
+ });
58
+
59
+ if (!latestEvents || Object.keys(latestEvents).length === 0) {
60
+ return h.response(getPipelineBadge(badgeConfig)).header('Content-Type', contentType);
61
+ }
62
+
63
+ // Only care about latest
64
+ const lastEvent = latestEvents[0];
65
+ const builds = await lastEvent.getBuilds({ readOnly: true });
66
+
67
+ if (!builds || builds.length < 1) {
68
+ return h.response(getPipelineBadge(badgeConfig)).header('Content-Type', contentType);
69
+ }
70
+
71
+ // Convert build statuses
72
+ const buildsStatus = builds.reverse().map(build => build.status.toLowerCase());
73
+
74
+ return h
75
+ .response(
76
+ getPipelineBadge(
77
+ Object.assign(badgeConfig, {
78
+ buildsStatus,
79
+ label: pipeline.name
80
+ })
81
+ )
82
+ )
83
+ .header('Content-Type', contentType);
84
+ } catch (err) {
85
+ logger.error(`Failed to get badge for pipeline:${pipelineId}: ${err.message}`);
86
+
87
+ return h.response(getPipelineBadge(badgeConfig));
88
+ }
115
89
  },
116
90
  validate: {
117
91
  params: joi.object({
@@ -64,7 +64,8 @@ module.exports = () => ({
64
64
  query: schema.api.pagination.concat(
65
65
  joi.object({
66
66
  type: joi.string(),
67
- prNum: prNumSchema
67
+ prNum: prNumSchema,
68
+ search: joi.forbidden() // we don't support search for Pipeline list events
68
69
  })
69
70
  )
70
71
  }
@@ -67,7 +67,8 @@ module.exports = () => ({
67
67
  .truthy('true')
68
68
  .falsy('false')
69
69
  .default(false),
70
- jobName: jobNameSchema
70
+ jobName: jobNameSchema,
71
+ search: joi.forbidden() // we don't support search for Pipeline list jobs
71
72
  })
72
73
  )
73
74
  }
@@ -87,7 +87,8 @@ module.exports = () => ({
87
87
  query: schema.api.pagination.concat(
88
88
  joi.object({
89
89
  eventId: pipelineIdSchema,
90
- groupEventId: pipelineIdSchema
90
+ groupEventId: pipelineIdSchema,
91
+ search: joi.forbidden() // we don't support search for Pipeline list stages
91
92
  })
92
93
  )
93
94
  }
@@ -102,7 +102,8 @@ module.exports = () => ({
102
102
  endTime: joi.string().isoDate(),
103
103
  aggregateInterval: joi.string().valid('none', 'day', 'week', 'month', 'year'),
104
104
  'downtimeJobs[]': jobIdsSchema.optional(),
105
- 'downtimeStatuses[]': statusesSchema.optional()
105
+ 'downtimeStatuses[]': statusesSchema.optional(),
106
+ search: joi.forbidden() // we don't support search for Pipeline metrics
106
107
  })
107
108
  )
108
109
  }
@@ -50,7 +50,11 @@ module.exports = () => ({
50
50
  params: joi.object({
51
51
  name: nameSchema
52
52
  }),
53
- query: schema.api.pagination
53
+ query: schema.api.pagination.concat(
54
+ joi.object({
55
+ search: joi.forbidden() // we don't support search for Template list tags
56
+ })
57
+ )
54
58
  }
55
59
  }
56
60
  });
@@ -57,7 +57,11 @@ module.exports = () => ({
57
57
  params: joi.object({
58
58
  name: nameSchema
59
59
  }),
60
- query: schema.api.pagination
60
+ query: schema.api.pagination.concat(
61
+ joi.object({
62
+ search: joi.forbidden() // we don't support search for Template list versions
63
+ })
64
+ )
61
65
  }
62
66
  }
63
67
  });
@@ -54,7 +54,11 @@ module.exports = () => ({
54
54
  params: joi.object({
55
55
  name: nameSchema
56
56
  }),
57
- query: schema.api.pagination
57
+ query: schema.api.pagination.concat(
58
+ joi.object({
59
+ search: joi.forbidden() // we don't support search for Template list versions with metrics
60
+ })
61
+ )
58
62
  }
59
63
  }
60
64
  });