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.161",
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": "^7.0.1",
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 = archiver('zip', { zlib: { level: 9 } });
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 = archiver('zip', { zlib: { level: 9 } });
71
+ const archive = await createZipArchive();
67
72
  // PassThrough stream to make archiver readable by Hapi
68
73
  const passThrough = new PassThrough();
69
74
 
@@ -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
- * Hapi interface for plugin to return package list
12
- * @method register
13
- * @param {Hapi.Server} server
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
- if (!fs.existsSync(path.resolve(process.cwd(), './node_modules'))) {
23
- start = path.resolve(process.cwd(), '../..');
24
- }
255
+ async register(server) {
256
+ try {
257
+ const data = collectPackage(findProjectRoot(), {});
25
258
 
26
- // Load licenses
27
- return checker.init(
28
- {
29
- production: true,
30
- start
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
- const sdVersions = depArray.filter(dep => SD_REGEX.test(dep.name)).map(dep => dep.name);
43
-
44
- return server.route({
45
- method: 'GET',
46
- path: '/versions',
47
- handler: (request, h) =>
48
- h.response({
49
- // List of Screwdriver package versions
50
- versions: sdVersions,
51
- // List of licenses for third-party dependencies
52
- licenses: depDisplay
53
- }),
54
- config: {
55
- description: 'API Package Versions',
56
- notes: 'Returns list of Screwdriver package versions and third-party dependencies',
57
- tags: ['api'],
58
- plugins: {
59
- 'hapi-rate-limit': {
60
- enabled: false
61
- }
62
- },
63
- response: {
64
- schema: schema.api.versions
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