mirror of
https://github.com/renovatebot/renovate.git
synced 2026-10-25 23:11:31 +00:00
4220c0fe36
* refactor(manager): share the .npmrc host-rule wrapper between bun, deno and npm Adds `withNpmrcHostRules()` to the npm manager utils: it injects the host-rule lines into a directory's `.npmrc`, runs the callback, and restores the original `.npmrc` from a `finally` block. bun, deno, the corepack `updateArtifacts()` and the three lock file loops in `post-update/index.ts` now share it instead of repeating getNpmrcContent / updateNpmrcContent / resetNpmrcContent. Adds `readUpdatedBinaryLockFile()` to the shared manager utils for the `Buffer.compare` plus file-addition block that bun and deno both carried. Behaviour changes: - bun and deno now restore `.npmrc` when `exec()` throws. The reset previously ran only after a successful install, so a failed lock file update left the injected registry credentials in the working tree. Covered by "restores .npmrc when the install fails" in `bun/artifacts.spec.ts` and `deno/artifacts.spec.ts`. - The npm, yarn and pnpm loops in `post-update/index.ts` now restore `.npmrc` when the loop body throws an `ExternalHostError`, for the same reason. - deno reads `config.isLockFileMaintenance` instead of deriving the flag from `config.updateType === 'lockFileMaintenance'`. Grouped branches overwrite `updateType` while `isLockFileMaintenance` is set explicitly, so the flag is the reliable source. The deno specs were updated to set it. * refactor(manager): let updateLockFile() compare binary lock files A Buffer as the existing content makes the skeleton read, compare and return the new lock file as bytes, so bun and deno use it instead of a separate readUpdatedBinaryLockFile() helper. * refactor(manager/devbox): update the lock file through updateLockFile() devbox kept the same Buffer compare as bun and deno; the trace log before returning the lock file goes away with it. * fix(manager/devbox): type the command list explicitly The list is now only read inside the run() closure, where TypeScript cannot resolve an evolving array type, so tsc reported an implicit any.
115 lines
3.4 KiB
TypeScript
115 lines
3.4 KiB
TypeScript
import detectIndent from 'detect-indent';
|
|
import upath from 'upath';
|
|
import { logger } from '../../../logger/index.ts';
|
|
import {
|
|
deleteLocalFile,
|
|
readLocalFile,
|
|
writeLocalFile,
|
|
} from '../../../util/fs/index.ts';
|
|
|
|
import { PackageJson } from './schema.ts';
|
|
import type { LockFile, ParseLockFileResult } from './types.ts';
|
|
|
|
export function parseLockFile(lockFile: string): ParseLockFileResult {
|
|
const detectedIndent = detectIndent(lockFile).indent || ' ';
|
|
|
|
let lockFileParsed: LockFile | undefined;
|
|
try {
|
|
lockFileParsed = JSON.parse(lockFile);
|
|
} catch (err) {
|
|
logger.warn({ err }, 'Error parsing npm lock file');
|
|
}
|
|
|
|
return { detectedIndent, lockFileParsed };
|
|
}
|
|
|
|
export function composeLockFile(lockFile: LockFile, indent: string): string {
|
|
return `${JSON.stringify(lockFile, null, indent)}\n`;
|
|
}
|
|
|
|
export async function getNpmrcContent(dir: string): Promise<string | null> {
|
|
const npmrcFilePath = upath.join(dir, '.npmrc');
|
|
let originalNpmrcContent: string | null = null;
|
|
try {
|
|
originalNpmrcContent = await readLocalFile(npmrcFilePath, 'utf8');
|
|
} catch {
|
|
/* v8 ignore next -- needs test */
|
|
originalNpmrcContent = null;
|
|
}
|
|
if (originalNpmrcContent) {
|
|
logger.debug(`npmrc file ${npmrcFilePath} found in repository`);
|
|
}
|
|
return originalNpmrcContent;
|
|
}
|
|
|
|
export async function updateNpmrcContent(
|
|
dir: string,
|
|
originalContent: string | null,
|
|
additionalLines: string[],
|
|
): Promise<void> {
|
|
const npmrcFilePath = upath.join(dir, '.npmrc');
|
|
const newNpmrc = originalContent
|
|
? [originalContent, ...additionalLines]
|
|
: additionalLines;
|
|
try {
|
|
const newContent = newNpmrc.length ? newNpmrc.join('\n') : null;
|
|
if (newContent !== originalContent) {
|
|
logger.debug(`Writing updated .npmrc file to ${npmrcFilePath}`);
|
|
await writeLocalFile(npmrcFilePath, `${newContent}\n`);
|
|
}
|
|
} catch /* v8 ignore next -- TODO: add test #40625 */ {
|
|
logger.warn('Unable to write custom npmrc file');
|
|
}
|
|
}
|
|
|
|
export async function resetNpmrcContent(
|
|
dir: string,
|
|
originalContent: string | null,
|
|
): Promise<void> {
|
|
const npmrcFilePath = upath.join(dir, '.npmrc');
|
|
if (originalContent) {
|
|
try {
|
|
await writeLocalFile(npmrcFilePath, originalContent);
|
|
} catch /* v8 ignore next -- TODO: add test #40625 */ {
|
|
logger.warn('Unable to reset npmrc to original contents');
|
|
}
|
|
} else {
|
|
try {
|
|
await deleteLocalFile(npmrcFilePath);
|
|
} catch /* v8 ignore next -- TODO: add test #40625 */ {
|
|
logger.warn('Unable to delete custom npmrc');
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Add the host-rule lines to the `.npmrc` in `dir`, run `fn`, and restore the original `.npmrc` afterwards.
|
|
*
|
|
* The restore runs in a `finally`, so a package manager that throws cannot leave the injected credentials behind in the working tree.
|
|
*/
|
|
export async function withNpmrcHostRules<T>(
|
|
dir: string,
|
|
additionalLines: string[],
|
|
fn: (originalNpmrcContent: string | null) => Promise<T>,
|
|
): Promise<T> {
|
|
const originalContent = await getNpmrcContent(dir);
|
|
await updateNpmrcContent(dir, originalContent, additionalLines);
|
|
try {
|
|
return await fn(originalContent);
|
|
} finally {
|
|
await resetNpmrcContent(dir, originalContent);
|
|
}
|
|
}
|
|
|
|
export async function loadPackageJson(parentDir: string): Promise<PackageJson> {
|
|
const json = await readLocalFile(
|
|
upath.join(parentDir, 'package.json'),
|
|
'utf8',
|
|
);
|
|
const res = PackageJson.safeParse(json);
|
|
if (res.success) {
|
|
return res.data;
|
|
}
|
|
return {};
|
|
}
|