Compare commits
No commits in common. "04e9e5f71ab354f6a1650e8fbd18c164f04fb5ec" and "1c7b6158f4a4b933614bb513394472f35ba4e7c0" have entirely different histories.
04e9e5f71a
...
1c7b6158f4
@ -2,20 +2,21 @@ project:
|
|||||||
name: changelord
|
name: changelord
|
||||||
homepage: https://git.babyl.ca/yanick/changelord.js
|
homepage: https://git.babyl.ca/yanick/changelord.js
|
||||||
with_stats: true
|
with_stats: true
|
||||||
next_directory: ./changelog-next
|
|
||||||
releases:
|
releases:
|
||||||
- version: NEXT
|
- version: NEXT
|
||||||
changes:
|
changes:
|
||||||
|
- add `git-gather` command
|
||||||
- type: feat
|
- type: feat
|
||||||
desc: add `git-gather` command
|
desc: " add 'next' to alias to 'upcoming'"
|
||||||
- type: feat
|
commit: 363c195477231a6b3b770e74ebfe316296ec5af2
|
||||||
desc: add 'next' to alias to 'upcoming'
|
|
||||||
- type: feat
|
- type: feat
|
||||||
desc: cutting a release also add a new NEXT release
|
desc: cutting a release also add a new NEXT release
|
||||||
|
commit: 167f631d1fe4eadba3ed5fdadbe378b8255d4ad2
|
||||||
- type: feat
|
- type: feat
|
||||||
desc: git-gather also filters on descs
|
desc: git-gather also filters on descs
|
||||||
- type: feat
|
- type: feat
|
||||||
desc: add the validate command
|
desc: add the validate command
|
||||||
|
commit: 5ba75a8e3d42f633e38c3584898ef0085c48fb04
|
||||||
- version: 0.1.0
|
- version: 0.1.0
|
||||||
changes:
|
changes:
|
||||||
- port the core of the Perl changelord to JavaScript.
|
- port the core of the Perl changelord to JavaScript.
|
||||||
|
15
README.md
15
README.md
@ -11,14 +11,6 @@ read its [introductory article][blog] on my blog.
|
|||||||
|
|
||||||
pnpm install changelord
|
pnpm install changelord
|
||||||
|
|
||||||
## `changelog-next` directory
|
|
||||||
|
|
||||||
If you want to mininize merge conflicts in `CHANGELOG.yml`,
|
|
||||||
you can set the option `project.next_directory` to a directory (typically
|
|
||||||
`./changelog-next`) that will hold yaml files containing the
|
|
||||||
changes for the NEXT release. Each of those files is expected to
|
|
||||||
have a list of changes.
|
|
||||||
|
|
||||||
## CLI commands
|
## CLI commands
|
||||||
|
|
||||||
### Global options
|
### Global options
|
||||||
@ -49,9 +41,6 @@ sections.
|
|||||||
|
|
||||||
Adds an entry to the `NEXT` release.
|
Adds an entry to the `NEXT` release.
|
||||||
|
|
||||||
If `project.next_directory` is defined, the entry will be added to that
|
|
||||||
directory instead of directly into `CHANGELOG.yml`.
|
|
||||||
|
|
||||||
$ changelord add --type=maint added a changelog to the project.
|
$ changelord add --type=maint added a changelog to the project.
|
||||||
|
|
||||||
#### Options
|
#### Options
|
||||||
@ -73,10 +62,6 @@ Cuts the next release. That is, resolves the `NEXT` version number based on the
|
|||||||
latest version and the changes in the `NEXT` section, and sets its date as
|
latest version and the changes in the `NEXT` section, and sets its date as
|
||||||
today. Modifies the source file with the result.
|
today. Modifies the source file with the result.
|
||||||
|
|
||||||
If the `project.next_directory` option is present,
|
|
||||||
all the changes in that directory are
|
|
||||||
merged to `CHANGELOG.yml` and the files themselves are deleted.
|
|
||||||
|
|
||||||
#### Options
|
#### Options
|
||||||
|
|
||||||
- `--dry` -- Resolves the next version but only outputs the resulting section
|
- `--dry` -- Resolves the next version but only outputs the resulting section
|
||||||
|
@ -1,2 +0,0 @@
|
|||||||
- desc: support changelog-next directory
|
|
||||||
type: feat
|
|
@ -24,15 +24,11 @@
|
|||||||
"author": "Yanick Champoux <yanick@babyl.ca> (http://techblog.babyl.ca/)",
|
"author": "Yanick Champoux <yanick@babyl.ca> (http://techblog.babyl.ca/)",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sindresorhus/slugify": "^2.2.1",
|
|
||||||
"@yanick/updeep-remeda": "^2.2.0",
|
"@yanick/updeep-remeda": "^2.2.0",
|
||||||
"ajv": "^8.12.0",
|
"ajv": "^8.12.0",
|
||||||
"consola": "^3.1.0",
|
"consola": "^3.1.0",
|
||||||
"filenamify": "^6.0.0",
|
|
||||||
"fs-extra": "^11.1.1",
|
"fs-extra": "^11.1.1",
|
||||||
"globby": "^13.1.4",
|
|
||||||
"markdown-utils": "^1.0.0",
|
"markdown-utils": "^1.0.0",
|
||||||
"nanoid": "^4.0.2",
|
|
||||||
"remeda": "^1.14.0",
|
"remeda": "^1.14.0",
|
||||||
"semver": "^7.5.0",
|
"semver": "^7.5.0",
|
||||||
"simple-git": "^3.18.0",
|
"simple-git": "^3.18.0",
|
||||||
|
@ -50,11 +50,6 @@ export default {
|
|||||||
with_stats: {
|
with_stats: {
|
||||||
description: "if true, add git statistics when bumping the version.",
|
description: "if true, add git statistics when bumping the version.",
|
||||||
},
|
},
|
||||||
next_directory: {
|
|
||||||
type: "string",
|
|
||||||
description:
|
|
||||||
"directory where the changes for the NEXT release are stashed",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
type: "object",
|
type: "object",
|
||||||
},
|
},
|
||||||
|
@ -10,8 +10,6 @@ import u from "@yanick/updeep-remeda";
|
|||||||
import { once } from "remeda";
|
import { once } from "remeda";
|
||||||
import simpleGit from "simple-git";
|
import simpleGit from "simple-git";
|
||||||
import Ajv from "ajv";
|
import Ajv from "ajv";
|
||||||
import { nanoid } from "nanoid";
|
|
||||||
import slugify from "@sindresorhus/slugify";
|
|
||||||
|
|
||||||
import print from "./command/print.js";
|
import print from "./command/print.js";
|
||||||
import init from "./command/init.js";
|
import init from "./command/init.js";
|
||||||
@ -23,8 +21,6 @@ import latest, { latest_version } from "./command/latest-version.js";
|
|||||||
import validate from "./command/validate.js";
|
import validate from "./command/validate.js";
|
||||||
import git_gather from "./command/git-gather.js";
|
import git_gather from "./command/git-gather.js";
|
||||||
import schemaV1 from "./changelog-schema.js";
|
import schemaV1 from "./changelog-schema.js";
|
||||||
import { globby } from "globby";
|
|
||||||
import { flatMap } from "remeda";
|
|
||||||
|
|
||||||
consola.raw = (...args) => console.log(...args);
|
consola.raw = (...args) => console.log(...args);
|
||||||
|
|
||||||
@ -36,27 +32,6 @@ yargs(hideBin(process.argv))
|
|||||||
fs
|
fs
|
||||||
.readFile(config.source, "utf-8")
|
.readFile(config.source, "utf-8")
|
||||||
.then(yaml.parse)
|
.then(yaml.parse)
|
||||||
.then(async (doc) => {
|
|
||||||
if (!doc.project.next_directory) return doc;
|
|
||||||
|
|
||||||
const changes = await globby([
|
|
||||||
doc.project.next_directory + "/*.yml",
|
|
||||||
doc.project.next_directory + "/*.yaml",
|
|
||||||
])
|
|
||||||
.then((files) =>
|
|
||||||
Promise.all(
|
|
||||||
files.map((f) => fs.readFile(f, "utf-8").then(yaml.parse))
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.then((r) => r.flat());
|
|
||||||
|
|
||||||
if (changes.length)
|
|
||||||
doc.releases
|
|
||||||
.find((r) => r.version === "NEXT")
|
|
||||||
.changes.push(...changes);
|
|
||||||
|
|
||||||
return doc;
|
|
||||||
})
|
|
||||||
.then((doc) => {
|
.then((doc) => {
|
||||||
const ajv = new Ajv();
|
const ajv = new Ajv();
|
||||||
const validate = ajv.compile(schemaV1);
|
const validate = ajv.compile(schemaV1);
|
||||||
@ -67,13 +42,6 @@ yargs(hideBin(process.argv))
|
|||||||
throw "changelog is invalid";
|
throw "changelog is invalid";
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
config.delete_next_dir_entries = async () => {
|
|
||||||
const changelog = await config.changelog();
|
|
||||||
return globby([
|
|
||||||
changelog.project.next_directory + "/*.yml",
|
|
||||||
changelog.project.next_directory + "/*.yaml",
|
|
||||||
]).then((files) => Promise.all(files.map((f) => fs.remove(f))));
|
|
||||||
};
|
|
||||||
config.save_changelog = async (changelog) => {
|
config.save_changelog = async (changelog) => {
|
||||||
if (!changelog) changelog = await config.changelog();
|
if (!changelog) changelog = await config.changelog();
|
||||||
return fs.writeFile(config.source, yaml.stringify(changelog));
|
return fs.writeFile(config.source, yaml.stringify(changelog));
|
||||||
@ -86,39 +54,12 @@ yargs(hideBin(process.argv))
|
|||||||
argv.yargs = yargs;
|
argv.yargs = yargs;
|
||||||
|
|
||||||
argv.add_to_next = async (entry) => {
|
argv.add_to_next = async (entry) => {
|
||||||
const dir = await argv.changelog().then((c) => c.project.next_directory);
|
const changelog = yaml.parse(await fs.readFile(argv.source, "utf-8"));
|
||||||
|
|
||||||
if (dir) {
|
|
||||||
await fs.ensureDir(dir);
|
|
||||||
const filename = join(
|
|
||||||
dir,
|
|
||||||
[
|
|
||||||
new Date().toISOString(),
|
|
||||||
entry.ticket,
|
|
||||||
entry.feat,
|
|
||||||
slugify(entry.desc, {
|
|
||||||
separator: "_",
|
|
||||||
}).slice(0, 10),
|
|
||||||
]
|
|
||||||
.filter((x) => x)
|
|
||||||
.join("-") + ".yml"
|
|
||||||
);
|
|
||||||
argv.consola.info(`writing change to ${filename}`);
|
|
||||||
if (fs.existsSync(filename)) {
|
|
||||||
argv.consola.error(`file ${filename} already exist`);
|
|
||||||
yargs.exit(1);
|
|
||||||
}
|
|
||||||
if (Object.keys(entry).length === 1) {
|
|
||||||
entry = entry.desc;
|
|
||||||
}
|
|
||||||
return fs.writeFile(filename, yaml.stringify([entry]));
|
|
||||||
}
|
|
||||||
|
|
||||||
const changelog = await argv.changelog();
|
|
||||||
|
|
||||||
let next = changelog.releases.find(u.matches({ version: "NEXT" }));
|
let next = changelog.releases.find(u.matches({ version: "NEXT" }));
|
||||||
if (!next) {
|
if (!next) {
|
||||||
changelog.releases.unshift(base_next_version);
|
next = { version: "NEXT", changes: [] };
|
||||||
|
changelog.releases.unshift(next);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Object.keys(entry).length === 1) {
|
if (Object.keys(entry).length === 1) {
|
||||||
@ -127,7 +68,7 @@ yargs(hideBin(process.argv))
|
|||||||
|
|
||||||
next.changes.push(entry);
|
next.changes.push(entry);
|
||||||
|
|
||||||
return argv.save_changelog();
|
return fs.writeFile(argv.source, yaml.stringify(changelog));
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
.default("source", join(process.cwd(), "CHANGELOG.yml"))
|
.default("source", join(process.cwd(), "CHANGELOG.yml"))
|
||||||
|
@ -15,7 +15,7 @@ const handler = async (config) => {
|
|||||||
|
|
||||||
config.consola.start(`adding '${entry.desc}' to the changelog`);
|
config.consola.start(`adding '${entry.desc}' to the changelog`);
|
||||||
|
|
||||||
await config.add_to_next(entry);
|
config.add_to_next(entry);
|
||||||
|
|
||||||
config.consola.success("done!");
|
config.consola.success("done!");
|
||||||
};
|
};
|
||||||
|
@ -62,12 +62,6 @@ const handler = async (config) => {
|
|||||||
config.consola.info("running in dry mode, not saving\n", next);
|
config.consola.info("running in dry mode, not saving\n", next);
|
||||||
} else {
|
} else {
|
||||||
await config.save_changelog(changelog);
|
await config.save_changelog(changelog);
|
||||||
if (changelog.project?.next_directory) {
|
|
||||||
config.consola.info(
|
|
||||||
`removing files in ${changelog.project.next_directory}`
|
|
||||||
);
|
|
||||||
await config.delete_next_dir_entries();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
config.consola.success(`version ${next.version} is cut!`);
|
config.consola.success(`version ${next.version} is cut!`);
|
||||||
|
@ -4,7 +4,7 @@ import yaml from "yaml";
|
|||||||
import { render_release } from "./print.js";
|
import { render_release } from "./print.js";
|
||||||
|
|
||||||
export async function next_release() {
|
export async function next_release() {
|
||||||
const source = await this.changelog();
|
const source = await fs.readFile(this.source, "utf-8").then(yaml.parse);
|
||||||
return (
|
return (
|
||||||
source.releases.find(u.matches({ version: "NEXT" })) ?? {
|
source.releases.find(u.matches({ version: "NEXT" })) ?? {
|
||||||
version: "NEXT",
|
version: "NEXT",
|
||||||
@ -14,14 +14,14 @@ export async function next_release() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const handler = async (config) => {
|
const handler = async (config) => {
|
||||||
const source = await config.changelog();
|
const source = await fs.readFile(config.source, "utf-8").then(yaml.parse);
|
||||||
|
|
||||||
const { body } = render_release(
|
const res = render_release(
|
||||||
{ ...config, next: true },
|
{ ...config, next: true },
|
||||||
source
|
source
|
||||||
)(await config.next_release());
|
)(source.releases.find(u.matches({ version: "NEXT" })));
|
||||||
|
|
||||||
config.consola.raw("\n" + body);
|
config.consola.raw("\n" + res.body);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@ -1,29 +0,0 @@
|
|||||||
import { test, expect, vi } from "vitest";
|
|
||||||
import upcoming from "./upcoming.js";
|
|
||||||
|
|
||||||
test("basic", async () => {
|
|
||||||
const changelog = {
|
|
||||||
releases: [{ version: "NEXT", changes: [] }, { version: "1.0.0" }],
|
|
||||||
change_types: [],
|
|
||||||
};
|
|
||||||
|
|
||||||
const noop = () => {};
|
|
||||||
const config = {
|
|
||||||
consola: {
|
|
||||||
start: noop,
|
|
||||||
raw: vi.fn(),
|
|
||||||
},
|
|
||||||
changelog: () => changelog,
|
|
||||||
next_release: () => ({
|
|
||||||
changes: [],
|
|
||||||
}),
|
|
||||||
latest_version: () => ({ version: "1.2.3" }),
|
|
||||||
git: () => ({
|
|
||||||
log: () => ({ all: [] }),
|
|
||||||
}),
|
|
||||||
};
|
|
||||||
|
|
||||||
await upcoming.handler(config);
|
|
||||||
|
|
||||||
expect(config.consola.raw).toHaveBeenCalled();
|
|
||||||
});
|
|
Loading…
Reference in New Issue
Block a user