Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implements --no-default-rc and --use-yarnrc #6007

Merged
merged 1 commit into from
Jun 27, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions __tests__/commands/_helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ export function makeConfigFromDirectory(cwd: string, reporter: Reporter, flags:
production: flags.production,
updateChecksums: !!flags.updateChecksums,
focus: !!flags.focus,
enableDefaultRc: !flags.noDefaultRc,
extraneousYarnrcFiles: flags.useYarnrc,
},
reporter,
);
Expand Down
1 change: 1 addition & 0 deletions __tests__/fixtures/cache/custom-location/.yarnrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
cache-folder "./uses-default-yarnrc"
1 change: 1 addition & 0 deletions __tests__/fixtures/cache/custom-location/custom-yarnrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
cache-folder "./uses-custom-yarnrc"
1 change: 1 addition & 0 deletions __tests__/fixtures/cache/custom-location/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
20 changes: 20 additions & 0 deletions __tests__/integration.js
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,26 @@ test('--cwd option', async () => {
expect(packageJson.dependencies['left-pad']).toBeDefined();
});

const customCacheCwd = `${__dirname}/fixtures/cache/custom-location`;

test('default rc', async (): Promise<void> => {
const [stdoutOutput] = await runYarn(['cache', 'dir'], {cwd: customCacheCwd});

expect(stdoutOutput).toMatch(/uses-default-yarnrc/);
});

test('--no-default-rc', async (): Promise<void> => {
const [stdoutOutput] = await runYarn(['cache', 'dir', '--no-default-rc'], {cwd: customCacheCwd});

expect(stdoutOutput).not.toMatch(/uses-default-yarnrc/);
});

test('--use-yarnrc', async (): Promise<void> => {
const [stdoutOutput] = await runYarn(['cache', 'dir', '--use-yarnrc', './custom-yarnrc'], {cwd: customCacheCwd});

expect(stdoutOutput).toMatch(/uses-custom-yarnrc/);
});

