diff --git a/CHANGELOG.md b/CHANGELOG.md index 44b4ee794..1361322d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,10 +4,15 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/) and this project adheres to [Semantic Versioning](https://semver.org/). -## [2.5.4] - Unreleased +## [2.6.0] - 2024-07-21 ### Added +- New option `--no-v-prefix` to generate the tag names without prepending `v` [#43] +- New option `--no-sort-releases` to disable sorting of releases [#51] - `--help, -h` flag [#45]. +### Fixed +- Updated dependencies + ## [2.5.3] - 2023-11-19 ### Fixed - Improve URL normalization in CLI [#42] @@ -97,9 +102,11 @@ New version merging Deno and Node code using Deno's `dnt` package. [#40]: https://github.com/oscarotero/keep-a-changelog/issues/40 [#41]: https://github.com/oscarotero/keep-a-changelog/issues/41 [#42]: https://github.com/oscarotero/keep-a-changelog/issues/42 +[#43]: https://github.com/oscarotero/keep-a-changelog/issues/43 [#45]: https://github.com/oscarotero/keep-a-changelog/issues/45 +[#51]: https://github.com/oscarotero/keep-a-changelog/issues/51 -[2.5.4]: https://github.com/oscarotero/keep-a-changelog/compare/v2.5.3...HEAD +[2.6.0]: https://github.com/oscarotero/keep-a-changelog/compare/v2.5.3...v2.6.0 [2.5.3]: https://github.com/oscarotero/keep-a-changelog/compare/v2.5.2...v2.5.3 [2.5.2]: https://github.com/oscarotero/keep-a-changelog/compare/v2.5.1...v2.5.2 [2.5.1]: https://github.com/oscarotero/keep-a-changelog/compare/v2.5.0...v2.5.1 diff --git a/README.md b/README.md index 3120c11ca..208e134a0 100644 --- a/README.md +++ b/README.md @@ -195,19 +195,9 @@ changelog --latest-release > 2.0.0 ``` -Available options: - -| Option | Description | -| ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `--format` | The output format for the generated markdown. It can be `markdownlint` or `compact`. The default value is `compact`. | -| `--bullet-style` | The Markdown bullet style to use. It can be `-`, `*`, `+`. The default value is `-`. | -| `--file` | The markdown file of the changelog. The default value is `CHANGELOG.md`. | -| `--url` | The base url used to build the diff urls of the different releases. It is taken from the existing diff urls in the markdown. If no urls are found, try to catch it using the url of the git remote repository. | -| `--https` | Set to false to use `http` instead `https` in the url (`--https=false`). | -| `--init` | Init a new empty changelog file. | -| `--latest-release` | Print the latest release version. | -| `--release` | Updated the latest unreleased version with the current date. Use `--release=X.Y.Z` to set a number if the version doesn't have it. | -| `--combine` | Combine changes from releases with the same version. | -| `--create` | Create a new Unreleased version. Use `--create=X.Y.Z` to specify a version number or just `--create` for a version without number. | -| `--quiet` | Do not output error messages | -| `--head` | Customize the `head` reference | +See available options: + +```sh +changelog --help +``` + diff --git a/bin.ts b/bin.ts index 8f921cd10..c036b7ff1 100755 --- a/bin.ts +++ b/bin.ts @@ -20,7 +20,14 @@ const argv = parseArgs(Deno.args, { "bullet-style": "-", }, string: ["file", "format", "url", "head", "bullet-style"], - boolean: ["https", "init", "latest-release", "quiet", "help", "combine"], + boolean: [ + "https", + "init", + "latest-release", + "quiet", + "help", + "combine" + ], alias: { h: "help", }, @@ -40,15 +47,17 @@ try { ); changelog.format = argv.format as "compact" | "markdownlint"; - changelog.bulletStyle = argv['bullet-style'] as "-" | "*" | "+"; + changelog.bulletStyle = argv["bullet-style"] as "-" | "*" | "+"; save(file, changelog, true); Deno.exit(0); } - const changelog = parser(Deno.readTextFileSync(file)); + const changelog = parser(Deno.readTextFileSync(file), { + autoSortReleases: argv["no-sort-releases"] === undefined ? true : false, + }); changelog.format = argv.format as "compact" | "markdownlint"; - changelog.bulletStyle = argv['bullet-style'] as "-" | "*" | "+"; + changelog.bulletStyle = argv["bullet-style"] as "-" | "*" | "+"; if (argv["no-v-prefix"]) { changelog.tagNameBuilder = (release) => String(release.version); } @@ -223,6 +232,7 @@ Options: --create Create a new release --no-v-prefix Do not add a "v" prefix to the version + --no-sort-releases Do not sort releases --head Set the HEAD link --quiet Do not print errors --help, -h Show this help message diff --git a/example.ts b/example.ts index aa7bfe66a..6ed3f4418 100644 --- a/example.ts +++ b/example.ts @@ -7,6 +7,10 @@ const changelog = new Changelog("Changelog") .added( "New option `--no-v-prefix` to generate the tag names without prepending `v` #43", ) + .added( + "New option `--no-sort-releases` to disable sorting of releases #51", + ) + .added("`--help, -h` flag [#45].") .fixed("Updated dependencies"), ) .addRelease( diff --git a/src/Changelog.ts b/src/Changelog.ts index dd5c9b267..b86d95b1e 100644 --- a/src/Changelog.ts +++ b/src/Changelog.ts @@ -13,9 +13,15 @@ export default class Changelog { tagNameBuilder?: (release: Release) => string; /** @deprecated: Use tagLinkBuilder() instead */ compareLinkBuilder?: (previous: Release, release: Release) => string; - tagLinkBuilder?: (url: string, tag: string, previous?: string, head?: string) => string; + tagLinkBuilder?: ( + url: string, + tag: string, + previous?: string, + head?: string, + ) => string; format: "compact" | "markdownlint" = "compact"; bulletStyle: "-" | "*" | "+" = "-"; + autoSortReleases = true; constructor(title: string, description = "") { this.title = title; @@ -24,7 +30,9 @@ export default class Changelog { addRelease(release: Release) { this.releases.push(release); - this.sortReleases(); + if (this.autoSortReleases) { + this.sortReleases(); + } release.changelog = this; return this; @@ -54,11 +62,21 @@ export default class Changelog { const url = this.url!; if (!previous) { - return this.tagLinkBuilder(this.url!, this.tagName(release), undefined, this.head); + return this.tagLinkBuilder( + this.url!, + this.tagName(release), + undefined, + this.head, + ); } if (!release.date || !release.version) { - return this.tagLinkBuilder(url, this.head, this.tagName(previous), this.head); + return this.tagLinkBuilder( + url, + this.head, + this.tagName(previous), + this.head, + ); } return this.tagLinkBuilder( diff --git a/src/Release.ts b/src/Release.ts index 12c2d1ebf..dbda19b15 100644 --- a/src/Release.ts +++ b/src/Release.ts @@ -85,7 +85,7 @@ export default class Release { this.parsedVersion = parsed; //Re-sort the releases of the parent changelog - if (this.changelog) { + if (this.changelog && this.changelog.autoSortReleases) { this.changelog.sortReleases(); } } @@ -175,7 +175,9 @@ export default class Release { if (changelog?.format === "markdownlint") { t.push(""); } - t = t.concat(changes.map((change) => change.toString(changelog?.bulletStyle))); + t = t.concat( + changes.map((change) => change.toString(changelog?.bulletStyle)), + ); t.push(""); } }); diff --git a/src/parser.ts b/src/parser.ts index b52aeb464..faa06c24b 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -11,15 +11,24 @@ export interface Options { date?: string, description?: string, ) => Release; + /** + * If false, releases will not be sorted automatically. + * Default is true. + */ + autoSortReleases: boolean; } const defaultOptions: Options = { releaseCreator: (version, date, description) => new Release(version, date, description), + autoSortReleases: true, }; /** Parse a markdown string */ -export default function parser(markdown: string, options?: Options): Changelog { +export default function parser( + markdown: string, + options?: Partial, +): Changelog { const opts = Object.assign({}, defaultOptions, options); const tokens = tokenize(markdown); @@ -39,6 +48,7 @@ function processTokens(tokens: Token[], opts: Options): Changelog { changelog.flag = getContent(tokens, "flag"); changelog.title = getContent(tokens, "h1", true); changelog.description = getTextContent(tokens); + changelog.autoSortReleases = opts.autoSortReleases; //Releases let release; @@ -83,7 +93,9 @@ function processTokens(tokens: Token[], opts: Options): Changelog { while (link) { if (!changelog.url) { - const matches = link.match(/^\[.*\]\:\s*(http.*?)\/(?:-\/)?(branchCompare|compare)(\/|\?).*$/); + const matches = link.match( + /^\[.*\]\:\s*(http.*?)\/(?:-\/)?(branchCompare|compare)(\/|\?).*$/, + ); if (matches) { changelog.url = matches[1]; diff --git a/src/settings.ts b/src/settings.ts index 17df28e62..dd6fd9db2 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -21,7 +21,12 @@ class URLPatternShim { export interface Settings { pattern: URLPatternShim; - tagLink: (url: string, tag: string, previous?: string, head?: string) => string; + tagLink: ( + url: string, + tag: string, + previous?: string, + head?: string, + ) => string; head: string; } diff --git a/test/changelog.sort.md b/test/changelog.sort.md new file mode 100644 index 000000000..bd86e4149 --- /dev/null +++ b/test/changelog.sort.md @@ -0,0 +1,17 @@ +# Changelog - gitlab demo +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/) +and this project adheres to [Semantic Versioning](https://semver.org/). + +## [1.0.1] - 2025-01-05 +### Fixed +- Bug fix + +## [2.0.0] - 2025-01-03 +### Added +- New feature + +## [1.0.0] - 2025-01-01 +### Added +- This is just a test changelog \ No newline at end of file diff --git a/test/parser.test.ts b/test/parser.test.ts index b1745b61b..cacc33f07 100644 --- a/test/parser.test.ts +++ b/test/parser.test.ts @@ -6,9 +6,11 @@ import getSettingsForURL from "../src/settings.ts"; const file = new URL("./changelog.custom.type.md", import.meta.url).pathname; const fileGitlab = new URL("./changelog.gitlab.md", import.meta.url).pathname; const fileAzdo = new URL("./changelog.azdo.md", import.meta.url).pathname; +const fileSort = new URL("./changelog.sort.md", import.meta.url).pathname; const changelogContent = Deno.readTextFileSync(file); const changelogContentGitlab = Deno.readTextFileSync(fileGitlab); const changelogContentAzdo = Deno.readTextFileSync(fileAzdo); +const changelogContentSort = Deno.readTextFileSync(fileSort); Deno.test("parser testing", function () { // is unable to parse changelog with unknown types @@ -20,6 +22,26 @@ Deno.test("parser testing", function () { assertEquals(changelog.toString().trim(), changelogContent.trim()); }); +Deno.test("parser testing auto sorting", function () { + const changelog = parser(changelogContentSort, ); + + assertEquals(changelog.releases[0].version, "2.0.0"); +}); + +Deno.test("parser testing manual sorting", function () { + const changelog = parser(changelogContentSort, { autoSortReleases: false }); + + changelog.sortReleases(); + + assertEquals(changelog.releases[0].version, "2.0.0"); +}); + +Deno.test("parser testing disabled auto sorting", function () { + const changelog = parser(changelogContentSort, { autoSortReleases: false }); + + assertEquals(changelog.releases[0].version, "1.0.1"); +}); + Deno.test("parser testing gitlab", function () { // parses a changelog with gitlab links const changelog = parser(changelogContentGitlab, );