screwdriver-api 8.0.161 → 8.0.163
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": "8.0.
|
|
3
|
+
"version": "8.0.163",
|
|
4
4
|
"description": "API server for the Screwdriver.cd service",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -85,7 +85,7 @@
|
|
|
85
85
|
"@hapi/inert": "^7.0.0",
|
|
86
86
|
"@hapi/vision": "^7.0.0",
|
|
87
87
|
"@promster/hapi": "^15.0.0",
|
|
88
|
-
"archiver": "^
|
|
88
|
+
"archiver": "^8.0.0",
|
|
89
89
|
"async": "^3.2.4",
|
|
90
90
|
"badge-maker": "^3.3.1",
|
|
91
91
|
"config": "^3.3.8",
|
|
@@ -100,7 +100,6 @@
|
|
|
100
100
|
"joi": "^17.7.0",
|
|
101
101
|
"js-yaml": "^3.14.1",
|
|
102
102
|
"jsonwebtoken": "^9.0.0",
|
|
103
|
-
"license-checker": "^25.0.1",
|
|
104
103
|
"lodash.isempty": "^4.4.0",
|
|
105
104
|
"lodash.mergewith": "^4.6.2",
|
|
106
105
|
"ndjson": "^2.0.0",
|
|
@@ -5,7 +5,6 @@ const joi = require('joi');
|
|
|
5
5
|
const jwt = require('jsonwebtoken');
|
|
6
6
|
const request = require('got');
|
|
7
7
|
const schema = require('screwdriver-data-schema');
|
|
8
|
-
const archiver = require('archiver');
|
|
9
8
|
const { PassThrough } = require('stream');
|
|
10
9
|
const logger = require('screwdriver-logger');
|
|
11
10
|
const { v4: uuidv4 } = require('uuid');
|
|
@@ -13,6 +12,12 @@ const idSchema = schema.models.build.base.extract('id');
|
|
|
13
12
|
const artifactSchema = joi.string().label('Artifact Name');
|
|
14
13
|
const typeSchema = joi.string().default('preview').valid('download', 'preview').label('Flag to trigger type either to download or preview');
|
|
15
14
|
|
|
15
|
+
async function createZipArchive() {
|
|
16
|
+
const { ZipArchive } = await import('archiver');
|
|
17
|
+
|
|
18
|
+
return new ZipArchive({ zlib: { level: 9 } });
|
|
19
|
+
}
|
|
20
|
+
|
|
16
21
|
module.exports = config => ({
|
|
17
22
|
method: 'GET',
|
|
18
23
|
path: '/builds/{id}/artifacts/{name*}',
|
|
@@ -90,7 +95,7 @@ module.exports = config => ({
|
|
|
90
95
|
}
|
|
91
96
|
|
|
92
97
|
// Create a stream and set up archiver
|
|
93
|
-
const archive =
|
|
98
|
+
const archive = await createZipArchive();
|
|
94
99
|
const passThrough = new PassThrough();
|
|
95
100
|
|
|
96
101
|
// Handle archiver errors
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const archiver = require('archiver');
|
|
4
3
|
const boom = require('@hapi/boom');
|
|
5
4
|
const request = require('got');
|
|
6
5
|
const joi = require('joi');
|
|
@@ -11,6 +10,12 @@ const schema = require('screwdriver-data-schema');
|
|
|
11
10
|
const { v4: uuidv4 } = require('uuid');
|
|
12
11
|
const idSchema = schema.models.build.base.extract('id');
|
|
13
12
|
|
|
13
|
+
async function createZipArchive() {
|
|
14
|
+
const { ZipArchive } = await import('archiver');
|
|
15
|
+
|
|
16
|
+
return new ZipArchive({ zlib: { level: 9 } });
|
|
17
|
+
}
|
|
18
|
+
|
|
14
19
|
|
|
15
20
|
module.exports = config => ({
|
|
16
21
|
method: 'GET',
|
|
@@ -63,7 +68,7 @@ module.exports = config => ({
|
|
|
63
68
|
const manifestArray = manifest.trim().split('\n');
|
|
64
69
|
|
|
65
70
|
// Create a stream and set up archiver
|
|
66
|
-
const archive =
|
|
71
|
+
const archive = await createZipArchive();
|
|
67
72
|
// PassThrough stream to make archiver readable by Hapi
|
|
68
73
|
const passThrough = new PassThrough();
|
|
69
74
|
|
package/plugins/versions.js
CHANGED
|
@@ -3,70 +3,299 @@
|
|
|
3
3
|
const fs = require('fs');
|
|
4
4
|
const path = require('path');
|
|
5
5
|
const process = require('process');
|
|
6
|
-
const checker = require('license-checker');
|
|
7
6
|
const VError = require('verror');
|
|
8
7
|
const schema = require('screwdriver-data-schema');
|
|
9
8
|
|
|
9
|
+
const UNKNOWN = 'UNKNOWN';
|
|
10
|
+
const UNLICENSED = 'UNLICENSED';
|
|
11
|
+
const SD_REGEX = /^screwdriver-/;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Read JSON file
|
|
15
|
+
* @param {string} filePath File path
|
|
16
|
+
* @returns {Object}
|
|
17
|
+
*/
|
|
18
|
+
function readJson(filePath) {
|
|
19
|
+
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Resolve project root path
|
|
24
|
+
* @returns {string}
|
|
25
|
+
*/
|
|
26
|
+
function findProjectRoot() {
|
|
27
|
+
if (fs.existsSync(path.resolve(process.cwd(), './node_modules'))) {
|
|
28
|
+
return process.cwd();
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return path.resolve(process.cwd(), '../..');
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Normalize repository url
|
|
36
|
+
* @param {Object|string} repository Repository URL
|
|
37
|
+
* @returns {string}
|
|
38
|
+
*/
|
|
39
|
+
function normalizeRepository(repository) {
|
|
40
|
+
const url = typeof repository === 'string' ? repository : repository && repository.url;
|
|
41
|
+
|
|
42
|
+
if (!url) {
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const normalizedUrl = url
|
|
47
|
+
.replace('http:', 'https:')
|
|
48
|
+
.replace('ssh://github.com', 'https://github.com')
|
|
49
|
+
.replace('git+ssh://git@', 'git://')
|
|
50
|
+
.replace('git+https://github.com', 'https://github.com')
|
|
51
|
+
.replace('git://github.com', 'https://github.com')
|
|
52
|
+
.replace('git@github.com:', 'https://github.com/')
|
|
53
|
+
.replace('www.github.com', 'github.com')
|
|
54
|
+
.replace('github:', '')
|
|
55
|
+
.replace(/\.git$/, '');
|
|
56
|
+
|
|
57
|
+
return normalizedUrl.startsWith('http') ? normalizedUrl : `https://github.com/${normalizedUrl}`;
|
|
58
|
+
}
|
|
59
|
+
|
|
10
60
|
/**
|
|
11
|
-
*
|
|
12
|
-
* @
|
|
13
|
-
* @
|
|
61
|
+
* Normalize license
|
|
62
|
+
* @param {Array|string} value license
|
|
63
|
+
* @returns {string}
|
|
14
64
|
*/
|
|
65
|
+
function normalizeLicense(value) {
|
|
66
|
+
if (!value) {
|
|
67
|
+
return undefined;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (Array.isArray(value)) {
|
|
71
|
+
const licenses = value
|
|
72
|
+
.map(item => {
|
|
73
|
+
if (typeof item === 'string') {
|
|
74
|
+
return item;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return item && (item.type || item.name);
|
|
78
|
+
})
|
|
79
|
+
.filter(Boolean);
|
|
80
|
+
|
|
81
|
+
return licenses.length === 1 ? licenses[0] : licenses;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (typeof value === 'object') {
|
|
85
|
+
return value.type || value.name;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return value;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Find license description from the document
|
|
93
|
+
* @param {string} text document
|
|
94
|
+
* @returns {string}
|
|
95
|
+
*/
|
|
96
|
+
function detectLicenseFromText(text) {
|
|
97
|
+
if (!text) {
|
|
98
|
+
return undefined;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const body = text.toLowerCase();
|
|
102
|
+
|
|
103
|
+
if (body.includes('mit license')) {
|
|
104
|
+
return 'MIT';
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (body.includes('apache license') && body.includes('version 2.0')) {
|
|
108
|
+
return 'Apache-2.0';
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (body.includes('isc license')) {
|
|
112
|
+
return 'ISC';
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (body.includes('bsd 3-clause')) {
|
|
116
|
+
return 'BSD-3-Clause';
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (body.includes('bsd 2-clause')) {
|
|
120
|
+
return 'BSD-2-Clause';
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return undefined;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Find license files
|
|
128
|
+
* @param {string} dir base directory
|
|
129
|
+
* @returns {Array}
|
|
130
|
+
*/
|
|
131
|
+
function getLicenseFiles(dir) {
|
|
132
|
+
return fs
|
|
133
|
+
.readdirSync(dir)
|
|
134
|
+
.filter(filename => {
|
|
135
|
+
const upper = filename.toUpperCase();
|
|
136
|
+
const basename = path.basename(upper, path.extname(upper));
|
|
137
|
+
|
|
138
|
+
return (
|
|
139
|
+
basename === 'LICENSE' || basename === 'LICENCE' || basename === 'COPYING' || basename === 'COPYRIGHT'
|
|
140
|
+
);
|
|
141
|
+
})
|
|
142
|
+
.sort();
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Find package directory
|
|
147
|
+
* @param {string} fromDir base directory
|
|
148
|
+
* @param {string} name package name
|
|
149
|
+
* @returns {string}
|
|
150
|
+
*/
|
|
151
|
+
function resolvePackageDir(fromDir, name) {
|
|
152
|
+
let current = fromDir;
|
|
153
|
+
|
|
154
|
+
while (current && current !== path.dirname(current)) {
|
|
155
|
+
const candidate = path.join(current, 'node_modules', name);
|
|
156
|
+
|
|
157
|
+
if (fs.existsSync(path.join(candidate, 'package.json'))) {
|
|
158
|
+
return candidate;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
current = path.dirname(current);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
return null;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* List up packages infomation
|
|
169
|
+
* @param {string} pkgDir base dirctory
|
|
170
|
+
* @param {object} data result store
|
|
171
|
+
* @returns {object}
|
|
172
|
+
*/
|
|
173
|
+
function collectPackage(pkgDir, data) {
|
|
174
|
+
const packageJsonPath = path.join(pkgDir, 'package.json');
|
|
175
|
+
|
|
176
|
+
if (!fs.existsSync(packageJsonPath)) {
|
|
177
|
+
return data;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const json = readJson(packageJsonPath);
|
|
181
|
+
const key = `${json.name}@${json.version}`;
|
|
182
|
+
|
|
183
|
+
if (!json.name || !json.version || data[key]) {
|
|
184
|
+
return data;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const moduleInfo = {
|
|
188
|
+
licenses: UNKNOWN
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
if (json.private) {
|
|
192
|
+
moduleInfo.private = true;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
const repository = normalizeRepository(json.repository);
|
|
196
|
+
|
|
197
|
+
if (repository) {
|
|
198
|
+
moduleInfo.repository = repository;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
let licenses = normalizeLicense(json.license || json.licenses);
|
|
202
|
+
|
|
203
|
+
if (!licenses && json.readme) {
|
|
204
|
+
licenses = detectLicenseFromText(json.readme);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const readmePath = path.join(pkgDir, 'README.md');
|
|
208
|
+
|
|
209
|
+
if (!licenses && fs.existsSync(readmePath)) {
|
|
210
|
+
licenses = detectLicenseFromText(fs.readFileSync(readmePath, 'utf8'));
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
getLicenseFiles(pkgDir).forEach((filename, index) => {
|
|
214
|
+
const licenseFile = path.join(pkgDir, filename);
|
|
215
|
+
|
|
216
|
+
if (!fs.lstatSync(licenseFile).isFile()) {
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const content = fs.readFileSync(licenseFile, 'utf8');
|
|
221
|
+
|
|
222
|
+
if (!licenses || String(licenses).includes(UNKNOWN) || String(licenses).indexOf('Custom:') === 0) {
|
|
223
|
+
licenses = detectLicenseFromText(content) || `Custom: ${filename}`;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
if (index === 0) {
|
|
227
|
+
moduleInfo.licenseFile = licenseFile;
|
|
228
|
+
}
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
moduleInfo.licenses = licenses || UNKNOWN;
|
|
232
|
+
|
|
233
|
+
if (json.private) {
|
|
234
|
+
moduleInfo.licenses = UNLICENSED;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
data[key] = moduleInfo;
|
|
238
|
+
|
|
239
|
+
[json.dependencies, json.optionalDependencies, json.peerDependencies].forEach(dependencies => {
|
|
240
|
+
Object.keys(dependencies || {}).forEach(depName => {
|
|
241
|
+
const childDir = resolvePackageDir(pkgDir, depName);
|
|
242
|
+
|
|
243
|
+
if (childDir) {
|
|
244
|
+
collectPackage(childDir, data);
|
|
245
|
+
}
|
|
246
|
+
});
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
return data;
|
|
250
|
+
}
|
|
251
|
+
|
|
15
252
|
const versionsTemplate = {
|
|
16
253
|
name: 'versions',
|
|
17
|
-
async register(server) {
|
|
18
|
-
// Designed to match Screwdriver specific packages
|
|
19
|
-
const SD_REGEX = /^screwdriver-/;
|
|
20
|
-
let start = process.cwd();
|
|
21
254
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
255
|
+
async register(server) {
|
|
256
|
+
try {
|
|
257
|
+
const data = collectPackage(findProjectRoot(), {});
|
|
25
258
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
},
|
|
32
|
-
(err, json) => {
|
|
33
|
-
if (err) {
|
|
34
|
-
return new VError(err, 'Unable to load package dependencies');
|
|
35
|
-
}
|
|
36
|
-
const depArray = Object.keys(json).map(key => ({ name: key, ...json[key] }));
|
|
37
|
-
const depDisplay = depArray.map(dep => ({
|
|
38
|
-
name: dep.name.split('@').slice(0, -1).join('@'),
|
|
39
|
-
repository: dep.repository || 'UNKNOWN',
|
|
40
|
-
licenses: dep.licenses || 'UNKNOWN'
|
|
259
|
+
const depArray = Object.keys(data)
|
|
260
|
+
.sort()
|
|
261
|
+
.map(key => ({
|
|
262
|
+
name: key,
|
|
263
|
+
...data[key]
|
|
41
264
|
}));
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
265
|
+
|
|
266
|
+
const depDisplay = depArray.map(dep => ({
|
|
267
|
+
name: dep.name.split('@').slice(0, -1).join('@'),
|
|
268
|
+
repository: dep.repository || UNKNOWN,
|
|
269
|
+
licenses: dep.licenses || UNKNOWN
|
|
270
|
+
}));
|
|
271
|
+
|
|
272
|
+
const sdVersions = depArray.filter(dep => SD_REGEX.test(dep.name)).map(dep => dep.name);
|
|
273
|
+
|
|
274
|
+
return server.route({
|
|
275
|
+
method: 'GET',
|
|
276
|
+
path: '/versions',
|
|
277
|
+
handler: (request, h) =>
|
|
278
|
+
h.response({
|
|
279
|
+
versions: sdVersions,
|
|
280
|
+
licenses: depDisplay
|
|
281
|
+
}),
|
|
282
|
+
config: {
|
|
283
|
+
description: 'API Package Versions',
|
|
284
|
+
notes: 'Returns list of Screwdriver package versions and third-party dependencies',
|
|
285
|
+
tags: ['api'],
|
|
286
|
+
plugins: {
|
|
287
|
+
'hapi-rate-limit': {
|
|
288
|
+
enabled: false
|
|
65
289
|
}
|
|
290
|
+
},
|
|
291
|
+
response: {
|
|
292
|
+
schema: schema.api.versions
|
|
66
293
|
}
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
)
|
|
294
|
+
}
|
|
295
|
+
});
|
|
296
|
+
} catch (err) {
|
|
297
|
+
throw new VError(err, 'Unable to load package dependencies');
|
|
298
|
+
}
|
|
70
299
|
}
|
|
71
300
|
};
|
|
72
301
|
|