Skip to content

Commit 1d74e46

Browse files
committed
feat: use cwd and env options passed by core
BREAKING CHANGE: require `semantic-release` >= `15.8.0`
1 parent e8c5604 commit 1d74e46

File tree

7 files changed

+76
-58
lines changed

7 files changed

+76
-58
lines changed

index.js

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,21 @@ const DEFAULT_RELEASE_RULES = require('./lib/default-release-rules');
1111
/**
1212
* Determine the type of release to create based on a list of commits.
1313
*
14-
* @param {Object} [pluginConfig={}] semantic-release configuration
14+
* @param {Object} pluginConfig The plugin configuration.
1515
* @param {String} pluginConfig.preset conventional-changelog preset ('angular', 'atom', 'codemirror', 'ember', 'eslint', 'express', 'jquery', 'jscs', 'jshint')
16-
* @param {String} pluginConfig.config requierable npm package with a custom conventional-changelog preset
17-
* @param {String|Array} pluginConfig.releaseRules a string to load an external module or an `Array` of rules.
18-
* @param {Object} pluginConfig.parserOpts additional `conventional-changelog-parser` options that will overwrite ones loaded by `preset` or `config`.
19-
* @param {Object} options semantic-release options
20-
* @param {Array} options.commits array of commits
16+
* @param {String} pluginConfig.config Requierable npm package with a custom conventional-changelog preset
17+
* @param {String|Array} pluginConfig.releaseRules A `String` to load an external module or an `Array` of rules.
18+
* @param {Object} pluginConfig.parserOpts Additional `conventional-changelog-parser` options that will overwrite ones loaded by `preset` or `config`.
19+
* @param {Object} context The semantic-release context.
20+
* @param {Array<Object>} context.commits The commits to analyze.
21+
* @param {String} context.cwd The current working directory.
2122
*
2223
* @returns {String|null} the type of release to create based on the list of commits or `null` if no release has to be done.
2324
*/
24-
async function commitAnalyzer(pluginConfig, {commits, logger}) {
25-
const releaseRules = loadReleaseRules(pluginConfig);
26-
const config = await loadParserConfig(pluginConfig);
25+
async function commitAnalyzer(pluginConfig, context) {
26+
const {commits, logger} = context;
27+
const releaseRules = loadReleaseRules(pluginConfig, context);
28+
const config = await loadParserConfig(pluginConfig, context);
2729
let releaseType = null;
2830

2931
filter(

lib/load-parser-config.js

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,22 @@ const conventionalChangelogAngular = require('conventional-changelog-angular');
55
/**
66
* Load `conventional-changelog-parser` options. Handle presets that return either a `Promise<Array>` or a `Promise<Function>`.
77
*
8-
* @param {Object} preset conventional-changelog preset ('angular', 'atom', 'codemirror', 'ember', 'eslint', 'express', 'jquery', 'jscs', 'jshint')
9-
* @param {string} config requierable npm package with a custom conventional-changelog preset
10-
* @param {Object} parserOpts additionnal `conventional-changelog-parser` options that will overwrite ones loaded by `preset` or `config`.
8+
* @param {Object} pluginConfig The plugin configuration.
9+
* @param {Object} pluginConfig.preset conventional-changelog preset ('angular', 'atom', 'codemirror', 'ember', 'eslint', 'express', 'jquery', 'jscs', 'jshint')
10+
* @param {String} pluginConfig.config Requierable npm package with a custom conventional-changelog preset
11+
* @param {Object} pluginConfig.parserOpts Additionnal `conventional-changelog-parser` options that will overwrite ones loaded by `preset` or `config`.
12+
* @param {Object} context The semantic-release context.
13+
* @param {String} context.cwd The current working directory.
1114
* @return {Promise<Object>} a `Promise` that resolve to the `conventional-changelog-parser` options.
1215
*/
13-
module.exports = async ({preset, config, parserOpts}) => {
16+
module.exports = async ({preset, config, parserOpts}, {cwd}) => {
1417
let loadedConfig;
1518

1619
if (preset) {
1720
const presetPackage = `conventional-changelog-${preset.toLowerCase()}`;
18-
loadedConfig = importFrom.silent(__dirname, presetPackage) || importFrom(process.cwd(), presetPackage);
21+
loadedConfig = importFrom.silent(__dirname, presetPackage) || importFrom(cwd, presetPackage);
1922
} else if (config) {
20-
loadedConfig = importFrom.silent(__dirname, config) || importFrom(process.cwd(), config);
23+
loadedConfig = importFrom.silent(__dirname, config) || importFrom(cwd, config);
2124
} else {
2225
loadedConfig = conventionalChangelogAngular;
2326
}

lib/load-release-rules.js

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,20 @@ const RELEASE_TYPES = require('./default-release-types');
77
* If `releaseRules` parameter is a `string` then load it as an external module with `require`.
88
* Verifies that the loaded/parameter `releaseRules` is an `Array` and each element has a valid `release` attribute.
99
*
10-
* @param {string|Array} releaseRules a string to load an external module or an `Array` of rules.
10+
* @param {Object} pluginConfig The plugin configuration.
11+
* @param {String|Array} pluginConfig.releaseRules A `String` to load an external module or an `Array` of rules.
12+
* @param {Object} context The semantic-release context.
13+
* @param {String} context.cwd The current working directory.
14+
*
1115
* @return {Array} the loaded and validated `releaseRules`.
1216
*/
13-
module.exports = ({releaseRules}) => {
17+
module.exports = ({releaseRules}, {cwd}) => {
1418
let loadedReleaseRules;
1519

1620
if (releaseRules) {
1721
loadedReleaseRules =
1822
typeof releaseRules === 'string'
19-
? importFrom.silent(__dirname, releaseRules) || importFrom(process.cwd(), releaseRules)
23+
? importFrom.silent(__dirname, releaseRules) || importFrom(cwd, releaseRules)
2024
: releaseRules;
2125

2226
if (!Array.isArray(loadedReleaseRules)) {

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@
7171
],
7272
"all": true
7373
},
74+
"peerDependencies": {
75+
"semantic-release": ">=15.8.0 <16.0.0"
76+
},
7477
"prettier": {
7578
"printWidth": 120,
7679
"trailingComma": "es5"

test/integration.test.js

Lines changed: 23 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import test from 'ava';
22
import {stub} from 'sinon';
33
import commitAnalyzer from '..';
44

5+
const cwd = process.cwd();
6+
57
test.beforeEach(t => {
68
const log = stub();
79
t.context.log = log;
@@ -10,7 +12,7 @@ test.beforeEach(t => {
1012

1113
test('Parse with "conventional-changelog-angular" by default', async t => {
1214
const commits = [{message: 'fix(scope1): First fix'}, {message: 'feat(scope2): Second feature'}];
13-
const releaseType = await commitAnalyzer({}, {commits, logger: t.context.logger});
15+
const releaseType = await commitAnalyzer({}, {cwd, commits, logger: t.context.logger});
1416

1517
t.is(releaseType, 'minor');
1618
t.true(t.context.log.calledWith('Analyzing commit: %s', commits[0].message));
@@ -22,7 +24,7 @@ test('Parse with "conventional-changelog-angular" by default', async t => {
2224

2325
test('Accept "preset" option', async t => {
2426
const commits = [{message: 'Fix: First fix (fixes #123)'}, {message: 'Update: Second feature (fixes #456)'}];
25-
const releaseType = await commitAnalyzer({preset: 'eslint'}, {commits, logger: t.context.logger});
27+
const releaseType = await commitAnalyzer({preset: 'eslint'}, {cwd, commits, logger: t.context.logger});
2628

2729
t.is(releaseType, 'minor');
2830
t.true(t.context.log.calledWith('Analyzing commit: %s', commits[0].message));
@@ -36,7 +38,7 @@ test('Accept "config" option', async t => {
3638
const commits = [{message: 'Fix: First fix (fixes #123)'}, {message: 'Update: Second feature (fixes #456)'}];
3739
const releaseType = await commitAnalyzer(
3840
{config: 'conventional-changelog-eslint'},
39-
{commits, logger: t.context.logger}
41+
{cwd, commits, logger: t.context.logger}
4042
);
4143

4244
t.is(releaseType, 'minor');
@@ -54,7 +56,7 @@ test('Accept a "parseOpts" object as option', async t => {
5456
];
5557
const releaseType = await commitAnalyzer(
5658
{parserOpts: {headerPattern: /^%%(.*?)%% (.*)$/, headerCorrespondence: ['tag', 'shortDesc']}},
57-
{commits, logger: t.context.logger}
59+
{cwd, commits, logger: t.context.logger}
5860
);
5961

6062
t.is(releaseType, 'minor');
@@ -72,7 +74,7 @@ test('Accept a partial "parseOpts" object as option', async t => {
7274
config: 'conventional-changelog-eslint',
7375
parserOpts: {headerPattern: /^%%(.*?)%% (.*)$/, headerCorrespondence: ['type', 'shortDesc']},
7476
},
75-
{commits, logger: t.context.logger}
77+
{cwd, commits, logger: t.context.logger}
7678
);
7779

7880
t.is(releaseType, 'patch');
@@ -89,7 +91,7 @@ test('Exclude commits if they have a matching revert commits', async t => {
8991
{hash: '456', message: 'revert: feat(scope): First feature\n\nThis reverts commit 123.\n'},
9092
{message: 'fix(scope): First fix'},
9193
];
92-
const releaseType = await commitAnalyzer({}, {commits, logger: t.context.logger});
94+
const releaseType = await commitAnalyzer({}, {cwd, commits, logger: t.context.logger});
9395

9496
t.is(releaseType, 'patch');
9597
t.true(t.context.log.calledWith('Analyzing commit: %s', commits[2].message));
@@ -101,7 +103,7 @@ test('Accept a "releaseRules" option that reference a requierable module', async
101103
const commits = [{message: 'fix(scope1): First fix'}, {message: 'feat(scope2): Second feature'}];
102104
const releaseType = await commitAnalyzer(
103105
{releaseRules: './test/fixtures/release-rules'},
104-
{commits, logger: t.context.logger}
106+
{cwd, commits, logger: t.context.logger}
105107
);
106108

107109
t.is(releaseType, 'minor');
@@ -117,7 +119,7 @@ test('Return "major" if there is a breaking change, using default releaseRules',
117119
{message: 'Fix: First fix (fixes #123)'},
118120
{message: 'Update: Second feature (fixes #456) \n\n BREAKING CHANGE: break something'},
119121
];
120-
const releaseType = await commitAnalyzer({preset: 'eslint'}, {commits, logger: t.context.logger});
122+
const releaseType = await commitAnalyzer({preset: 'eslint'}, {cwd, commits, logger: t.context.logger});
121123

122124
t.is(releaseType, 'major');
123125
t.true(t.context.log.calledWith('Analyzing commit: %s', commits[0].message));
@@ -129,7 +131,7 @@ test('Return "major" if there is a breaking change, using default releaseRules',
129131

130132
test('Return "patch" if there is only types set to "patch", using default releaseRules', async t => {
131133
const commits = [{message: 'fix: First fix (fixes #123)'}, {message: 'perf: perf improvement'}];
132-
const releaseType = await commitAnalyzer({}, {commits, logger: t.context.logger});
134+
const releaseType = await commitAnalyzer({}, {cwd, commits, logger: t.context.logger});
133135

134136
t.is(releaseType, 'patch');
135137
t.true(t.context.log.calledWith('Analyzing commit: %s', commits[0].message));
@@ -142,11 +144,8 @@ test('Return "patch" if there is only types set to "patch", using default releas
142144
test('Allow to use regex in "releaseRules" configuration', async t => {
143145
const commits = [{message: 'Chore: First chore (fixes #123)'}, {message: 'Docs: update README (fixes #456)'}];
144146
const releaseType = await commitAnalyzer(
145-
{
146-
preset: 'eslint',
147-
releaseRules: [{tag: 'Chore', release: 'patch'}, {message: '/README/', release: 'minor'}],
148-
},
149-
{commits, logger: t.context.logger}
147+
{preset: 'eslint', releaseRules: [{tag: 'Chore', release: 'patch'}, {message: '/README/', release: 'minor'}]},
148+
{cwd, commits, logger: t.context.logger}
150149
);
151150

152151
t.is(releaseType, 'minor');
@@ -159,7 +158,7 @@ test('Allow to use regex in "releaseRules" configuration', async t => {
159158

160159
test('Return "null" if no rule match', async t => {
161160
const commits = [{message: 'doc: doc update'}, {message: 'chore: Chore'}];
162-
const releaseType = await commitAnalyzer({}, {commits, logger: t.context.logger});
161+
const releaseType = await commitAnalyzer({}, {cwd, commits, logger: t.context.logger});
163162

164163
t.is(releaseType, null);
165164
t.true(t.context.log.calledWith('Analyzing commit: %s', commits[0].message));
@@ -173,7 +172,7 @@ test('Process rules in order and apply highest match', async t => {
173172
const commits = [{message: 'Chore: First chore (fixes #123)'}, {message: 'Docs: update README (fixes #456)'}];
174173
const releaseType = await commitAnalyzer(
175174
{preset: 'eslint', releaseRules: [{tag: 'Chore', release: 'minor'}, {tag: 'Chore', release: 'patch'}]},
176-
{commits, logger: t.context.logger}
175+
{cwd, commits, logger: t.context.logger}
177176
);
178177

179178
t.is(releaseType, 'minor');
@@ -191,7 +190,7 @@ test('Process rules in order and apply highest match from config even if default
191190
];
192191
const releaseType = await commitAnalyzer(
193192
{preset: 'eslint', releaseRules: [{tag: 'Chore', release: 'patch'}, {breaking: true, release: 'minor'}]},
194-
{commits, logger: t.context.logger}
193+
{cwd, commits, logger: t.context.logger}
195194
);
196195

197196
t.is(releaseType, 'minor');
@@ -206,7 +205,7 @@ test('Use default "releaseRules" if none of provided match', async t => {
206205
const commits = [{message: 'Chore: First chore'}, {message: 'Update: new feature'}];
207206
const releaseType = await commitAnalyzer(
208207
{preset: 'eslint', releaseRules: [{tag: 'Chore', release: 'patch'}]},
209-
{commits, logger: t.context.logger}
208+
{cwd, commits, logger: t.context.logger}
210209
);
211210

212211
t.is(releaseType, 'minor');
@@ -218,40 +217,40 @@ test('Use default "releaseRules" if none of provided match', async t => {
218217
});
219218

220219
test('Throw error if "preset" doesn`t exist', async t => {
221-
const error = await t.throws(commitAnalyzer({preset: 'unknown-preset'}, {}));
220+
const error = await t.throws(commitAnalyzer({preset: 'unknown-preset'}, {cwd}));
222221

223222
t.is(error.code, 'MODULE_NOT_FOUND');
224223
});
225224

226225
test('Throw error if "releaseRules" is not an Array or a String', async t => {
227226
await t.throws(
228-
commitAnalyzer({releaseRules: {}}, {}),
227+
commitAnalyzer({releaseRules: {}}, {cwd}),
229228
/Error in commit-analyzer configuration: "releaseRules" must be an array of rules/
230229
);
231230
});
232231

233232
test('Throw error if "releaseRules" option reference a requierable module that is not an Array or a String', async t => {
234233
await t.throws(
235-
commitAnalyzer({releaseRules: './test/fixtures/release-rules-invalid'}, {}),
234+
commitAnalyzer({releaseRules: './test/fixtures/release-rules-invalid'}, {cwd}),
236235
/Error in commit-analyzer configuration: "releaseRules" must be an array of rules/
237236
);
238237
});
239238

240239
test('Throw error if "config" doesn`t exist', async t => {
241240
const commits = [{message: 'Fix: First fix (fixes #123)'}, {message: 'Update: Second feature (fixes #456)'}];
242-
const error = await t.throws(commitAnalyzer({config: 'unknown-config'}, {commits, logger: t.context.logger}));
241+
const error = await t.throws(commitAnalyzer({config: 'unknown-config'}, {cwd, commits, logger: t.context.logger}));
243242

244243
t.is(error.code, 'MODULE_NOT_FOUND');
245244
});
246245

247246
test('Throw error if "releaseRules" reference invalid commit type', async t => {
248247
await t.throws(
249-
commitAnalyzer({preset: 'eslint', releaseRules: [{tag: 'Update', release: 'invalid'}]}, {}),
248+
commitAnalyzer({preset: 'eslint', releaseRules: [{tag: 'Update', release: 'invalid'}]}, {cwd}),
250249
/Error in commit-analyzer configuration: "invalid" is not a valid release type\. Valid values are:\[?.*\]/
251250
);
252251
});
253252

254253
test('Re-Throw error from "conventional-changelog-parser"', async t => {
255254
const commits = [{message: 'Fix: First fix (fixes #123)'}, {message: 'Update: Second feature (fixes #456)'}];
256-
await t.throws(commitAnalyzer({parserOpts: {headerPattern: '\\'}}, {commits, logger: t.context.logger}));
255+
await t.throws(commitAnalyzer({parserOpts: {headerPattern: '\\'}}, {cwd, commits, logger: t.context.logger}));
257256
});

test/load-parser-config.test.js

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import test from 'ava';
22
import loadParserConfig from '../lib/load-parser-config';
33

4+
const cwd = process.cwd();
5+
46
/**
57
* AVA macro to verify that `loadParserConfig` return a parserOpts object.
68
*
@@ -9,7 +11,7 @@ import loadParserConfig from '../lib/load-parser-config';
911
* @param {[type]} preset the `conventional-changelog` preset to test.
1012
*/
1113
async function loadPreset(t, preset) {
12-
t.truthy((await loadParserConfig({preset})).headerPattern);
14+
t.truthy((await loadParserConfig({preset}, {cwd})).headerPattern);
1315
}
1416
loadPreset.title = (providedTitle, preset) => `${providedTitle} Load "${preset}" preset`.trim();
1517

@@ -21,17 +23,17 @@ loadPreset.title = (providedTitle, preset) => `${providedTitle} Load "${preset}"
2123
* @param {[type]} config the `conventional-changelog` config to test.
2224
*/
2325
async function loadConfig(t, config) {
24-
t.truthy((await loadParserConfig({config: `conventional-changelog-${config}`})).headerPattern);
26+
t.truthy((await loadParserConfig({config: `conventional-changelog-${config}`}, {cwd})).headerPattern);
2527
}
2628
loadConfig.title = (providedTitle, config) => `${providedTitle} Load "${config}" config`.trim();
2729

2830
test('Load "conventional-changelog-angular" by default', async t => {
29-
t.deepEqual(await loadParserConfig({}), (await require('conventional-changelog-angular')).parserOpts);
31+
t.deepEqual(await loadParserConfig({}, {cwd}), (await require('conventional-changelog-angular')).parserOpts);
3032
});
3133

3234
test('Accept a "parserOpts" object as option', async t => {
3335
const customParserOpts = {headerPattern: /^##(.*?)## (.*)$/, headerCorrespondence: ['tag', 'shortDesc']};
34-
const parserOpts = await loadParserConfig({parserOpts: customParserOpts});
36+
const parserOpts = await loadParserConfig({parserOpts: customParserOpts}, {cwd});
3537

3638
t.is(customParserOpts.headerPattern, parserOpts.headerPattern);
3739
t.deepEqual(customParserOpts.headerCorrespondence, parserOpts.headerCorrespondence);
@@ -40,7 +42,7 @@ test('Accept a "parserOpts" object as option', async t => {
4042

4143
test('Accept a partial "parserOpts" object as option that overlaod a preset', async t => {
4244
const customParserOpts = {headerPattern: /^##(.*?)## (.*)$/, headerCorrespondence: ['tag', 'shortDesc']};
43-
const parserOpts = await loadParserConfig({parserOpts: customParserOpts, preset: 'angular'});
45+
const parserOpts = await loadParserConfig({parserOpts: customParserOpts, preset: 'angular'}, {cwd});
4446

4547
t.is(customParserOpts.headerPattern, parserOpts.headerPattern);
4648
t.deepEqual(customParserOpts.headerCorrespondence, parserOpts.headerCorrespondence);
@@ -49,7 +51,10 @@ test('Accept a partial "parserOpts" object as option that overlaod a preset', as
4951

5052
test('Accept a partial "parserOpts" object as option that overlaod a config', async t => {
5153
const customParserOpts = {headerPattern: /^##(.*?)## (.*)$/, headerCorrespondence: ['tag', 'shortDesc']};
52-
const parserOpts = await loadParserConfig({parserOpts: customParserOpts, config: 'conventional-changelog-angular'});
54+
const parserOpts = await loadParserConfig(
55+
{parserOpts: customParserOpts, config: 'conventional-changelog-angular'},
56+
{cwd}
57+
);
5358

5459
t.is(customParserOpts.headerPattern, parserOpts.headerPattern);
5560
t.deepEqual(customParserOpts.headerCorrespondence, parserOpts.headerCorrespondence);
@@ -70,13 +75,13 @@ test(loadPreset, 'jshint');
7075
test(loadConfig, 'jshint');
7176

7277
test('Throw error if "config" doesn`t exist', async t => {
73-
const error = await t.throws(loadParserConfig({config: 'unknown-config'}));
78+
const error = await t.throws(loadParserConfig({config: 'unknown-config'}, {cwd}));
7479

7580
t.is(error.code, 'MODULE_NOT_FOUND');
7681
});
7782

7883
test('Throw error if "preset" doesn`t exist', async t => {
79-
const error = await t.throws(loadParserConfig({preset: 'unknown-preset'}));
84+
const error = await t.throws(loadParserConfig({preset: 'unknown-preset'}, {cwd}));
8085

8186
t.is(error.code, 'MODULE_NOT_FOUND');
8287
});

0 commit comments

Comments
 (0)