mirror of https://github.com/nodejs/corepack.git
				
				
				
			fix: do not resolve fallback descriptor when `packageManager` is defined (#632)
This commit is contained in:
		
							parent
							
								
									b0c46078f1
								
							
						
					
					
						commit
						12e77e5069
					
				|  | @ -14,9 +14,9 @@ import * as folderUtils                                       from './folderUtil | |||
| import type {NodeError}                                       from './nodeUtils'; | ||||
| import * as semverUtils                                       from './semverUtils'; | ||||
| import * as specUtils                                         from './specUtils'; | ||||
| import {Config, Descriptor, Locator, PackageManagerSpec}      from './types'; | ||||
| import {Config, Descriptor, LazyLocator, Locator}             from './types'; | ||||
| import {SupportedPackageManagers, SupportedPackageManagerSet} from './types'; | ||||
| import {isSupportedPackageManager}                            from './types'; | ||||
| import {isSupportedPackageManager, PackageManagerSpec}        from './types'; | ||||
| 
 | ||||
| export type PreparedPackageManagerInfo = Awaited<ReturnType<Engine[`ensurePackageManager`]>>; | ||||
| 
 | ||||
|  | @ -244,12 +244,16 @@ export class Engine { | |||
|    * project using the default package managers, and configure it so that we | ||||
|    * don't need to ask again in the future. | ||||
|    */ | ||||
|   async findProjectSpec(initialCwd: string, locator: Locator, {transparent = false}: {transparent?: boolean} = {}): Promise<Descriptor> { | ||||
|   async findProjectSpec(initialCwd: string, locator: Locator | LazyLocator, {transparent = false}: {transparent?: boolean} = {}): Promise<Descriptor> { | ||||
|     // A locator is a valid descriptor (but not the other way around)
 | ||||
|     const fallbackDescriptor = {name: locator.name, range: `${locator.reference}`}; | ||||
| 
 | ||||
|     if (process.env.COREPACK_ENABLE_PROJECT_SPEC === `0`) | ||||
|     if (process.env.COREPACK_ENABLE_PROJECT_SPEC === `0`) { | ||||
|       if (typeof locator.reference === `function`) | ||||
|         fallbackDescriptor.range = await locator.reference(); | ||||
| 
 | ||||
|       return fallbackDescriptor; | ||||
|     } | ||||
| 
 | ||||
|     if (process.env.COREPACK_ENABLE_STRICT === `0`) | ||||
|       transparent = true; | ||||
|  | @ -258,11 +262,18 @@ export class Engine { | |||
|       const result = await specUtils.loadSpec(initialCwd); | ||||
| 
 | ||||
|       switch (result.type) { | ||||
|         case `NoProject`: | ||||
|         case `NoProject`: { | ||||
|           if (typeof locator.reference === `function`) | ||||
|             fallbackDescriptor.range = await locator.reference(); | ||||
| 
 | ||||
|           debugUtils.log(`Falling back to ${fallbackDescriptor.name}@${fallbackDescriptor.range} as no project manifest were found`); | ||||
|           return fallbackDescriptor; | ||||
|         } | ||||
| 
 | ||||
|         case `NoSpec`: { | ||||
|           if (typeof locator.reference === `function`) | ||||
|             fallbackDescriptor.range = await locator.reference(); | ||||
| 
 | ||||
|           if (process.env.COREPACK_ENABLE_AUTO_PIN !== `0`) { | ||||
|             const resolved = await this.resolveDescriptor(fallbackDescriptor, {allowTags: true}); | ||||
|             if (resolved === null) | ||||
|  | @ -284,6 +295,9 @@ export class Engine { | |||
|         case `Found`: { | ||||
|           if (result.spec.name !== locator.name) { | ||||
|             if (transparent) { | ||||
|               if (typeof locator.reference === `function`) | ||||
|                 fallbackDescriptor.range = await locator.reference(); | ||||
| 
 | ||||
|               debugUtils.log(`Falling back to ${fallbackDescriptor.name}@${fallbackDescriptor.range} in a ${result.spec.name}@${result.spec.range} project`); | ||||
|               return fallbackDescriptor; | ||||
|             } else { | ||||
|  | @ -299,14 +313,14 @@ export class Engine { | |||
|   } | ||||
| 
 | ||||
|   async executePackageManagerRequest({packageManager, binaryName, binaryVersion}: PackageManagerRequest, {cwd, args}: {cwd: string, args: Array<string>}): Promise<void> { | ||||
|     let fallbackLocator: Locator = { | ||||
|     let fallbackLocator: Locator | LazyLocator = { | ||||
|       name: binaryName as SupportedPackageManagers, | ||||
|       reference: undefined as any, | ||||
|     }; | ||||
| 
 | ||||
|     let isTransparentCommand = false; | ||||
|     if (packageManager != null) { | ||||
|       const defaultVersion = binaryVersion || await this.getDefaultVersion(packageManager); | ||||
|       const defaultVersion = binaryVersion || (() => this.getDefaultVersion(packageManager)); | ||||
|       const definition = this.config.definitions[packageManager]!; | ||||
| 
 | ||||
|       // If all leading segments match one of the patterns defined in the `transparent`
 | ||||
|  | @ -325,7 +339,7 @@ export class Engine { | |||
| 
 | ||||
|       fallbackLocator = { | ||||
|         name: packageManager, | ||||
|         reference: fallbackReference, | ||||
|         reference: fallbackReference as string, | ||||
|       }; | ||||
|     } | ||||
| 
 | ||||
|  |  | |||
|  | @ -145,3 +145,18 @@ export interface Locator { | |||
|      */ | ||||
|   reference: string; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * | ||||
|  */ | ||||
| export interface LazyLocator { | ||||
|   /** | ||||
|      * The name of the package manager required. | ||||
|      */ | ||||
|   name: string; | ||||
| 
 | ||||
|   /** | ||||
|      * The exact version required. | ||||
|      */ | ||||
|   reference: () => Promise<string>; | ||||
| } | ||||
|  |  | |||
|  | @ -497,15 +497,10 @@ describe(`read-only and offline environment`, () => { | |||
|         exitCode: 0, | ||||
|       }); | ||||
| 
 | ||||
|       // Let corepack discover the latest yarn version.
 | ||||
|       // BUG: This should not be necessary with a fully specified version in package.json plus populated corepack cache.
 | ||||
|       // Engine.executePackageManagerRequest needs to defer the fallback work. This requires a big refactoring.
 | ||||
|       await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ | ||||
|         exitCode: 0, | ||||
|       }); | ||||
| 
 | ||||
|       // Make COREPACK_HOME ro
 | ||||
|       const home = npath.toPortablePath(folderUtils.getCorepackHomeFolder()); | ||||
|       // Make a lastKnownGood.json file with not JSON-parsable content:
 | ||||
|       await xfs.writeFilePromise(ppath.join(home, `lastKnownGood.json`), `{`); | ||||
|       await xfs.chmodPromise(ppath.join(home, `lastKnownGood.json`), 0o444); | ||||
|       await xfs.chmodPromise(home, 0o555); | ||||
| 
 | ||||
|  | @ -967,54 +962,63 @@ for (const authType of [`COREPACK_NPM_REGISTRY`, `COREPACK_NPM_TOKEN`, `COREPACK | |||
| describe(`handle integrity checks`, () => { | ||||
|   beforeEach(() => { | ||||
|     process.env.AUTH_TYPE = `COREPACK_NPM_TOKEN`; // See `_registryServer.mjs`
 | ||||
|     process.env.COREPACK_DEFAULT_TO_LATEST = `1`; | ||||
|   }); | ||||
| 
 | ||||
|   it(`should return no error when signature matches`, async () => { | ||||
|     process.env.TEST_INTEGRITY = `valid`; // See `_registryServer.mjs`
 | ||||
| 
 | ||||
|     await xfs.mktempPromise(async cwd => { | ||||
|       await Promise.all([ | ||||
|         expect(runCli(cwd, [`pnpm`, `--version`], true)).resolves.toMatchObject({ | ||||
|           exitCode: 0, | ||||
|           stdout: `pnpm: Hello from custom registry\n`, | ||||
|           stderr: ``, | ||||
|         }), | ||||
|         expect(runCli(cwd, [`yarn@1.x`, `--version`], true)).resolves.toMatchObject({ | ||||
|           exitCode: 0, | ||||
|           stdout: `yarn: Hello from custom registry\n`, | ||||
|           stderr: ``, | ||||
|         }), | ||||
|         expect(runCli(cwd, [`yarn@5.x`, `--version`], true)).resolves.toMatchObject({ | ||||
|           exitCode: 0, | ||||
|           stdout: `yarn: Hello from custom registry\n`, | ||||
|           stderr: ``, | ||||
|         }), | ||||
|       ]); | ||||
|   describe(`when signature matches`, () => { | ||||
|     beforeEach(() => { | ||||
|       process.env.TEST_INTEGRITY = `valid`; // See `_registryServer.mjs`
 | ||||
|     }); | ||||
| 
 | ||||
|     it(`should return no error when calling 'corepack use'`, async () => { | ||||
|       await xfs.mktempPromise(async cwd => { | ||||
|       // Skip rest of the test on Windows & Node.js 18.x as it inevitably times out otherwise.
 | ||||
|       if (process.version.startsWith(`v18.`) && os.platform() === `win32`) return; | ||||
|         if (process.version.startsWith(`v18.`) && os.platform() === `win32`) return; | ||||
| 
 | ||||
|       // Removing home directory to force the "re-download"
 | ||||
|       await xfs.rmPromise(process.env.COREPACK_HOME as any, {recursive: true}); | ||||
|         // Removing home directory to force the "re-download"
 | ||||
|         await xfs.rmPromise(process.env.COREPACK_HOME as any, {recursive: true}); | ||||
| 
 | ||||
|       await Promise.all([ | ||||
|         expect(runCli(cwd, [`use`, `pnpm`], true)).resolves.toMatchObject({ | ||||
|           exitCode: 0, | ||||
|           stdout: `Installing pnpm@1.9998.9999 in the project...\n\npnpm: Hello from custom registry\n`, | ||||
|           stderr: ``, | ||||
|         }), | ||||
|         expect(runCli(cwd, [`use`, `yarn@1.x`], true)).resolves.toMatchObject({ | ||||
|           exitCode: 0, | ||||
|           stdout: `Installing yarn@1.9998.9999 in the project...\n\nyarn: Hello from custom registry\n`, | ||||
|           stderr: ``, | ||||
|         }), | ||||
|         expect(runCli(cwd, [`use`, `yarn@latest`], true)).resolves.toMatchObject({ | ||||
|           exitCode: 0, | ||||
|           stdout: `Installing yarn@5.9999.9999 in the project...\n\nyarn: Hello from custom registry\n`, | ||||
|           stderr: ``, | ||||
|         }), | ||||
|       ]); | ||||
|         await Promise.all([ | ||||
|           expect(runCli(cwd, [`use`, `pnpm`], true)).resolves.toMatchObject({ | ||||
|             exitCode: 0, | ||||
|             stdout: `Installing pnpm@1.9998.9999 in the project...\n\npnpm: Hello from custom registry\n`, | ||||
|             stderr: ``, | ||||
|           }), | ||||
|           expect(runCli(cwd, [`use`, `yarn@1.x`], true)).resolves.toMatchObject({ | ||||
|             exitCode: 0, | ||||
|             stdout: `Installing yarn@1.9998.9999 in the project...\n\nyarn: Hello from custom registry\n`, | ||||
|             stderr: ``, | ||||
|           }), | ||||
|           expect(runCli(cwd, [`use`, `yarn@latest`], true)).resolves.toMatchObject({ | ||||
|             exitCode: 0, | ||||
|             stdout: `Installing yarn@5.9999.9999 in the project...\n\nyarn: Hello from custom registry\n`, | ||||
|             stderr: ``, | ||||
|           }), | ||||
|         ]); | ||||
|       }); | ||||
|     }); | ||||
| 
 | ||||
| 
 | ||||
|     it(`should return no error when fetching latest version`, async () => { | ||||
|       process.env.COREPACK_DEFAULT_TO_LATEST = `1`; | ||||
|       await xfs.mktempPromise(async cwd => { | ||||
|         await Promise.all([ | ||||
|           expect(runCli(cwd, [`pnpm`, `--version`], true)).resolves.toMatchObject({ | ||||
|             exitCode: 0, | ||||
|             stdout: `pnpm: Hello from custom registry\n`, | ||||
|             stderr: ``, | ||||
|           }), | ||||
|           expect(runCli(cwd, [`yarn@1.x`, `--version`], true)).resolves.toMatchObject({ | ||||
|             exitCode: 0, | ||||
|             stdout: `yarn: Hello from custom registry\n`, | ||||
|             stderr: ``, | ||||
|           }), | ||||
|           expect(runCli(cwd, [`yarn@5.x`, `--version`], true)).resolves.toMatchObject({ | ||||
|             exitCode: 0, | ||||
|             stdout: `yarn: Hello from custom registry\n`, | ||||
|             stderr: ``, | ||||
|           }), | ||||
|         ]); | ||||
|       }); | ||||
|     }); | ||||
|   }); | ||||
|   it(`should return an error when signature does not match with a tag`, async () => { | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue