Skip to content

Commit 055b928

Browse files
authored
feat: download the latest version instead of a pinned one (#134)
Fixes: #93
1 parent af38d5a commit 055b928

File tree

6 files changed

+64
-9
lines changed

6 files changed

+64
-9
lines changed

README.md

+13-2
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,16 @@ Just use your package managers as you usually would. Run `yarn install` in Yarn
4646

4747
## Known Good Releases
4848

49-
When running Yarn or pnpm within projects that don't list a supported package manager, Corepack will default to a set of Known Good Releases. In a way, you can compare this to Node.js, where each version ships with a specific version of npm.
49+
When running Corepack within projects that don't list a supported package
50+
manager, it will default to a set of Known Good Releases. In a way, you can
51+
compare this to Node.js, where each version ships with a specific version of npm.
5052

51-
The Known Good Releases can be updated system-wide using the `--activate` flag from the `corepack prepare` and `corepack hydrate` commands.
53+
If there is no Known Good Release for the requested package manager, Corepack
54+
looks up the npm registry for the latest available version and cache it for
55+
future use.
56+
57+
The Known Good Releases can be updated system-wide using the `--activate` flag
58+
from the `corepack prepare` and `corepack hydrate` commands.
5259

5360
## Offline Workflow
5461

@@ -106,6 +113,10 @@ This command will retrieve the given package manager from the specified archive
106113

107114
- `COREPACK_ENABLE_NETWORK` can be set to `0` to prevent Corepack from accessing the network (in which case you'll be responsible for hydrating the package manager versions that will be required for the projects you'll run, using `corepack hydrate`).
108115

116+
- `COREPACK_DEFAULT_TO_LATEST` can be set to `0` in order to instruct Corepack
117+
not to lookup on the remote registry for the latest version of the selected
118+
package manager.
119+
109120
- `COREPACK_HOME` can be set in order to define where Corepack should install
110121
the package managers. By default it is set to `%LOCALAPPDATA%\node\corepack`
111122
on Windows, and to `$HOME/.cache/node/corepack` everywhere else.

config.json

+12
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22
"definitions": {
33
"npm": {
44
"default": "8.18.0+sha1.bd6ca7f637720441f812370363e2ae67426fb42f",
5+
"fetchLatestFrom": {
6+
"type": "npm",
7+
"package": "npm"
8+
},
59
"transparent": {
610
"commands": [
711
[
@@ -29,6 +33,10 @@
2933
},
3034
"pnpm": {
3135
"default": "7.9.3+sha1.843f76d13dbfa9f6dfb5135d6fbaa8b99facacc9",
36+
"fetchLatestFrom": {
37+
"type": "npm",
38+
"package": "pnpm"
39+
},
3240
"transparent": {
3341
"commands": [
3442
[
@@ -71,6 +79,10 @@
7179
},
7280
"yarn": {
7381
"default": "1.22.19+sha1.4ba7fc5c6e704fce2066ecbfb0b0d8976fe62447",
82+
"fetchLatestFrom": {
83+
"type": "npm",
84+
"package": "yarn"
85+
},
7486
"transparent": {
7587
"default": "3.2.2+sha224.634d0331703700cabfa9d9389835bd8f7426b0207ed6b74d8d34c81e",
7688
"commands": [

sources/Engine.ts

+16-7
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import {UsageError} from 'clipanion';
22
import fs from 'fs';
33
import path from 'path';
4+
import process from 'process';
45
import semver from 'semver';
56

67
import defaultConfig from '../config.json';
@@ -69,17 +70,25 @@ export class Engine {
6970
// Ignore errors; too bad
7071
}
7172

72-
if (typeof lastKnownGood !== `object` || lastKnownGood === null)
73-
return definition.default;
73+
if (typeof lastKnownGood === `object` && lastKnownGood !== null &&
74+
Object.prototype.hasOwnProperty.call(lastKnownGood, packageManager)) {
75+
const override = (lastKnownGood as any)[packageManager];
76+
if (typeof override === `string`) {
77+
return override;
78+
}
79+
}
7480

75-
if (!Object.prototype.hasOwnProperty.call(lastKnownGood, packageManager))
81+
if (process.env.COREPACK_DEFAULT_TO_LATEST === `0`)
7682
return definition.default;
7783

78-
const override = (lastKnownGood as any)[packageManager];
79-
if (typeof override !== `string`)
80-
return definition.default;
84+
const reference = await corepackUtils.fetchLatestStableVersion(definition.fetchLatestFrom);
85+
86+
await this.activatePackageManager({
87+
name: packageManager,
88+
reference,
89+
});
8190

82-
return override;
91+
return reference;
8392
}
8493

8594
async activatePackageManager(locator: Locator) {

sources/corepackUtils.ts

+17
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,23 @@ import * as httpUtils from './httpUtils
1212
import * as nodeUtils from './nodeUtils';
1313
import {RegistrySpec, Descriptor, Locator, PackageManagerSpec} from './types';
1414

15+
export async function fetchLatestStableVersion(spec: RegistrySpec) {
16+
switch (spec.type) {
17+
case `npm`: {
18+
const {[`dist-tags`]: {latest}, versions: {[latest]: {dist: {shasum}}}} =
19+
await httpUtils.fetchAsJson(`https://registry.npmjs.org/${spec.package}`);
20+
return `${latest}+sha1.${shasum}`;
21+
}
22+
case `url`: {
23+
const data = await httpUtils.fetchAsJson(spec.url);
24+
return data[spec.fields.tags].stable;
25+
}
26+
default: {
27+
throw new Error(`Unsupported specification ${JSON.stringify(spec)}`);
28+
}
29+
}
30+
}
31+
1532
export async function fetchAvailableTags(spec: RegistrySpec): Promise<Record<string, string>> {
1633
switch (spec.type) {
1734
case `npm`: {

sources/types.ts

+5
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,11 @@ export interface Config {
6262
*/
6363
default: string;
6464

65+
/**
66+
* Defines how to fetch the latest version from a remote registry.
67+
*/
68+
fetchLatestFrom: RegistrySpec;
69+
6570
/**
6671
* Defines a set of commands that are fine to run even if the user isn't
6772
* in a project configured for the specified package manager. For instance,

tests/main.test.ts

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {runCli} from './_runCli';
66

77
beforeEach(async () => {
88
process.env.COREPACK_HOME = npath.fromPortablePath(await xfs.mktempPromise());
9+
process.env.COREPACK_DEFAULT_TO_LATEST = `0`;
910
});
1011

1112
it(`should refuse to download a package manager if the hash doesn't match`, async () => {

0 commit comments

Comments
 (0)