Skip to content

Commit

Permalink
feat: download the latest version instead of a pinned one (#134)
Browse files Browse the repository at this point in the history
Fixes: #93
  • Loading branch information
aduh95 committed Aug 19, 2022
1 parent af38d5a commit 055b928
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 9 deletions.
15 changes: 13 additions & 2 deletions README.md
Expand Up @@ -46,9 +46,16 @@ Just use your package managers as you usually would. Run `yarn install` in Yarn

## Known Good Releases

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.
When running Corepack within projects that don't list a supported package
manager, it 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.

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

The Known Good Releases can be updated system-wide using the `--activate` flag
from the `corepack prepare` and `corepack hydrate` commands.

## Offline Workflow

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

- `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`).

- `COREPACK_DEFAULT_TO_LATEST` can be set to `0` in order to instruct Corepack
not to lookup on the remote registry for the latest version of the selected
package manager.

- `COREPACK_HOME` can be set in order to define where Corepack should install
the package managers. By default it is set to `%LOCALAPPDATA%\node\corepack`
on Windows, and to `$HOME/.cache/node/corepack` everywhere else.
Expand Down
12 changes: 12 additions & 0 deletions config.json
Expand Up @@ -2,6 +2,10 @@
"definitions": {
"npm": {
"default": "8.18.0+sha1.bd6ca7f637720441f812370363e2ae67426fb42f",
"fetchLatestFrom": {
"type": "npm",
"package": "npm"
},
"transparent": {
"commands": [
[
Expand Down Expand Up @@ -29,6 +33,10 @@
},
"pnpm": {
"default": "7.9.3+sha1.843f76d13dbfa9f6dfb5135d6fbaa8b99facacc9",
"fetchLatestFrom": {
"type": "npm",
"package": "pnpm"
},
"transparent": {
"commands": [
[
Expand Down Expand Up @@ -71,6 +79,10 @@
},
"yarn": {
"default": "1.22.19+sha1.4ba7fc5c6e704fce2066ecbfb0b0d8976fe62447",
"fetchLatestFrom": {
"type": "npm",
"package": "yarn"
},
"transparent": {
"default": "3.2.2+sha224.634d0331703700cabfa9d9389835bd8f7426b0207ed6b74d8d34c81e",
"commands": [
Expand Down
23 changes: 16 additions & 7 deletions sources/Engine.ts
@@ -1,6 +1,7 @@
import {UsageError} from 'clipanion';
import fs from 'fs';
import path from 'path';
import process from 'process';
import semver from 'semver';

import defaultConfig from '../config.json';
Expand Down Expand Up @@ -69,17 +70,25 @@ export class Engine {
// Ignore errors; too bad
}

if (typeof lastKnownGood !== `object` || lastKnownGood === null)
return definition.default;
if (typeof lastKnownGood === `object` && lastKnownGood !== null &&
Object.prototype.hasOwnProperty.call(lastKnownGood, packageManager)) {
const override = (lastKnownGood as any)[packageManager];
if (typeof override === `string`) {
return override;
}
}

if (!Object.prototype.hasOwnProperty.call(lastKnownGood, packageManager))
if (process.env.COREPACK_DEFAULT_TO_LATEST === `0`)
return definition.default;

const override = (lastKnownGood as any)[packageManager];
if (typeof override !== `string`)
return definition.default;
const reference = await corepackUtils.fetchLatestStableVersion(definition.fetchLatestFrom);

await this.activatePackageManager({
name: packageManager,
reference,
});

return override;
return reference;
}

async activatePackageManager(locator: Locator) {
Expand Down
17 changes: 17 additions & 0 deletions sources/corepackUtils.ts
Expand Up @@ -12,6 +12,23 @@ import * as httpUtils from './httpUtils
import * as nodeUtils from './nodeUtils';
import {RegistrySpec, Descriptor, Locator, PackageManagerSpec} from './types';

export async function fetchLatestStableVersion(spec: RegistrySpec) {
switch (spec.type) {
case `npm`: {
const {[`dist-tags`]: {latest}, versions: {[latest]: {dist: {shasum}}}} =
await httpUtils.fetchAsJson(`https://registry.npmjs.org/${spec.package}`);
return `${latest}+sha1.${shasum}`;
}
case `url`: {
const data = await httpUtils.fetchAsJson(spec.url);
return data[spec.fields.tags].stable;
}
default: {
throw new Error(`Unsupported specification ${JSON.stringify(spec)}`);
}
}
}

export async function fetchAvailableTags(spec: RegistrySpec): Promise<Record<string, string>> {
switch (spec.type) {
case `npm`: {
Expand Down
5 changes: 5 additions & 0 deletions sources/types.ts
Expand Up @@ -62,6 +62,11 @@ export interface Config {
*/
default: string;

/**
* Defines how to fetch the latest version from a remote registry.
*/
fetchLatestFrom: RegistrySpec;

/**
* Defines a set of commands that are fine to run even if the user isn't
* in a project configured for the specified package manager. For instance,
Expand Down
1 change: 1 addition & 0 deletions tests/main.test.ts
Expand Up @@ -6,6 +6,7 @@ import {runCli} from './_runCli';

beforeEach(async () => {
process.env.COREPACK_HOME = npath.fromPortablePath(await xfs.mktempPromise());
process.env.COREPACK_DEFAULT_TO_LATEST = `0`;
});

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

0 comments on commit 055b928

Please sign in to comment.