eol-check
Version:
CLI tool to check End-of-Life (EOL) status of Node.js, package managers, operating systems, dependencies, and databases. Supports HTML reports and GitHub Actions.
221 lines (220 loc) • 10.2 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const commander_1 = require("commander");
const chalk_1 = __importDefault(require("chalk"));
const open_1 = __importDefault(require("open"));
const scannerEngine_1 = require("./scanners/scannerEngine");
const endoflifeApi_1 = require("./core/endoflifeApi");
const evaluator_1 = require("./core/evaluator");
const dependencyScanner_1 = require("./scanners/dependencyScanner");
const productMapper_1 = require("./core/productMapper");
const htmlReporter_1 = require("./reporters/htmlReporter");
const program = new commander_1.Command();
program
.name('eol-check')
.description('Check End of Life (EOL) status of your development environment and project dependencies')
.version('1.4.3')
.option('--json', 'Output results as JSON')
.option('--html <filename>', 'Generate HTML report to specified file')
.option('--no-browser', 'Do not open HTML report in browser')
.option('--verbose', 'Show verbose output')
.option('--refresh-cache', 'Force refresh cache from API')
.action(async (cmdOptions) => {
try {
await main(cmdOptions);
}
catch (err) {
console.error(chalk_1.default.red('Error running eol-check:'), err);
process.exit(1);
}
});
program
.command('query')
.description('Query EOL status for a specific product')
.argument('<product>', 'Product name (e.g. nodejs, python, ubuntu)')
.argument('[version]', 'Specific version to check')
.option('--refresh-cache', 'Force refresh cache from API')
.action(async (product, version, cmdOptions) => {
try {
const data = await (0, endoflifeApi_1.fetchEolData)(product, cmdOptions.refreshCache);
if (version) {
const result = (0, evaluator_1.evaluateVersion)(product, version, data);
let color = chalk_1.default.green;
if (result.status === evaluator_1.Status.WARN)
color = chalk_1.default.yellow;
if (result.status === evaluator_1.Status.ERR)
color = chalk_1.default.red;
console.log(`${color(`[${result.status}]`)} ${chalk_1.default.bold(result.component)} ${result.version} - ${result.message}`);
}
else {
console.log(chalk_1.default.bold(`EOL Data for ${product}:`));
console.table(data.map((release) => ({
Cycle: release.cycle,
'Release Date': release.releaseDate,
'EOL Date': release.eol,
'LTS': release.lts,
})));
}
}
catch (error) {
const errorMsg = error instanceof Error ? error.message : String(error);
console.error(chalk_1.default.red('\n✗ Failed to fetch EOL data'));
console.error(chalk_1.default.yellow(`Product: ${chalk_1.default.bold(product)}`));
if (errorMsg.includes('404') || errorMsg.includes('Not Found')) {
console.error(chalk_1.default.gray(`\nThe product "${product}" was not found on endoflife.date.`));
console.error(chalk_1.default.gray('Please check the product name and try again.'));
console.error(chalk_1.default.gray(`\nSearch for available products at: ${chalk_1.default.cyan('https://endoflife.date/api/all.json')}`));
}
else {
console.error(chalk_1.default.gray(`\nError: ${errorMsg}`));
}
}
process.exit(0);
});
program.parse(process.argv);
async function main(options) {
if (options.verbose) {
console.log(chalk_1.default.blue('Scanning environment...'));
}
const scanResult = (0, scannerEngine_1.scanEnvironment)();
const results = [];
// Check Node.js
if (scanResult.nodeVersion) {
if (options.verbose)
console.log(`Checking Node.js ${scanResult.nodeVersion}...`);
const nodeData = await (0, endoflifeApi_1.fetchEolData)('nodejs', options.refreshCache);
const result = (0, evaluator_1.evaluateVersion)('Node.js', scanResult.nodeVersion, nodeData);
result.category = evaluator_1.Category.RUNTIME;
results.push(result);
}
// Check OS (if detected)
if (scanResult.os && scanResult.os !== 'Unknown') {
// Note: OS matching is tricky with endoflife.date as they have specific slugs like 'ubuntu', 'alpine'.
// For now, we'll try to map common ones or skip if unsure.
// This is a simplified implementation for the prototype.
const osLower = scanResult.os.toLowerCase();
let product = '';
if (osLower.includes('ubuntu'))
product = 'ubuntu';
else if (osLower.includes('alpine'))
product = 'alpine';
else if (osLower.includes('debian'))
product = 'debian';
if (product) {
if (options.verbose)
console.log(`Checking OS ${scanResult.os} (mapped to ${product})...`);
try {
const osData = await (0, endoflifeApi_1.fetchEolData)(product, options.refreshCache);
// Extract version from string like "Ubuntu 22.04.5 LTS" -> "22.04"
const versionMatch = scanResult.os.match(/(\d+(\.\d+)?)/);
if (versionMatch) {
const result = (0, evaluator_1.evaluateVersion)(scanResult.os, versionMatch[0], osData);
result.category = evaluator_1.Category.OS;
results.push(result);
}
}
catch (error) {
if (options.verbose) {
console.warn(chalk_1.default.yellow(`Warning: Could not fetch EOL data for OS ${scanResult.os}: ${error}`));
}
}
}
}
// Check System Services
if (scanResult.services.length > 0) {
if (options.verbose)
console.log('Checking system services...');
for (const service of scanResult.services) {
if (options.verbose)
console.log(`Checking service ${service.name} (${service.version})...`);
try {
const eolData = await (0, endoflifeApi_1.fetchEolData)(service.product, options.refreshCache);
if (eolData && eolData.length > 0) {
const result = (0, evaluator_1.evaluateVersion)(service.name, service.version, eolData);
result.category = evaluator_1.Category.SERVICE;
results.push(result);
}
}
catch (error) {
if (options.verbose) {
console.warn(chalk_1.default.yellow(`Warning: Could not fetch EOL data for ${service.name} (${service.product}): ${error}`));
}
}
}
}
// Check Project Dependencies
if (options.verbose)
console.log('Scanning project dependencies...');
const dependencies = (0, dependencyScanner_1.scanDependencies)(process.cwd());
for (const dep of dependencies) {
const product = (0, productMapper_1.mapPackageToProduct)(dep.name);
if (product) {
if (options.verbose)
console.log(`Checking dependency ${dep.name} (mapped to ${product})...`);
try {
const eolData = await (0, endoflifeApi_1.fetchEolData)(product, options.refreshCache);
if (eolData && eolData.length > 0) {
const version = (0, dependencyScanner_1.cleanVersion)(dep.version);
const result = (0, evaluator_1.evaluateVersion)(dep.name, version, eolData);
result.category = evaluator_1.Category.DEPENDENCY;
results.push(result);
}
}
catch (error) {
if (options.verbose) {
console.warn(chalk_1.default.yellow(`Warning: Could not fetch EOL data for ${dep.name}: ${error}`));
}
else {
console.warn(chalk_1.default.yellow(`Warning: Could not fetch EOL data for ${dep.name} (mapped to ${product}). Skipping...`));
}
}
}
}
// Generate HTML report if requested
if (options.html) {
try {
(0, htmlReporter_1.generateHtmlReport)(results, options.html);
console.log(chalk_1.default.green(`\n✓ HTML report generated: ${options.html}`));
if (options.browser !== false) {
await (0, open_1.default)(options.html);
if (options.verbose)
console.log('Opening report in default browser...');
}
}
catch (error) {
console.error(chalk_1.default.red(`Failed to generate HTML report: ${error}`));
}
}
if (options.json) {
console.log(JSON.stringify(results, null, 2));
}
else {
console.log(chalk_1.default.bold('\nEOL Check Results:'));
let hasError = false;
// Group results by category
const categories = [evaluator_1.Category.RUNTIME, evaluator_1.Category.OS, evaluator_1.Category.SERVICE, evaluator_1.Category.DEPENDENCY];
for (const category of categories) {
const categoryResults = results.filter((r) => r.category === category);
if (categoryResults.length === 0)
continue;
console.log(chalk_1.default.cyan(`\n── ${category} ──`));
categoryResults.forEach((res) => {
let color = chalk_1.default.green;
if (res.status === evaluator_1.Status.WARN)
color = chalk_1.default.yellow;
if (res.status === evaluator_1.Status.ERR) {
color = chalk_1.default.red;
hasError = true;
}
console.log(`${color(`[${res.status}]`)} ${chalk_1.default.bold(res.component)} ${res.version} - ${res.message}`);
});
}
if (hasError) {
process.exit(1);
}
}
}