Skip to content

Commit

Permalink
fix(conventional-commits): support conventional-changelog-conventiona…
Browse files Browse the repository at this point in the history
…lcommits (lerna#2138)
  • Loading branch information
MunifTanjim committed Apr 17, 2020
1 parent 6c4ee52 commit ea2259c
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 12 deletions.
19 changes: 19 additions & 0 deletions commands/version/README.md
Expand Up @@ -166,6 +166,25 @@ Presets are names of built-in or installable configuration for conventional chan
Presets may be passed as the full name of the package, or the auto-expanded suffix
(e.g., `angular` is expanded to `conventional-changelog-angular`).

This option is can also be specified in `lerna.json` configuration:

```json
{
"changelogPreset": "angular"
}
```

If the preset exports a builder function (e.g. `conventional-changelog-conventionalcommits`), you can specify the [preset configuration](https://github.com/conventional-changelog/conventional-changelog-config-spec) too:

```json
{
"changelogPreset": {
"name": "conventionalcommits",
"issueUrlFormat": "{{host}}/{{owner}}/{{repository}}/issues/{{id}}"
}
}
```

### `--exact`

```sh
Expand Down
@@ -0,0 +1,27 @@
"use strict";

// https://git.io/vx5iq (conventional-changelog-angular/conventional-recommended-bump.js, etc)
const parserOpts = require("./parser-opts");
const writerOpts = require("./writer-opts");
const whatBump = require("./what-bump");

// https://git.io/fhyKK
module.exports = presetOpts;

function presetOpts(param) {
if (typeof param !== "function") {
return Promise.resolve(
Object.assign(param, {
parserOpts,
writerOpts,
whatBump,
})
);
}

process.nextTick(param, null, {
parserOpts,
writerOpts,
whatBump,
});
}
37 changes: 37 additions & 0 deletions core/conventional-commits/__tests__/conventional-commits.test.js
Expand Up @@ -12,6 +12,7 @@ const gitTag = require("@lerna-test/git-tag");

// file under test
const { recommendVersion, updateChangelog } = require("..");
const getChangelogConfig = require("../lib/get-changelog-config");

// stabilize changelog commit SHA and datestamp
expect.addSnapshotSerializer(require("@lerna-test/serialize-changelog"));
Expand Down Expand Up @@ -481,6 +482,42 @@ describe("conventional-commits", () => {
`);
});

it("supports config builder presets", async () => {
const cwd = await initFixture("fixed");

const configForPresetNameString = await getChangelogConfig("./scripts/config-builder-preset", cwd);
expect(configForPresetNameString).toBeDefined();

const presetConfigObject = { name: "./scripts/config-builder-preset", key: "value" };
const configForPresetConfigObject = await getChangelogConfig(presetConfigObject, cwd);

expect(configForPresetConfigObject).toBeDefined();
expect(configForPresetConfigObject.key).toBe(presetConfigObject.key);

await gitTag(cwd, "v1.0.0");

const [, pkg2] = await getPackages(cwd);

// make a change in package-2
await pkg2.set("changed", 1).serialize();
await gitAdd(cwd, pkg2.manifestLocation);
await gitCommit(cwd, "fix(pkg2): A commit using a legacy callback preset");

// update version
await pkg2.set("version", "1.0.1").serialize();

const leafChangelog = await updateChangelog(pkg2, "fixed", {
changelogPreset: "./scripts/config-builder-preset",
});

expect(leafChangelog.newEntry).toMatchInlineSnapshot(`
<a name="1.0.1"></a>
## <small>1.0.1 (YYYY-MM-DD)</small>
* fix(pkg2): A commit using a legacy callback preset
`);
});

it("updates independent changelogs", async () => {
const cwd = await initFixture("independent");

Expand Down
34 changes: 22 additions & 12 deletions core/conventional-commits/lib/get-changelog-config.js
Expand Up @@ -13,27 +13,37 @@ function isFunction(config) {
return Object.prototype.toString.call(config) === "[object Function]";
}

function resolveConfigPromise(presetPackageName) {
function resolveConfigPromise(presetPackageName, presetConfig) {
log.verbose("getChangelogConfig", "Attempting to resolve preset %j", presetPackageName);

// eslint-disable-next-line global-require, import/no-dynamic-require
let config = require(presetPackageName);

log.info("getChangelogConfig", "Successfully resolved preset %j", presetPackageName);

// legacy presets export an errback function instead of Q.all()
if (isFunction(config)) {
config = pify(config)();
try {
// try assuming config builder function first
config = config(presetConfig);
} catch (_) {
// legacy presets export an errback function instead of Q.all()
config = pify(config)();
}
}

return config;
}

function getChangelogConfig(changelogPreset = "conventional-changelog-angular", rootPath) {
let config = cfgCache.get(changelogPreset);
const presetName = typeof changelogPreset === "string" ? changelogPreset : changelogPreset.name;
const presetConfig = typeof changelogPreset === "object" ? changelogPreset : {};

const cacheKey = `${presetName}${presetConfig ? JSON.stringify(presetConfig) : ""}`;

let config = cfgCache.get(cacheKey);

if (!config) {
let presetPackageName = changelogPreset;
let presetPackageName = presetName;

// https://github.com/npm/npm-package-arg#result-object
const parsed = npa(presetPackageName, rootPath);
Expand All @@ -57,15 +67,15 @@ function getChangelogConfig(changelogPreset = "conventional-changelog-angular",

// Maybe it doesn't need an implicit 'conventional-changelog-' prefix?
try {
config = resolveConfigPromise(presetPackageName);
config = resolveConfigPromise(presetPackageName, presetConfig);

cfgCache.set(changelogPreset, config);
cfgCache.set(cacheKey, config);

// early exit, yay
return Promise.resolve(config);
} catch (err) {
log.verbose("getChangelogConfig", err.message);
log.info("getChangelogConfig", "Auto-prefixing conventional-changelog preset %j", changelogPreset);
log.info("getChangelogConfig", "Auto-prefixing conventional-changelog preset %j", presetName);

// probably a deep shorthand subpath :P
parsed.name = parsed.raw;
Expand All @@ -85,16 +95,16 @@ function getChangelogConfig(changelogPreset = "conventional-changelog-angular",
}

try {
config = resolveConfigPromise(presetPackageName);
config = resolveConfigPromise(presetPackageName, presetConfig);

cfgCache.set(changelogPreset, config);
cfgCache.set(cacheKey, config);
} catch (err) {
log.warn("getChangelogConfig", err.message);

throw new ValidationError(
"EPRESET",
`Unable to load conventional-changelog preset '${changelogPreset}'${
changelogPreset !== presetPackageName ? ` (${presetPackageName})` : ""
`Unable to load conventional-changelog preset '${presetName}'${
presetName !== presetPackageName ? ` (${presetPackageName})` : ""
}`
);
}
Expand Down

0 comments on commit ea2259c

Please sign in to comment.