Skip to content

Commit

Permalink
Implements "yarn self set" (#6673)
Browse files Browse the repository at this point in the history
* Implements "yarn self set"

* Adds support for nightlies

* Updates changelog

* Renames "yarn self set" into "yarn policies set-version"
  • Loading branch information
arcanis committed Nov 20, 2018
1 parent 7f41910 commit 158da6c
Show file tree
Hide file tree
Showing 5 changed files with 175 additions and 3 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Expand Up @@ -4,6 +4,10 @@ Please add one entry in this file for each change in Yarn's behavior. Use the sa

## Master

- Implements `yarn policies set-version [range]`. Check [the documentation]() for usage & tips.

[#6673](https://github.com/yarnpkg/yarn/pull/6673) - [**Maël Nison**](https://twitter.com/arcanis)

- Fixes a resolution issue when a package had an invalid `main` entry

[#6682](https://github.com/yarnpkg/yarn/pull/6682) - [**Maël Nison**](https://twitter.com/arcanis)
Expand Down
2 changes: 2 additions & 0 deletions src/cli/commands/index.js
Expand Up @@ -32,6 +32,7 @@ import * as node from './node.js';
import * as outdated from './outdated.js';
import * as owner from './owner.js';
import * as pack from './pack.js';
import * as policies from './policies.js';
import * as publish from './publish.js';
import * as remove from './remove.js';
import * as run from './run.js';
Expand Down Expand Up @@ -78,6 +79,7 @@ const commands = {
outdated,
owner,
pack,
policies,
prune: buildUseless("The prune command isn't necessary. `yarn install` will prune extraneous packages."),
publish,
remove,
Expand Down
160 changes: 160 additions & 0 deletions src/cli/commands/policies.js
@@ -0,0 +1,160 @@
/* @flow */

import type {Reporter} from '../../reporters/index.js';
import type Config from '../../config.js';
import buildSubCommands from './_build-sub-commands.js';
import {getRcConfigForCwd} from '../../rc.js';
import * as fs from '../../util/fs.js';
import {stringify} from '../../lockfile';

const chalk = require('chalk');
const invariant = require('invariant');
const path = require('path');
const semver = require('semver');

type ReleaseAsset = {|
id: any,

name: string,
browser_download_url: string,
|};

type Release = {|
id: any,

draft: boolean,
prerelease: boolean,

tag_name: string,
version: {|
version: string,
|},

assets: Array<ReleaseAsset>,
|};

function getBundleAsset(release: Release): ?ReleaseAsset {
return release.assets.find(asset => {
return asset.name.match(/^yarn-[0-9]+\.[0-9]+\.[0-9]+\.js$/);
});
}

type FetchReleasesOptions = {|
includePrereleases: boolean,
|};

async function fetchReleases(
config: Config,
{includePrereleases = false}: FetchReleasesOptions = {},
): Promise<Array<Release>> {
const request: Array<Release> = await config.requestManager.request({
url: `https://api.github.com/repos/yarnpkg/yarn/releases`,
json: true,
});

const releases = request.filter(release => {
if (release.draft) {
return false;
}

if (release.prerelease && !includePrereleases) {
return false;
}

// $FlowFixMe
release.version = semver.coerce(release.tag_name);

if (!release.version) {
return false;
}

if (!getBundleAsset(release)) {
return false;
}

return true;
});

releases.sort((a, b) => {
// $FlowFixMe
return -semver.compare(a.version, b.version);
});

return releases;
}

function fetchBundle(config: Config, url: string): Promise<Buffer> {
return config.requestManager.request({
url,
buffer: true,
});
}

export function hasWrapper(flags: Object, args: Array<string>): boolean {
return false;
}

const {run, setFlags, examples} = buildSubCommands('policies', {
async setVersion(config: Config, reporter: Reporter, flags: Object, args: Array<string>): Promise<void> {
let range = args[0] || 'latest';
let allowRc = flags.rc;

reporter.log(`Resolving ${chalk.yellow(range)} to a url...`);

if (range === 'rc') {
range = 'latest';
allowRc = true;
}

if (range === 'latest') {
range = '*';
}

let bundleUrl;
let bundleVersion;

if (range === 'nightly' || range === 'nightlies') {
bundleUrl = 'https://nightly.yarnpkg.com/latest.js';
bundleVersion = 'nightly';
} else {
const releases = await fetchReleases(config, {
includePrereleases: allowRc,
});

const release = releases.find(release => {
// $FlowFixMe
return semver.satisfies(release.version, range);
});

if (!release) {
throw new Error(`Release not found: ${range}`);
}

const asset = getBundleAsset(release);
invariant(asset, 'The bundle asset should exist');

bundleUrl = asset.browser_download_url;
bundleVersion = release.version.version;
}

reporter.log(`Downloading ${chalk.green(bundleUrl)}...`);

const bundle = await fetchBundle(config, bundleUrl);
const rc = getRcConfigForCwd(config.lockfileFolder, []);

const yarnPath = path.resolve(config.lockfileFolder, `.yarn/releases/yarn-${bundleVersion}.js`);
reporter.log(`Saving it into ${chalk.magenta(yarnPath)}...`);
await fs.mkdirp(path.dirname(yarnPath));
await fs.writeFile(yarnPath, bundle);
await fs.chmod(yarnPath, 0o755);

const rcPath = `${config.lockfileFolder}/.yarnrc`;
reporter.log(`Updating ${chalk.magenta(rcPath)}...`);
rc['yarn-path'] = path.relative(config.lockfileFolder, yarnPath);
await fs.writeFilePreservingEol(rcPath, `${stringify(rc)}\n`);

reporter.log(`Done!`);
},
});

export {run, setFlags, examples};
8 changes: 6 additions & 2 deletions src/registries/yarn-registry.js
Expand Up @@ -31,7 +31,8 @@ export const DEFAULTS = {
'user-agent': [`yarn/${version}`, 'npm/?', `node/${process.version}`, process.platform, process.arch].join(' '),
};

const RELATIVE_KEYS = ['yarn-offline-mirror', 'cache-folder', 'offline-cache-folder'];
const RELATIVE_KEYS = ['yarn-offline-mirror', 'cache-folder', 'offline-cache-folder', 'yarn-path'];
const FOLDER_KEY = ['yarn-offline-mirror', 'cache-folder', 'offline-cache-folder'];

const npmMap = {
'version-git-sign': 'sign-git-tag',
Expand Down Expand Up @@ -96,7 +97,10 @@ export default class YarnRegistry extends NpmRegistry {

if (!this.config[key] && valueLoc) {
const resolvedLoc = (config[key] = path.resolve(path.dirname(loc), valueLoc));
await fs.mkdirp(resolvedLoc);

if (FOLDER_KEY.includes(key)) {
await fs.mkdirp(resolvedLoc);
}
}
}

Expand Down
4 changes: 3 additions & 1 deletion src/util/fs.js
Expand Up @@ -28,7 +28,9 @@ export const lockQueue = new BlockingQueue('fs lock');

export const readFileBuffer = promisify(fs.readFile);
export const open: (path: string, flags: string, mode?: number) => Promise<Array<string>> = promisify(fs.open);
export const writeFile: (path: string, data: string, options?: Object) => Promise<void> = promisify(fs.writeFile);
export const writeFile: (path: string, data: string | Buffer, options?: Object) => Promise<void> = promisify(
fs.writeFile,
);
export const readlink: (path: string, opts: void) => Promise<string> = promisify(fs.readlink);
export const realpath: (path: string, opts: void) => Promise<string> = promisify(fs.realpath);
export const readdir: (path: string, opts: void) => Promise<Array<string>> = promisify(fs.readdir);
Expand Down

0 comments on commit 158da6c

Please sign in to comment.