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

fix(conventional-commits): Support modern config builder functions #2546

Merged
merged 1 commit into from May 24, 2020
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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");
evocateur marked this conversation as resolved.
Show resolved Hide resolved

// 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