feat: minimum age
Node.js CI / CI (push) Failing after 8s
Security Scan and Upload / Security & DefectDojo Upload (push) Successful in 57s

This commit is contained in:
2026-02-03 18:58:40 -08:00
parent efac4cf32b
commit bc572cdf76
5 changed files with 190 additions and 7 deletions
+10 -2
View File
@@ -6,7 +6,7 @@
import { Logger } from "@nhcarrigan/logger";
import semver from "semver";
import type { NpmService } from "./npmService.js";
import { NpmService } from "./npmService.js";
import type {
DependencyType,
DependencyUpdate,
@@ -151,7 +151,15 @@ class DependencyAnalyzerService {
return null;
}
const latestVersion = packageInfo["dist-tags"].latest;
// Use mature version (at least 10 days old) instead of dist-tags.latest
const latestVersion = NpmService.getLatestMatureVersion(
packageInfo,
10,
);
if (latestVersion === null) {
return null;
}
const cleanCurrentVersion = cleanVersion(currentVersion);
if (shouldUpdate(cleanCurrentVersion, latestVersion)) {
+38
View File
@@ -148,6 +148,44 @@ class NpmService {
});
}
/**
* Gets the latest version that is at least minimumAgeDays old.
* @param packageInfo - The package information from npm.
* @param minimumAgeDays - Minimum days since publication (default 10).
* @returns The latest mature version, or null if none found.
*/
public static getLatestMatureVersion(
packageInfo: NpmPackageInfo,
minimumAgeDays = 10,
): string | null {
const now = Date.now();
const minimumAgeMs = minimumAgeDays * 24 * 60 * 60 * 1000;
const cutoffDate = now - minimumAgeMs;
const versions = Object.keys(packageInfo.versions);
const matureVersions = versions.filter((version) => {
const publishedAt = packageInfo.time[version];
if (publishedAt === undefined) {
return false;
}
const publishedDate = new Date(publishedAt).getTime();
return publishedDate <= cutoffDate;
});
if (matureVersions.length === 0) {
return null;
}
// Sort by semver (descending) to get the latest mature version
matureVersions.sort((version1, version2) => {
return version2.localeCompare(version1, undefined, { numeric: true });
});
// eslint-disable-next-line capitalized-comments -- v8 coverage ignore directive must be lowercase
/* v8 ignore next -- @preserve */
return matureVersions[0] ?? null;
}
/**
* Fetches changelog information for a package update.
* @param options - The changelog fetch options.