Skip to content

Commit 063994d

Browse files
committed
feat(core): Allow to configure with json, yaml and package.json
Fix conventional-changelog#73
1 parent e6ef072 commit 063994d

File tree

19 files changed

+352
-77
lines changed

19 files changed

+352
-77
lines changed

@commitlint/cli/cli.test.js

+24-6
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ const exec = (command, args = [], opts = {}) => {
3131
console.log(result.stderr);
3232
}
3333
return result;
34-
}
34+
};
3535
};
3636

3737
const cli = exec.bind(null, CLI);
@@ -40,8 +40,12 @@ const mkdir = exec.bind(null, bin('mkdirp'));
4040
const npm = exec.bind(null, 'npm');
4141
const rm = exec.bind(null, bin('rimraf'));
4242

43-
test('should throw when called without [input]', t => {
44-
t.throws(cli()(), /Expected a raw commit/);
43+
test('should throw when called without [input]', async t => {
44+
const dir = tmp.dirSync().name;
45+
46+
await init(dir);
47+
await t.throws(cli([], {cwd: dir})(), /Expected a raw commit/);
48+
await rm([dir])();
4549
});
4650

4751
test('should reprint input from stdin', async t => {
@@ -73,11 +77,19 @@ test('should fail for input from stdin with rule from rc', async t => {
7377
});
7478

7579
test('should fail for input from stdin with rule from js', async t => {
80+
const dir = tmp.dirSync().name;
81+
82+
await init(dir);
83+
await sander.copydir(EXTENDS_ROOT).to(dir);
84+
7685
const actual = await t.throws(
77-
cli(['--extends', './extended'], {cwd: EXTENDS_ROOT})('foo: bar')
86+
cli(['--extends', './extended'], {cwd: dir})('foo: bar')
7887
);
88+
7989
t.true(includes(actual.stdout, 'type must not be one of [foo]'));
8090
t.is(actual.code, 1);
91+
92+
await rm([dir])();
8193
});
8294

8395
test('should produce no error output with --quiet flag', async t => {
@@ -129,7 +141,9 @@ test('should pick up parser preset', async t => {
129141
const actual = await t.throws(cli([], {cwd})('type(scope)-ticket subject'));
130142
t.true(includes(actual.stdout, 'message may not be empty [subject-empty]'));
131143

132-
await cli(['--parser-preset', './parser-preset'], {cwd})('type(scope)-ticket subject');
144+
await cli(['--parser-preset', './parser-preset'], {cwd})(
145+
'type(scope)-ticket subject'
146+
);
133147
});
134148

135149
async function init(cwd) {
@@ -142,5 +156,9 @@ async function init(cwd) {
142156
}
143157

144158
function pkg(cwd) {
145-
return sander.writeFile(cwd, 'package.json', JSON.stringify({scripts: {commitmsg: `${CLI} -e`}}));
159+
return sander.writeFile(
160+
cwd,
161+
'package.json',
162+
JSON.stringify({scripts: {commitmsg: `${CLI} -e`}})
163+
);
146164
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
module.exports = {
2+
extends: ['./first-extended'],
3+
rules: {
4+
zero: 0
5+
}
6+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
module.exports = {
2+
extends: ['./second-extended'],
3+
rules: {
4+
one: 1
5+
}
6+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module.exports = {
2+
rules: {
3+
two: 2
4+
}
5+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"extends": ["./first-extended"],
3+
"rules": {
4+
"zero": 0
5+
}
6+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
module.exports = {
2+
extends: ['./second-extended'],
3+
rules: {
4+
one: 1
5+
}
6+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module.exports = {
2+
rules: {
3+
two: 2
4+
}
5+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
module.exports = {
2+
extends: ['./second-extended'],
3+
rules: {
4+
one: 1
5+
}
6+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module.exports = {
2+
rules: {
3+
two: 2
4+
}
5+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"commitlint": {
3+
"extends": ["./first-extended"],
4+
"rules": {
5+
"zero": 0
6+
}
7+
}
8+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
extends:
2+
- "./first-extended"
3+
rules:
4+
zero: 0
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
module.exports = {
2+
extends: ['./second-extended'],
3+
rules: {
4+
one: 1
5+
}
6+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module.exports = {
2+
rules: {
3+
two: 2
4+
}
5+
};

@commitlint/core/package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@
7878
"nyc": "10.3.2",
7979
"path-exists": "3.0.0",
8080
"resolve-from": "3.0.0",
81+
"sander": "^0.6.0",
8182
"rimraf": "2.6.1",
8283
"xo": "0.18.2"
8384
},
@@ -86,10 +87,10 @@
8687
"chalk": "^2.0.1",
8788
"conventional-changelog-angular": "^1.3.3",
8889
"conventional-commits-parser": "^1.3.0",
90+
"cosmiconfig": "^3.0.1",
8991
"find-up": "^2.1.0",
9092
"franc": "^2.0.0",
9193
"git-raw-commits": "^1.1.2",
92-
"import-from": "^2.1.0",
9394
"lodash": "^4.17.4",
9495
"mz": "^2.6.0",
9596
"path-exists": "^3.0.0",

@commitlint/core/src/load.js

+33-20
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import path from 'path';
2-
import importFrom from 'import-from';
32
import {entries, merge, mergeWith, pick} from 'lodash';
43
import rc from 'rc';
4+
import cosmiconfig from 'cosmiconfig';
55
import resolveFrom from 'resolve-from';
6+
import up from 'find-up';
67

78
import resolveExtends from './library/resolve-extends';
89
import executeRule from './library/execute-rule';
@@ -12,19 +13,23 @@ const valid = input => pick(input, 'extends', 'rules', 'parserPreset');
1213

1314
export default async (seed = {}) => {
1415
// Obtain config from .rc files
15-
const raw = file();
16-
16+
const raw = await file();
1717
// Merge passed config with file based options
1818
const config = valid(merge(raw, seed));
1919
const opts = merge({extends: [], rules: {}}, pick(config, 'extends'));
2020

2121
// Resolve parserPreset key
2222
if (typeof config.parserPreset === 'string') {
23-
const resolvedParserPreset = resolveFrom(process.cwd(), config.parserPreset);
23+
const resolvedParserPreset = resolveFrom(
24+
process.cwd(),
25+
config.parserPreset
26+
);
2427

2528
config.parserPreset = {
2629
name: config.parserPreset,
27-
path: `./${path.posix.relative(process.cwd(), resolvedParserPreset)}`.split(path.sep).join('/'),
30+
path: `./${path.posix.relative(process.cwd(), resolvedParserPreset)}`
31+
.split(path.sep)
32+
.join('/'),
2833
opts: require(resolvedParserPreset)
2934
};
3035
}
@@ -39,7 +44,10 @@ export default async (seed = {}) => {
3944
const preset = valid(mergeWith(extended, config, w));
4045

4146
// Await parser-preset if applicable
42-
if (typeof preset.parserPreset === 'object' && typeof preset.parserPreset.opts === 'object') {
47+
if (
48+
typeof preset.parserPreset === 'object' &&
49+
typeof preset.parserPreset.opts === 'object'
50+
) {
4351
preset.parserPreset.opts = await preset.parserPreset.opts;
4452
}
4553

@@ -73,14 +81,16 @@ export default async (seed = {}) => {
7381
}, preset);
7482
};
7583

76-
function file() {
84+
async function file() {
7785
const legacy = rc('conventional-changelog-lint');
7886
const legacyFound = typeof legacy.config === 'string';
87+
const explorer = cosmiconfig('commitlint', {
88+
rcExtensions: true,
89+
stopDir: await toplevel()
90+
});
91+
const config = await explorer.load('.');
7992

80-
const found = resolveable('./commitlint.config');
81-
const raw = found ? importFrom(process.cwd(), './commitlint.config') : {};
82-
83-
if (legacyFound && !found) {
93+
if (legacyFound && !config) {
8494
console.warn(
8595
`Using legacy ${path.relative(
8696
process.cwd(),
@@ -89,7 +99,7 @@ function file() {
8999
);
90100
}
91101

92-
if (legacyFound && found) {
102+
if (legacyFound && config) {
93103
console.warn(
94104
`Ignored legacy ${path.relative(
95105
process.cwd(),
@@ -98,18 +108,21 @@ function file() {
98108
);
99109
}
100110

101-
if (found) {
102-
return raw;
111+
if (config) {
112+
return config.config;
103113
}
104114

105115
return legacy;
106116
}
107117

108-
function resolveable(id) {
109-
try {
110-
resolveFrom(process.cwd(), id);
111-
return true;
112-
} catch (err) {
113-
return false;
118+
// Find the next git root
119+
// (start: string) => Promise<string | null>
120+
async function toplevel(cwd = process.cwd()) {
121+
const found = await up('.git', {cwd});
122+
123+
if (typeof found !== 'string') {
124+
return found;
114125
}
126+
127+
return path.join(found, '..');
115128
}

0 commit comments

Comments
 (0)