diff --git a/@commitlint/cli/fixtures/inner-scope/commitlint.config.js b/@commitlint/cli/fixtures/inner-scope/commitlint.config.js new file mode 100644 index 0000000000..f25ceaf559 --- /dev/null +++ b/@commitlint/cli/fixtures/inner-scope/commitlint.config.js @@ -0,0 +1,5 @@ +module.exports = { + rules: { + 'type-enum': [2, 'always', ['outer']] + } +}; diff --git a/@commitlint/cli/fixtures/inner-scope/inner-scope/commitlint.config.js b/@commitlint/cli/fixtures/inner-scope/inner-scope/commitlint.config.js new file mode 100644 index 0000000000..bfffc3d9d9 --- /dev/null +++ b/@commitlint/cli/fixtures/inner-scope/inner-scope/commitlint.config.js @@ -0,0 +1,5 @@ +module.exports = { + rules: { + 'type-enum': [2, 'always', ['inner']] + } +}; diff --git a/@commitlint/cli/fixtures/outer-scope/commitlint.config.js b/@commitlint/cli/fixtures/outer-scope/commitlint.config.js new file mode 100644 index 0000000000..f25ceaf559 --- /dev/null +++ b/@commitlint/cli/fixtures/outer-scope/commitlint.config.js @@ -0,0 +1,5 @@ +module.exports = { + rules: { + 'type-enum': [2, 'always', ['outer']] + } +}; diff --git a/@commitlint/cli/src/cli.test.js b/@commitlint/cli/src/cli.test.js index b314f00607..3e8a17a91d 100644 --- a/@commitlint/cli/src/cli.test.js +++ b/@commitlint/cli/src/cli.test.js @@ -1,5 +1,5 @@ import path from 'path'; -import {git} from '@commitlint/test'; +import {fix, git} from '@commitlint/test'; import test from 'ava'; import execa from 'execa'; import {merge} from 'lodash'; @@ -118,6 +118,38 @@ test('should pick up parser preset and succeed accordingly', async t => { t.is(actual.code, 0); }); +test('should pick up config from outside git repo and fail accordingly', async t => { + const outer = await fix.bootstrap('fixtures/outer-scope'); + const cwd = await git.init(path.join(outer, 'inner-scope')); + + const actual = await cli([], {cwd})('inner: bar'); + t.is(actual.code, 1); +}); + +test('should pick up config from outside git repo and succeed accordingly', async t => { + const outer = await fix.bootstrap('fixtures/outer-scope'); + const cwd = await git.init(path.join(outer, 'inner-scope')); + + const actual = await cli([], {cwd})('outer: bar'); + t.is(actual.code, 0); +}); + +test('should pick up config from inside git repo with precedence and succeed accordingly', async t => { + const outer = await fix.bootstrap('fixtures/inner-scope'); + const cwd = await git.init(path.join(outer, 'inner-scope')); + + const actual = await cli([], {cwd})('inner: bar'); + t.is(actual.code, 0); +}); + +test('should pick up config from inside git repo with precedence and fail accordingly', async t => { + const outer = await fix.bootstrap('fixtures/inner-scope'); + const cwd = await git.init(path.join(outer, 'inner-scope')); + + const actual = await cli([], {cwd})('outer: bar'); + t.is(actual.code, 1); +}); + async function writePkg(payload, options) { const pkgPath = path.join(options.cwd, 'package.json'); const pkg = JSON.parse(await sander.readFile(pkgPath)); diff --git a/@commitlint/core/fixtures/outer-scope/commitlint.config.js b/@commitlint/core/fixtures/outer-scope/commitlint.config.js new file mode 100644 index 0000000000..23554f588f --- /dev/null +++ b/@commitlint/core/fixtures/outer-scope/commitlint.config.js @@ -0,0 +1,7 @@ +module.exports = { + rules: { + outer: true, + inner: false, + child: false + } +}; diff --git a/@commitlint/core/fixtures/outer-scope/inner-scope/child-scope/commitlint.config.js b/@commitlint/core/fixtures/outer-scope/inner-scope/child-scope/commitlint.config.js new file mode 100644 index 0000000000..925d251382 --- /dev/null +++ b/@commitlint/core/fixtures/outer-scope/inner-scope/child-scope/commitlint.config.js @@ -0,0 +1,7 @@ +module.exports = { + rules: { + outer: false, + inner: false, + child: true + } +}; diff --git a/@commitlint/core/src/load.js b/@commitlint/core/src/load.js index b8680cb250..b19c3cd0ed 100644 --- a/@commitlint/core/src/load.js +++ b/@commitlint/core/src/load.js @@ -5,22 +5,16 @@ import resolveFrom from 'resolve-from'; import executeRule from './library/execute-rule'; import resolveExtends from './library/resolve-extends'; -import toplevel from './library/toplevel'; const w = (a, b) => (Array.isArray(b) ? b : undefined); const valid = input => pick(input, 'extends', 'rules', 'parserPreset'); export default async (seed = {}, options = {cwd: ''}) => { - const explorer = cosmiconfig('commitlint', { - rcExtensions: true, - stopDir: await toplevel(options.cwd) - }); - - const raw = (await explorer.load(options.cwd)) || {}; - const base = raw.filepath ? path.dirname(raw.filepath) : options.cwd; + const loaded = await loadConfig(options.cwd); + const base = loaded.filepath ? path.dirname(loaded.filepath) : options.cwd; // Merge passed config with file based options - const config = valid(merge(raw.config, seed)); + const config = valid(merge(loaded.config, seed)); const opts = merge({extends: [], rules: {}}, pick(config, 'extends')); // Resolve parserPreset key @@ -80,3 +74,17 @@ export default async (seed = {}, options = {cwd: ''}) => { return registry; }, preset); }; + +async function loadConfig(cwd) { + const explorer = cosmiconfig('commitlint', { + rcExtensions: true + }); + + const local = await explorer.load(cwd); + + if (local) { + return local; + } + + return {}; +} diff --git a/@commitlint/core/src/load.test.js b/@commitlint/core/src/load.test.js index 4538f9dfdc..3fa9da29bc 100644 --- a/@commitlint/core/src/load.test.js +++ b/@commitlint/core/src/load.test.js @@ -1,4 +1,5 @@ -import {git} from '@commitlint/test'; +import path from 'path'; +import {fix, git} from '@commitlint/test'; import test from 'ava'; import load from './load'; @@ -181,3 +182,35 @@ test('ignores unknow keys recursively', async t => { } }); }); + +test('find up from given cwd', async t => { + const outer = await fix.bootstrap('fixtures/outer-scope'); + await git.init(path.join(outer, 'inner-scope')); + const cwd = path.join(outer, 'inner-scope', 'child-scope'); + + const actual = await load({}, {cwd}); + + t.deepEqual(actual, { + extends: [], + rules: { + child: true, + inner: false, + outer: false + } + }); +}); + +test('find up config from outside current git repo', async t => { + const outer = await fix.bootstrap('fixtures/outer-scope'); + const cwd = await git.init(path.join(outer, 'inner-scope')); + const actual = await load({}, {cwd}); + + t.deepEqual(actual, { + extends: [], + rules: { + child: false, + inner: false, + outer: true + } + }); +}); diff --git a/@packages/test/src/fix.js b/@packages/test/src/fix.js new file mode 100644 index 0000000000..14b88b58c4 --- /dev/null +++ b/@packages/test/src/fix.js @@ -0,0 +1,25 @@ +import crypto from 'crypto'; +import os from 'os'; +import path from 'path'; + +import * as sander from '@marionebl/sander'; +import pkgDir from 'pkg-dir'; + +export {bootstrap}; + +async function bootstrap(fixture) { + const cwd = path.join(os.tmpdir(), rand()); + + if (typeof fixture !== 'undefined') { + await sander.copydir(await pkgDir(), fixture).to(cwd); + } + + return cwd; +} + +function rand() { + return crypto + .randomBytes(Math.ceil(6)) + .toString('hex') + .slice(0, 12); +} diff --git a/@packages/test/src/git.js b/@packages/test/src/git.js index 8d535b9950..c2e1950ff7 100644 --- a/@packages/test/src/git.js +++ b/@packages/test/src/git.js @@ -6,7 +6,7 @@ import * as sander from '@marionebl/sander'; import execa from 'execa'; import pkgDir from 'pkg-dir'; -export {bootstrap, clone}; +export {bootstrap, clone, init}; async function bootstrap(fixture) { const cwd = path.join(os.tmpdir(), rand()); @@ -15,8 +15,7 @@ async function bootstrap(fixture) { await sander.copydir(await pkgDir(), fixture).to(cwd); } - await execa('git', ['init', cwd]); - await setup(cwd); + await init(cwd); return cwd; } @@ -27,6 +26,12 @@ async function clone(source, ...args) { return cwd; } +async function init(cwd) { + await execa('git', ['init', cwd]); + await setup(cwd); + return cwd; +} + async function setup(cwd) { try { await execa('git', ['config', 'user.name', 'ava'], {cwd}); diff --git a/@packages/test/src/index.js b/@packages/test/src/index.js index f2848c67e6..2825fd2120 100644 --- a/@packages/test/src/index.js +++ b/@packages/test/src/index.js @@ -1,4 +1,5 @@ +import * as fix from './fix'; import * as git from './git'; import * as npm from './npm'; -export {git, npm}; +export {fix, git, npm};