predeploy-check 1.0.0 → 1.1.0
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/LICENSE +21 -0
- package/README.md +83 -74
- package/bin/cli.js +50 -48
- package/checks/01-python-render.js +207 -123
- package/checks/03-case-sensitivity.js +240 -228
- package/index.js +137 -130
- package/package.json +37 -37
package/index.js
CHANGED
|
@@ -1,130 +1,137 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const chalk = require('chalk');
|
|
4
|
-
const path = require('path');
|
|
5
|
-
const fs = require('fs');
|
|
6
|
-
|
|
7
|
-
// Dynamically load all check modules from /checks/
|
|
8
|
-
const checksDir = path.join(__dirname, 'checks');
|
|
9
|
-
const checkFiles = fs.readdirSync(checksDir)
|
|
10
|
-
.filter((f) => f.endsWith('.js'))
|
|
11
|
-
.sort();
|
|
12
|
-
|
|
13
|
-
const checks = checkFiles.map((f) => {
|
|
14
|
-
const mod = require(path.join(checksDir, f));
|
|
15
|
-
return {
|
|
16
|
-
name: mod.name || f.replace('.js', ''),
|
|
17
|
-
run: mod.run,
|
|
18
|
-
};
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
const STATUS_ICONS = {
|
|
22
|
-
pass: chalk.green('✅'),
|
|
23
|
-
warn: chalk.yellow('⚠️ '),
|
|
24
|
-
fail: chalk.red('❌'),
|
|
25
|
-
skip: chalk.gray('⏭️ '),
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
const STATUS_COLORS = {
|
|
29
|
-
pass: chalk.green,
|
|
30
|
-
warn: chalk.yellow,
|
|
31
|
-
fail: chalk.red,
|
|
32
|
-
skip: chalk.gray,
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Format a single result line.
|
|
37
|
-
*/
|
|
38
|
-
function formatResult(result) {
|
|
39
|
-
const icon = STATUS_ICONS[result.status] || '?';
|
|
40
|
-
const color = STATUS_COLORS[result.status] || chalk.white;
|
|
41
|
-
const lines = [];
|
|
42
|
-
|
|
43
|
-
lines.push(`${icon} ${color.bold(result.message)}`);
|
|
44
|
-
|
|
45
|
-
if (result.details && result.details.length > 0) {
|
|
46
|
-
for (const detail of result.details) {
|
|
47
|
-
const loc = detail.file
|
|
48
|
-
? chalk.dim(` ${detail.file}${detail.line ? `:${detail.line}` : ''}`)
|
|
49
|
-
: '';
|
|
50
|
-
if (loc) lines.push(loc);
|
|
51
|
-
if (detail.message) lines.push(chalk.dim(` → ${detail.message}`));
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
if (result.fix && result.status !== 'pass') {
|
|
56
|
-
lines.push(chalk.cyan(` 💡 Fix: ${result.fix}`));
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
return lines.join('\n');
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Run all checks against the given project root.
|
|
64
|
-
* Returns exit code: 1 if any ❌, 0 otherwise.
|
|
65
|
-
*/
|
|
66
|
-
async function runAllChecks(projectRoot) {
|
|
67
|
-
console.log('');
|
|
68
|
-
console.log(chalk.bold.underline(` predeploy-check`) + chalk.dim(` scanning ${projectRoot}`));
|
|
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
|
-
if (
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const chalk = require('chalk');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const fs = require('fs');
|
|
6
|
+
|
|
7
|
+
// Dynamically load all check modules from /checks/
|
|
8
|
+
const checksDir = path.join(__dirname, 'checks');
|
|
9
|
+
const checkFiles = fs.readdirSync(checksDir)
|
|
10
|
+
.filter((f) => f.endsWith('.js'))
|
|
11
|
+
.sort();
|
|
12
|
+
|
|
13
|
+
const checks = checkFiles.map((f) => {
|
|
14
|
+
const mod = require(path.join(checksDir, f));
|
|
15
|
+
return {
|
|
16
|
+
name: mod.name || f.replace('.js', ''),
|
|
17
|
+
run: mod.run,
|
|
18
|
+
};
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
const STATUS_ICONS = {
|
|
22
|
+
pass: chalk.green('✅'),
|
|
23
|
+
warn: chalk.yellow('⚠️ '),
|
|
24
|
+
fail: chalk.red('❌'),
|
|
25
|
+
skip: chalk.gray('⏭️ '),
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const STATUS_COLORS = {
|
|
29
|
+
pass: chalk.green,
|
|
30
|
+
warn: chalk.yellow,
|
|
31
|
+
fail: chalk.red,
|
|
32
|
+
skip: chalk.gray,
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Format a single result line.
|
|
37
|
+
*/
|
|
38
|
+
function formatResult(result) {
|
|
39
|
+
const icon = STATUS_ICONS[result.status] || '?';
|
|
40
|
+
const color = STATUS_COLORS[result.status] || chalk.white;
|
|
41
|
+
const lines = [];
|
|
42
|
+
|
|
43
|
+
lines.push(`${icon} ${color.bold(result.message)}`);
|
|
44
|
+
|
|
45
|
+
if (result.details && result.details.length > 0) {
|
|
46
|
+
for (const detail of result.details) {
|
|
47
|
+
const loc = detail.file
|
|
48
|
+
? chalk.dim(` ${detail.file}${detail.line ? `:${detail.line}` : ''}`)
|
|
49
|
+
: '';
|
|
50
|
+
if (loc) lines.push(loc);
|
|
51
|
+
if (detail.message) lines.push(chalk.dim(` → ${detail.message}`));
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (result.fix && result.status !== 'pass') {
|
|
56
|
+
lines.push(chalk.cyan(` 💡 Fix: ${result.fix}`));
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return lines.join('\n');
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Run all checks against the given project root.
|
|
64
|
+
* Returns exit code: 1 if any ❌, 0 otherwise.
|
|
65
|
+
*/
|
|
66
|
+
async function runAllChecks(projectRoot, options = {}) {
|
|
67
|
+
console.log('');
|
|
68
|
+
console.log(chalk.bold.underline(` predeploy-check`) + chalk.dim(` scanning ${projectRoot}`));
|
|
69
|
+
if (options.live) {
|
|
70
|
+
if (typeof fetch === 'function') {
|
|
71
|
+
console.log(chalk.dim(' live mode: verifying wheel availability against PyPI (requires internet)'));
|
|
72
|
+
} else {
|
|
73
|
+
console.log(chalk.yellow(' live mode requested, but this Node.js version has no global fetch (needs Node 18+) — falling back to static checks'));
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
console.log(chalk.dim(' ─'.repeat(30)));
|
|
77
|
+
console.log('');
|
|
78
|
+
|
|
79
|
+
let hasFail = false;
|
|
80
|
+
let passCount = 0;
|
|
81
|
+
let warnCount = 0;
|
|
82
|
+
let failCount = 0;
|
|
83
|
+
let skipCount = 0;
|
|
84
|
+
|
|
85
|
+
for (const check of checks) {
|
|
86
|
+
try {
|
|
87
|
+
const results = await check.run(projectRoot, options);
|
|
88
|
+
|
|
89
|
+
// A check can return a single result or an array of results
|
|
90
|
+
const resultArray = Array.isArray(results) ? results : [results];
|
|
91
|
+
|
|
92
|
+
for (const result of resultArray) {
|
|
93
|
+
console.log(formatResult(result));
|
|
94
|
+
console.log('');
|
|
95
|
+
|
|
96
|
+
if (result.status === 'fail') {
|
|
97
|
+
hasFail = true;
|
|
98
|
+
failCount++;
|
|
99
|
+
} else if (result.status === 'warn') {
|
|
100
|
+
warnCount++;
|
|
101
|
+
} else if (result.status === 'skip') {
|
|
102
|
+
skipCount++;
|
|
103
|
+
} else {
|
|
104
|
+
passCount++;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
} catch (err) {
|
|
108
|
+
console.log(chalk.red(`❌ ${check.name}: internal error — ${err.message}`));
|
|
109
|
+
console.log('');
|
|
110
|
+
hasFail = true;
|
|
111
|
+
failCount++;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Summary bar
|
|
116
|
+
console.log(chalk.dim(' ─'.repeat(30)));
|
|
117
|
+
|
|
118
|
+
const parts = [];
|
|
119
|
+
if (passCount > 0) parts.push(chalk.green(`${passCount} passed`));
|
|
120
|
+
if (warnCount > 0) parts.push(chalk.yellow(`${warnCount} warnings`));
|
|
121
|
+
if (failCount > 0) parts.push(chalk.red(`${failCount} failed`));
|
|
122
|
+
if (skipCount > 0) parts.push(chalk.gray(`${skipCount} skipped`));
|
|
123
|
+
|
|
124
|
+
console.log(`\n ${chalk.bold('Summary:')} ${parts.join(chalk.dim(' · '))}`);
|
|
125
|
+
|
|
126
|
+
if (hasFail) {
|
|
127
|
+
console.log(chalk.red.bold('\n Deploy will likely fail. Fix ❌ issues above.\n'));
|
|
128
|
+
} else if (warnCount > 0) {
|
|
129
|
+
console.log(chalk.yellow('\n Some warnings detected. Review ⚠️ items above.\n'));
|
|
130
|
+
} else {
|
|
131
|
+
console.log(chalk.green.bold('\n All checks passed! You\'re good to deploy. 🚀\n'));
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return hasFail ? 1 : 0;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
module.exports = { runAllChecks };
|
package/package.json
CHANGED
|
@@ -1,37 +1,37 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "predeploy-check",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "Scan a project folder and flag known deployment-failure patterns for Render and Vercel before you push.",
|
|
5
|
-
"main": "index.js",
|
|
6
|
-
"bin": {
|
|
7
|
-
"predeploy-check": "bin/cli.js"
|
|
8
|
-
},
|
|
9
|
-
"scripts": {
|
|
10
|
-
"start": "node bin/cli.js",
|
|
11
|
-
"test": "node
|
|
12
|
-
},
|
|
13
|
-
"keywords": [
|
|
14
|
-
"deploy",
|
|
15
|
-
"vercel",
|
|
16
|
-
"render",
|
|
17
|
-
"lint",
|
|
18
|
-
"pre-deploy",
|
|
19
|
-
"ci",
|
|
20
|
-
"deployment",
|
|
21
|
-
"check"
|
|
22
|
-
],
|
|
23
|
-
"author": "",
|
|
24
|
-
"license": "MIT",
|
|
25
|
-
"dependencies": {
|
|
26
|
-
"chalk": "^4.1.2"
|
|
27
|
-
},
|
|
28
|
-
"engines": {
|
|
29
|
-
"node": ">=14.0.0"
|
|
30
|
-
},
|
|
31
|
-
"files": [
|
|
32
|
-
"bin/",
|
|
33
|
-
"checks/",
|
|
34
|
-
"index.js",
|
|
35
|
-
"README.md"
|
|
36
|
-
]
|
|
37
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "predeploy-check",
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "Scan a project folder and flag known deployment-failure patterns for Render and Vercel before you push.",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"predeploy-check": "bin/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"start": "node bin/cli.js",
|
|
11
|
+
"test": "node --test test/*.test.js"
|
|
12
|
+
},
|
|
13
|
+
"keywords": [
|
|
14
|
+
"deploy",
|
|
15
|
+
"vercel",
|
|
16
|
+
"render",
|
|
17
|
+
"lint",
|
|
18
|
+
"pre-deploy",
|
|
19
|
+
"ci",
|
|
20
|
+
"deployment",
|
|
21
|
+
"check"
|
|
22
|
+
],
|
|
23
|
+
"author": "",
|
|
24
|
+
"license": "MIT",
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"chalk": "^4.1.2"
|
|
27
|
+
},
|
|
28
|
+
"engines": {
|
|
29
|
+
"node": ">=14.0.0"
|
|
30
|
+
},
|
|
31
|
+
"files": [
|
|
32
|
+
"bin/",
|
|
33
|
+
"checks/",
|
|
34
|
+
"index.js",
|
|
35
|
+
"README.md"
|
|
36
|
+
]
|
|
37
|
+
}
|