forked from aws/aws-cdk
-
Notifications
You must be signed in to change notification settings - Fork 0
/
verify-stripped-exp.ts
158 lines (138 loc) · 5.07 KB
/
verify-stripped-exp.ts
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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
// +------------------------------------------------------------------------------------------------
// | this script is executed post packaging to verify that experimental modules in aws-cdk-lib includes **only** L1 autogenerated files.
// | The purpose is to avoid publishing L2 of experimental modules with aws-cdk-lib
// |
import { spawnSync } from 'child_process';
import * as console from 'console';
import * as os from 'os';
import * as path from 'path';
import * as fs from 'fs-extra';
async function main(tempDir: string) {
console.log('🧐 Verifying all experimental modules includes only L1s files...');
const cwd = process.cwd();
const awsCdkModulesRepoPath = path.join(findWorkspacePath(), 'packages', '@aws-cdk');
// eslint-disable-next-line @typescript-eslint/no-require-imports
const version = require('./../package.json').version;
const tarFullPath = path.join(cwd, 'dist', 'js', `aws-cdk-lib@${version}.jsii.tgz`);
const invalidCfnModules = new Map<string, Array<String>>();
const invalidModules = new Array<string>();
// install the tarball in a temp directory
console.log(`installing aws-cdk-lib from dist/js into ${tempDir}`);
exec('npm', ['install', '--prefix', tempDir, tarFullPath]);
const installedAwsCdkLibPath = path.join(tempDir, 'node_modules', 'aws-cdk-lib', 'lib');
for (const module of fs.readdirSync(awsCdkModulesRepoPath)) {
// eslint-disable-next-line @typescript-eslint/no-require-imports
const pkgJson = require(path.join(awsCdkModulesRepoPath, module, 'package.json'));
if (pkgJson.stability !== 'experimental') {
continue;
}
if (pkgJson['cdk-build']?.cloudformation) {
// if a cfn module, verify only the allowed files exists
const files = await listAllFiles(path.join(installedAwsCdkLibPath, module));
const invalidFiles = new Array();
files.forEach(file => {
if (!isAllowedFile(file)) {
invalidFiles.push(file);
}
});
if (invalidFiles.length > 0) {
invalidCfnModules.set(module, invalidFiles);
}
} else {
// not a cfn module, verify it was entirely removed
if (fs.existsSync(path.join(installedAwsCdkLibPath, module))) {
invalidModules.push(module);
}
}
}
if (invalidCfnModules.size > 0 || invalidModules.length > 0) {
if (invalidCfnModules.size > 0 ) {
console.log('cfn module with invalid files:');
for (let [module, files] of invalidCfnModules.entries()) {
console.log(`${module}:`);
files.forEach(file => console.log(`\t ${file}`));
}
}
console.log('---------------------------------------------');
if (invalidModules.length > 0) {
console.log('non-cfn experimental modules:');
invalidModules.forEach(m => console.log(`\t ${m}`));
}
throw new Error('Verification Error');
}
}
const tempDir = fs.mkdtempSync(os.tmpdir());
main(tempDir).then(
() => {
fs.removeSync(tempDir);
console.log('✅ All experimental modules includes only L1s files!');
process.exit(0);
},
(err) => {
process.stderr.write(`${err}\n`);
process.stderr.write(`❌ Verification failed, Some experimental modules includes non L1 files, see details above. Inspect working directory: '${tempDir}'`);
process.exit(1);
},
);
/**
* Spawn sync with error handling
*/
function exec(cmd: string, args: string[]) {
const proc = spawnSync(cmd, args);
if (proc.error) {
throw proc.error;
}
if (proc.status !== 0) {
if (proc.stdout || proc.stderr) {
throw new Error(`${cmd} exited with status ${proc.status}; stdout: ${proc.stdout?.toString().trim()}\n\n\nstderr: ${proc.stderr?.toString().trim()}`);
}
throw new Error(`${cmd} exited with status ${proc.status}`);
}
return proc;
}
const GENERATED_SUFFIX_REGEX = new RegExp(/generated\.(js|d\.ts)$/);
const ALLOWED_FILES = ['.jsiirc.json', 'index.ts', 'index.js', 'index.d.ts'];
/**
* Recursively collect all files in dir
*/
async function listAllFiles(dir: string) {
const ret = new Array();
async function recurse(part: string) {
const files = await fs.readdir(part);
for (const file of files) {
const fullPath = path.join(part, file);
if ((await fs.stat(fullPath)).isDirectory()) {
await recurse(fullPath);
} else {
ret.push(file);
}
}
}
await recurse(dir);
return ret;
}
/**
* Find the workspace root path. Walk up the directory tree until you find lerna.json
*/
function findWorkspacePath() {
return _findRootPath(process.cwd());
function _findRootPath(part: string): string {
if (part === path.resolve(part, '..')) {
throw new Error('couldn\'t find a \'lerna.json\' file when walking up the directory tree, are you in a aws-cdk project?');
}
if (fs.existsSync(path.resolve(part, 'lerna.json'))) {
return part;
}
return _findRootPath(path.resolve(part, '..'));
}
}
/**
* @param file
* @returns true if the file allowed in an L1 only modules, otherwise false
*/
function isAllowedFile(file: string) {
if (GENERATED_SUFFIX_REGEX.test(file)) {
return true;
}
return ALLOWED_FILES.includes(file);
}