forked from backstage/backstage
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrun-fossa.js
executable file
·141 lines (120 loc) · 3.92 KB
/
run-fossa.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
#!/usr/bin/env node
/*
* Copyright 2020 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// This script generates an appropriate fossa config, and wraps the running
// of `fossa analyze` in a retry loop as it frequently fails with a 502 error
const { resolve: resolvePath, join: joinPath, basename } = require('path');
const { promises: fs } = require('fs');
const { execFile: execFileCb } = require('child_process');
const { promisify } = require('util');
const execFile = promisify(execFileCb);
const FOSSA_YAML_HEAD = `
version: 2
cli:
server: https://app.fossa.com
fetcher: custom
project: backstage
analyze:
modules:`;
const IGNORED_DIRS = ['node_modules', 'dist', 'bin', '.git'];
// Finds all directories containing package.json files that we're interested in analyzing
async function findPackageJsonDirs(dir, depth = 0) {
if (depth > 2) {
return []; // Skipping packages that are deeper than 2 dirs in
}
const files = await fs.readdir(dir);
const paths = await Promise.all(
files
.filter(file => !IGNORED_DIRS.includes(file))
.map(async file => {
const path = joinPath(dir, file);
if ((await fs.stat(path)).isDirectory()) {
return findPackageJsonDirs(path, depth + 1);
} else if (file === 'package.json') {
return dir;
}
return [];
}),
);
return paths.flat();
}
// A replacement for `fossa init`, as that generates a bad config for this repo
async function generateConfig(paths) {
let content = FOSSA_YAML_HEAD;
for (const path of paths) {
content += `
- name: ${basename(path)}
type: npm
path: ${path}
target: ${path}
options:
strategy: yarn-list
`;
}
return content;
}
// Runs `fossa analyze`, with 502 errors being retried up to 3 times
async function runAnalyze(githubRef) {
for (let attempt = 1; attempt <= 3; attempt++) {
console.error(`Running fossa analyze, attempt ${attempt}`);
try {
const { stdout, stderr } = await execFile(
'fossa',
['analyze', '--branch', githubRef],
{ shell: true },
);
console.error(stderr);
console.log(stdout);
return; // Analyze was successful, we're done
} catch (error) {
if (!error.code) {
throw error;
}
if (error.stderr) {
process.stderr.write(error.stderr);
}
if (error.stdout) {
process.stdout.write(error.stdout);
}
if (error.stderr && error.stderr.includes('502 Bad Gateway')) {
console.error('Encountered 502 during fossa analysis upload, retrying');
continue;
}
throw new Error(`Fossa analyze failed with code ${error.code}`);
}
}
console.error('Maximum number of retries reached, skipping fossa analysis');
}
async function main() {
const githubRef = process.env.GITHUB_REF;
if (!githubRef) {
throw new Error('GITHUB_REF is not set');
}
// This is picked up by the fossa CLI and should be set
if (!process.env.FOSSA_API_KEY) {
throw new Error('FOSSA_API_KEY is not set');
}
process.cwd(resolvePath(__dirname, '..'));
const packageJsonPaths = await findPackageJsonDirs('.');
const configContents = await generateConfig(packageJsonPaths);
await fs.writeFile('.fossa.yml', configContents, 'utf8');
console.error(`Generated fossa config:\n${configContents}`);
await runAnalyze(githubRef);
}
main().catch(error => {
console.error(error.stack);
process.exit(1);
});