test('yarnrc arguments', async () => {
const cwd = await makeTemp();

Expand Down
16 changes: 16 additions & 0 deletions __tests__/rc.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,22 @@ test('resolve .yarnrc args and use --cwd if present', () => {
expect(args.indexOf('--foo') !== -1).toBe(true);
});

test("don't resolve .yarnrc args from the default locations when using --no-default-rc", () => {
const args = getRcArgs('install', ['--cwd', path.join(fixturesLoc, 'empty'), '--no-default-rc']);
expect(args.indexOf('--foo') !== -1).toBe(false);
});

test('resolve .yarnrc args from the extraneous locations when using --use-yarnrc', () => {
const args = getRcArgs('install', [
'--cwd',
path.join(fixturesLoc, 'empty'),
'--no-default-rc',
'--use-yarnrc',
path.join(fixturesLoc, 'empty', '.yarnrc'),
]);
expect(args.indexOf('--foo') !== -1).toBe(true);
});

test('resolve .yarnrc args and use process.cwd() if no --cwd present', () => {
const cwd = process.cwd();
process.chdir(path.join(fixturesLoc, 'empty'));
Expand Down
26 changes: 13 additions & 13 deletions __tests__/registries/npm-registry.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ describe('request', () => {
function createRegistry(config: Object): Object {
const testCwd = '.';
const {mockRequestManager, mockRegistries, mockReporter} = createMocks();
const npmRegistry = new NpmRegistry(testCwd, mockRegistries, mockRequestManager, mockReporter);
const npmRegistry = new NpmRegistry(testCwd, mockRegistries, mockRequestManager, mockReporter, true, []);
npmRegistry.config = config;
return {
request(url: string, options: Object, packageName: string): Object {
Expand Down Expand Up @@ -577,7 +577,7 @@ describe('isRequestToRegistry functional test', () => {
test('request to registry url matching', () => {
const testCwd = '.';
const {mockRequestManager, mockRegistries, mockReporter} = createMocks();
const npmRegistry = new NpmRegistry(testCwd, mockRegistries, mockRequestManager, mockReporter);
const npmRegistry = new NpmRegistry(testCwd, mockRegistries, mockRequestManager, mockReporter, true, []);

const validRegistryUrls = [
['http://foo.bar:80/foo/bar/baz', 'http://foo.bar/foo/'],
Expand Down Expand Up @@ -609,7 +609,7 @@ describe('isRequestToRegistry functional test', () => {
test('isRequestToRegistry with custom host prefix', () => {
const testCwd = '.';
const {mockRequestManager, mockRegistries, mockReporter} = createMocks();
const npmRegistry = new NpmRegistry(testCwd, mockRegistries, mockRequestManager, mockReporter);
const npmRegistry = new NpmRegistry(testCwd, mockRegistries, mockRequestManager, mockReporter, true, []);

npmRegistry.config = {
'custom-host-suffix': 'some.host.org',
Expand Down Expand Up @@ -659,7 +659,7 @@ describe('isScopedPackage functional test', () => {
test('identifies scope correctly', () => {
const testCwd = '.';
const {mockRequestManager, mockRegistries, mockReporter} = createMocks();
const npmRegistry = new NpmRegistry(testCwd, mockRegistries, mockRequestManager, mockReporter);
const npmRegistry = new NpmRegistry(testCwd, mockRegistries, mockRequestManager, mockReporter, true, []);

packageIdents.forEach(([pathname, scope]) => {
expect(npmRegistry.isScopedPackage(pathname)).toEqual(!!scope.length);
Expand All @@ -671,7 +671,7 @@ describe('getRequestUrl functional test', () => {
test('returns pathname when it is a full URL', () => {
const testCwd = '.';
const {mockRequestManager, mockRegistries, mockReporter} = createMocks();
const npmRegistry = new NpmRegistry(testCwd, mockRegistries, mockRequestManager, mockReporter);
const npmRegistry = new NpmRegistry(testCwd, mockRegistries, mockRequestManager, mockReporter, true, []);
const fullURL = 'HTTP://xn--xample-hva.com:80/foo/bar/baz';

expect(npmRegistry.getRequestUrl('https://my.registry.co', fullURL)).toEqual(fullURL);
Expand All @@ -680,7 +680,7 @@ describe('getRequestUrl functional test', () => {
test('correctly handles registries lacking a trailing slash', () => {
const testCwd = '.';
const {mockRequestManager, mockRegistries, mockReporter} = createMocks();
const npmRegistry = new NpmRegistry(testCwd, mockRegistries, mockRequestManager, mockReporter);
const npmRegistry = new NpmRegistry(testCwd, mockRegistries, mockRequestManager, mockReporter, true, []);
const registry = 'https://my.registry.co/registry';
const pathname = 'foo/bar/baz';

Expand All @@ -692,7 +692,7 @@ describe('getScope functional test', () => {
describe('matches scope correctly', () => {
const testCwd = '.';
const {mockRequestManager, mockRegistries, mockReporter} = createMocks();
const npmRegistry = new NpmRegistry(testCwd, mockRegistries, mockRequestManager, mockReporter);
const npmRegistry = new NpmRegistry(testCwd, mockRegistries, mockRequestManager, mockReporter, true, []);

packageIdents.forEach(([pathname, scope]) => {
expect(npmRegistry.getScope(pathname)).toEqual(scope);
Expand All @@ -705,7 +705,7 @@ describe('getPossibleConfigLocations', () => {
const testCwd = './project/subdirectory';
const {mockRequestManager, mockRegistries} = createMocks();
const reporter = new BufferReporter({verbose: true});
const npmRegistry = new NpmRegistry(testCwd, mockRegistries, mockRequestManager, reporter);
const npmRegistry = new NpmRegistry(testCwd, mockRegistries, mockRequestManager, reporter, true, []);
await npmRegistry.getPossibleConfigLocations('npmrc', reporter);

const logs = reporter.getBuffer().map(logItem => logItem.data);
Expand All @@ -730,7 +730,7 @@ describe('checkOutdated functional test', () => {
test('homepage URL from top level', async () => {
const testCwd = '.';
const {mockRequestManager, mockRegistries, mockReporter} = createMocks();
const npmRegistry = new NpmRegistry(testCwd, mockRegistries, mockRequestManager, mockReporter);
const npmRegistry = new NpmRegistry(testCwd, mockRegistries, mockRequestManager, mockReporter, true, []);

mockRequestManager.request = () => {
return {
Expand Down Expand Up @@ -758,7 +758,7 @@ describe('checkOutdated functional test', () => {
test('homepage URL fallback to wanted package manifest', async () => {
const testCwd = '.';
const {mockRequestManager, mockRegistries, mockReporter} = createMocks();
const npmRegistry = new NpmRegistry(testCwd, mockRegistries, mockRequestManager, mockReporter);
const npmRegistry = new NpmRegistry(testCwd, mockRegistries, mockRequestManager, mockReporter, true, []);

mockRequestManager.request = () => {
return {
Expand Down Expand Up @@ -786,7 +786,7 @@ describe('checkOutdated functional test', () => {
test('repository URL from top level', async () => {
const testCwd = '.';
const {mockRequestManager, mockRegistries, mockReporter} = createMocks();
const npmRegistry = new NpmRegistry(testCwd, mockRegistries, mockRequestManager, mockReporter);
const npmRegistry = new NpmRegistry(testCwd, mockRegistries, mockRequestManager, mockReporter, true, []);

mockRequestManager.request = () => {
return {
Expand Down Expand Up @@ -816,7 +816,7 @@ describe('checkOutdated functional test', () => {
test('repository URL fallback to wanted package manifest', async () => {
const testCwd = '.';
const {mockRequestManager, mockRegistries, mockReporter} = createMocks();
const npmRegistry = new NpmRegistry(testCwd, mockRegistries, mockRequestManager, mockReporter);
const npmRegistry = new NpmRegistry(testCwd, mockRegistries, mockRequestManager, mockReporter, true, []);

mockRequestManager.request = () => {
return {
Expand Down Expand Up @@ -846,7 +846,7 @@ describe('checkOutdated functional test', () => {
test('unpublished package (no versions)', async () => {
const testCwd = '.';
const {mockRequestManager, mockRegistries, mockReporter} = createMocks();
const npmRegistry = new NpmRegistry(testCwd, mockRegistries, mockRequestManager, mockReporter);
const npmRegistry = new NpmRegistry(testCwd, mockRegistries, mockRequestManager, mockReporter, true, []);

mockRequestManager.request = () => {
return {
Expand Down
5 changes: 4 additions & 1 deletion bin/yarn.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ if (majorVer < 4) {
// be truthy when built with webpack :(
var cli = require(dirPath + 'cli');
if (!cli.autoRun) {
cli.default();
cli.default().catch(function(error) {
console.error(error.stack || error.message || error);
process.exitCode = 1;
});
}
}
29 changes: 23 additions & 6 deletions src/cli/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,21 +41,33 @@ function findProjectRoot(base: string): string {
return base;
}

export function main({
export async function main({
startArgs,
args,
endArgs,
}: {
startArgs: Array<string>,
args: Array<string>,
endArgs: Array<string>,
}) {
}): Promise<void> {
const collect = (val, acc) => {
acc.push(val);
return acc;
};

loudRejection();
handleSignals();

// set global options
commander.version(version, '-v, --version');
commander.usage('[command] [flags]');
commander.option('--no-default-rc', 'prevent Yarn from automatically detecting yarnrc and npmrc files');
commander.option(
'--use-yarnrc <path>',
'specifies a yarnrc file that Yarn should use (.yarnrc only, not .npmrc)',
collect,
[],
);
commander.option('--verbose', 'output verbose messages on internal operations');
commander.option('--offline', 'trigger an error if any required dependencies are not available in local cache');
commander.option('--prefer-offline', 'use network only if dependencies are not available in local cache');
Expand Down Expand Up @@ -477,11 +489,13 @@ export function main({

const cwd = command.shouldRunInCurrentCwd ? commander.cwd : findProjectRoot(commander.cwd);

config
await config
.init({
cwd,
commandName,

enableDefaultRc: commander.defaultRc,
extraneousYarnrcFiles: commander.useYarnrc,
binLinks: commander.binLinks,
modulesFolder: commander.modulesFolder,
linkFolder: commander.linkFolder,
Expand Down Expand Up @@ -564,7 +578,7 @@ export function main({
}

async function start(): Promise<void> {
const rc = getRcConfigForCwd(process.cwd());
const rc = getRcConfigForCwd(process.cwd(), process.argv.slice(2));
const yarnPath = rc['yarn-path'];

if (yarnPath && !boolifyWithDefault(process.env.YARN_IGNORE_PATH, false)) {
Expand All @@ -590,7 +604,7 @@ async function start(): Promise<void> {
const args = process.argv.slice(2, doubleDashIndex === -1 ? process.argv.length : doubleDashIndex);
const endArgs = doubleDashIndex === -1 ? [] : process.argv.slice(doubleDashIndex);

main({startArgs, args, endArgs});
await main({startArgs, args, endArgs});
}
}

Expand All @@ -599,7 +613,10 @@ async function start(): Promise<void> {
export const autoRun = module.children.length === 0;

if (require.main === module) {
start();
start().catch(error => {
console.error(error.stack || error.message || error);
process.exitCode = 1;
});
}

export default start;
21 changes: 20 additions & 1 deletion src/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ export type ConfigOptions = {
nonInteractive?: boolean,
scriptsPrependNodePath?: boolean,

enableDefaultRc?: boolean,
extraneousYarnrcFiles?: Array<string>,

// Loosely compare semver for invalid cases like "0.01.0"
looseSemver?: ?boolean,

Expand Down Expand Up @@ -96,6 +99,10 @@ export default class Config {
this._init({});
}

//
enableDefaultRc: boolean;
extraneousYarnrcFiles: Array<string>;

//
looseSemver: boolean;
offline: boolean;
Expand Down Expand Up @@ -272,8 +279,17 @@ export default class Config {
for (const key of Object.keys(registries)) {
const Registry = registries[key];

const extraneousRcFiles = Registry === registries.yarn ? this.extraneousYarnrcFiles : [];

// instantiate registry
const registry = new Registry(this.cwd, this.registries, this.requestManager, this.reporter);
const registry = new Registry(
this.cwd,
this.registries,
this.requestManager,
this.reporter,
this.enableDefaultRc,
extraneousRcFiles,
);
await registry.init({
registry: opts.registry,
});
Expand Down Expand Up @@ -386,6 +402,9 @@ export default class Config {

this.commandName = opts.commandName || '';

this.enableDefaultRc = !!opts.enableDefaultRc;
this.extraneousYarnrcFiles = opts.extraneousYarnrcFiles || [];

this.preferOffline = !!opts.preferOffline;
this.modulesFolder = opts.modulesFolder;
this.globalFolder = opts.globalFolder || constants.GLOBAL_MODULE_DIRECTORY;
Expand Down
50 changes: 36 additions & 14 deletions src/rc.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/* @flow */

import {readFileSync} from 'fs';
import {dirname, resolve} from 'path';

import commander from 'commander';
Expand All @@ -11,24 +12,45 @@ import * as rcUtil from './util/rc.js';
const PATH_KEYS = new Set(['yarn-path', 'cache-folder', 'global-folder', 'modules-folder', 'cwd']);

// given a cwd, load all .yarnrc files relative to it
export function getRcConfigForCwd(cwd: string): {[key: string]: string} {
return rcUtil.findRc('yarn', cwd, (fileText, filePath) => {
const {object: values} = parse(fileText, 'yarnrc');

// some keys reference directories so keep their relativity
for (const key in values) {
if (PATH_KEYS.has(key.replace(/^(--)?([^.]+\.)*/, ''))) {
values[key] = resolve(dirname(filePath), values[key]);
}
export function getRcConfigForCwd(cwd: string, args: Array<string>): {[key: string]: string} {
const config = {};

if (args.indexOf('--no-default-rc') === -1) {
Object.assign(
config,
rcUtil.findRc('yarn', cwd, (fileText, filePath) => {
return loadRcFile(fileText, filePath);
}),
);
}

for (let index = args.indexOf('--use-yarnrc'); index !== -1; index = args.indexOf('--use-yarnrc', index + 1)) {
const value = args[index + 1];

if (value && value.charAt(0) !== '-') {
Object.assign(config, loadRcFile(readFileSync(value).toString(), value));
}
}

return config;
}

function loadRcFile(fileText: string, filePath: string): {[key: string]: string} {
const {object: values} = parse(fileText, 'yarnrc');

// some keys reference directories so keep their relativity
for (const key in values) {
if (PATH_KEYS.has(key.replace(/^(--)?([^.]+\.)*/, ''))) {
values[key] = resolve(dirname(filePath), values[key]);
}
}

return values;
});
return values;
}

// get the built of arguments of a .yarnrc chain of the passed cwd
function buildRcArgs(cwd: string): Map<string, Array<string>> {
const config = getRcConfigForCwd(cwd);
function buildRcArgs(cwd: string, args: Array<string>): Map<string, Array<string>> {
const config = getRcConfigForCwd(cwd, args);

const argsForCommands: Map<string, Array<string>> = new Map();

Expand Down Expand Up @@ -82,7 +104,7 @@ export function getRcArgs(commandName: string, args: Array<string>, previousCwds
const origCwd = extractCwdArg(args) || process.cwd();

// get a map of command names and their arguments
const argMap = buildRcArgs(origCwd);
const argMap = buildRcArgs(origCwd, args);

// concat wildcard arguments and arguments meant for this specific command
const newArgs = [...(argMap.get('*') || []), ...(argMap.get(commandName) || [])];
Expand Down
Loading