implement pnpm migration (#22262)

### What does this PR do?

fixes #7157, fixes #14662

migrates pnpm-workspace.yaml data to package.json & converts
pnpm-lock.yml to bun.lock

---

### How did you verify your code works?

manually, tests and real world examples

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Dylan Conway <dylan.conway567@gmail.com>
This commit is contained in:
Michael H
2025-09-27 17:45:29 +10:00
committed by GitHub
parent 8c9c7894d6
commit ba20670da3
53 changed files with 5864 additions and 396 deletions

View File

@@ -261,7 +261,7 @@ export function tempDirWithFiles(
basename: string,
filesOrAbsolutePathToCopyFolderFrom: DirectoryTree | string,
): string {
const base = fs.mkdtempSync(join(fs.realpathSync(os.tmpdir()), basename + "_"));
const base = fs.mkdtempSync(join(fs.realpathSync.native(os.tmpdir()), basename + "_"));
makeTreeSync(base, filesOrAbsolutePathToCopyFolderFrom);
return base;
}
@@ -278,10 +278,10 @@ class DisposableString extends String {
export function tempDir(
basename: string,
filesOrAbsolutePathToCopyFolderFrom: DirectoryTree | string,
): DisposableString {
): string & DisposableString & AsyncDisposable {
const base = tempDirWithFiles(basename, filesOrAbsolutePathToCopyFolderFrom);
return new DisposableString(base);
return new DisposableString(base) as string & DisposableString & AsyncDisposable;
}
export function tempDirWithFilesAnon(filesOrAbsolutePathToCopyFolderFrom: DirectoryTree | string): string {
@@ -1722,14 +1722,16 @@ export class VerdaccioRegistry {
`;
}
async createTestDir(bunfigOpts: BunfigOpts = {}) {
async createTestDir(
opts: { bunfigOpts?: BunfigOpts; files?: DirectoryTree | string } = { bunfigOpts: {}, files: {} },
) {
await rm(join(dirname(this.configPath), "htpasswd"), { force: true });
await rm(join(this.packagesPath, "private-pkg-dont-touch"), { force: true });
const packageDir = tmpdirSync();
const packageDir = tempDir("verdaccio-test-", opts.files ?? {});
const packageJson = join(packageDir, "package.json");
await this.writeBunfig(packageDir, bunfigOpts);
await this.writeBunfig(packageDir, opts.bunfigOpts);
this.users = {};
return { packageDir, packageJson };
return { packageDir: String(packageDir), packageJson };
}
async writeBunfig(dir: string, opts: BunfigOpts = {}) {
@@ -1836,3 +1838,52 @@ export function normalizeBunSnapshot(snapshot: string, optionalDir?: string) {
.trim()
);
}
export function nodeModulesPackages(nodeModulesPath: string): string {
const packages: string[] = [];
function scanDirectory(dir: string, relativePath: string = "") {
try {
const entries = fs.readdirSync(dir, { withFileTypes: true });
for (const entry of entries) {
const fullPath = join(dir, entry.name);
if (entry.isDirectory()) {
if (entry.name === ".bun-cache") {
// Skip .bun-cache directories
continue;
}
const newRelativePath = relativePath ? `${relativePath}/${entry.name}` : entry.name;
// Check if this directory contains a package.json
const packageJsonPath = join(fullPath, "package.json");
if (fs.existsSync(packageJsonPath)) {
try {
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
const name = packageJson.name || "unknown";
const version = packageJson.version || "unknown";
packages.push(`${newRelativePath}/${name}@${version}`);
} catch {
// If package.json is invalid, still include the path
packages.push(`${newRelativePath}/[invalid-package.json]`);
}
}
// Recursively scan subdirectories (including nested node_modules)
scanDirectory(fullPath, newRelativePath);
}
}
} catch (err) {
// Ignore errors for directories we can't read
}
}
scanDirectory(nodeModulesPath);
// Sort the packages alphabetically
packages.sort();
return packages.join("\n");
}