mirror of
https://github.com/renovatebot/renovate.git
synced 2026-11-01 10:09:50 +00:00
716baf630b
* feat(lint): add renovate/prefer-fs-util and renovate/prefer-luxon rules Two shared-util substitution rules, both at warn level: - renovate/prefer-fs-util flags value imports of fs, node:fs, fs/promises, node:fs/promises, fs-extra and fs-extra/esm in lib/ source files outside lib/util/fs/, pointing to the scoped helpers from lib/util/fs. Spec files and type-only imports are exempt. A config-only change via no-restricted-imports was considered but rejected: that rule is at error severity globally and per-path warn severity is not expressible, so the 13 existing call sites would break the baseline. - renovate/prefer-luxon flags new Date(...) and Date.now() in lib/ source files, pointing to Luxon per best-practices. Date/time utility modules (lib/util/date, lib/util/pretty-time, lib/util/timestamp) and spec files (vi.setSystemTime etc.) are exempt. Baseline: 13 prefer-fs-util and 45 prefer-luxon warnings, zero errors. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * refactor: use Luxon instead of new Date() at remaining call sites Fixes all renovate/prefer-luxon violations for `new Date(...)`: - `new Date().toISOString()` -> `DateTime.utc().toISO()` (byte-identical output) in the http cache provider, schedule logging and PR cache. - `new Date()` -> `DateTime.now().toJSDate()` for the git commit-date fallback and the rubygems `syncedAt` markers (same `Date` values). - rust-release-channel now computes the Rust 1.0 release date and nightly version dates via `DateTime.utc(...)`; previously `new Date(y, m, d)` used the local timezone while the epoch used UTC, so the comparison was timezone-dependent at the boundary date. Tests run with TZ=UTC, where behavior is unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * refactor: use lib/util/fs helpers in repository worker Fixes renovate/prefer-fs-util violations outside bootstrap code: - `fs.ensureDir()` -> `ensureDir()` from lib/util/fs (same fs-extra call underneath; it no-ops on an empty dir name, so the repository worker spec now simulates the init failure via a rejected `initRepo` instead of relying on `fs.ensureDir('')` throwing). - `fs.remove(privateCacheDir())` -> `cachePathExists()` + `rmCache()`, keeping the remove-if-present semantics while asserting cacheDir containment. Two call sites keep raw imports with reasoned disable comments: - lib/util/modules.ts synchronously enumerates Renovate's own installed module directories at import time. - lib/util/cache/package/impl/sqlite.ts receives cacheDir as an explicit argument during global initialization, before GlobalConfig (which the scoped cache helpers resolve against) contains cacheDir. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(lint): promote prefer-fs-util and prefer-luxon to error Both rules are narrowed to what is actually accepted practice before being promoted: prefer-luxon no longer flags `Date.now()`: it returns UTC-based epoch milliseconds used for elapsed-time measurement and TTL arithmetic, which is timezone-independent by construction. The mined reviewer feedback behind this rule ("use Luxon for date arithmetic outside util") targets timezone-dependent date construction/formatting, which cannot occur with a raw millis number; the rule keeps flagging `new Date(...)`. prefer-fs-util exempts code that legitimately needs raw fs access because the scoped lib/util/fs helpers resolve against GlobalConfig localDir/cacheDir, which does not exist yet or does not apply there: - lib/logger/: log-file streams at user-configured system paths during bootstrap; lib/util/fs also depends on the logger (import cycle). - lib/workers/global/: creates baseDir/cacheDir themselves and reads/writes user-supplied paths before GlobalConfig is seeded. - lib/config-validator.ts: standalone CLI without GlobalConfig. - lib/util/git/: owns the localDir lifecycle (clone, emptyDir, symlinks) and private-key files with sync cleanup on process exit. Also fixes a pre-existing tsc error in prefer-fs-util.js: `importKind` is a TypeScript-ESTree extension missing from eslint's base AST types. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * refactor(fs): make rmCache ignore missing paths All rmCache callers use it for cleanup, where a missing path is a no-op, so bake force: true in instead of guarding call sites with an existence check. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * refactor(linters): exempt lib/instrumentation from prefer-fs-util `lib/instrumentation/file-exporter.ts` landed on main while this branch was open and imports `node:fs/promises` directly. The exporter writes to a user-configured system path (`RENOVATE_TRACING_FILE_EXPORTER_PATH`) outside `localDir`/`cacheDir`, so the scoped helpers do not apply. `lib/instrumentation` is also deliberately kept out of the module graph of instrumented libraries (see the `⚠️` note in `lib/renovate.ts`), so it must not pull in `lib/util/fs` and its config/logger dependencies. Exempt the directory, as is already done for `lib/logger`. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * docs: shorten doc --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
51 lines
1.3 KiB
TypeScript
51 lines
1.3 KiB
TypeScript
import { DateTime } from 'luxon';
|
|
import { logger } from '../../../../logger/index.ts';
|
|
import { getCache } from '../../../../util/cache/repository/index.ts';
|
|
import type { PrCache } from '../../../../util/cache/repository/types.ts';
|
|
|
|
export function getPrCache(branchName: string): PrCache | null {
|
|
logger.trace(`getPrCache()`);
|
|
const cache = getCache();
|
|
const branch = cache.branches?.find(
|
|
(branch) => branchName === branch.branchName,
|
|
);
|
|
|
|
const prCache = branch?.prCache;
|
|
if (!prCache) {
|
|
return null;
|
|
}
|
|
|
|
// istanbul ignore if
|
|
if (prCache.fingerprint) {
|
|
prCache.bodyFingerprint = prCache.fingerprint;
|
|
delete prCache.fingerprint;
|
|
}
|
|
|
|
return prCache;
|
|
}
|
|
|
|
// store the time a PR was last updated
|
|
export function setPrCache(
|
|
branchName: string,
|
|
bodyFingerprint: string,
|
|
prModified: boolean,
|
|
): void {
|
|
logger.debug(`setPrCache()`);
|
|
const cache = getCache();
|
|
const branch = cache.branches?.find(
|
|
(branch) => branchName === branch.branchName,
|
|
);
|
|
|
|
if (!branch) {
|
|
logger.debug(`setPrCache(): Branch cache not present`);
|
|
return;
|
|
}
|
|
|
|
const lastEdited = branch.prCache?.lastEdited;
|
|
branch.prCache = {
|
|
bodyFingerprint,
|
|
// update time when creating new cache or when pr was modified
|
|
lastEdited: lastEdited && !prModified ? lastEdited : DateTime.utc().toISO(),
|
|
};
|
|
}
|