From dc0c626320603d0d6a5ca4f322c9959be679228d Mon Sep 17 00:00:00 2001 From: steveluscher Date: Sat, 2 Dec 2023 23:39:38 +0000 Subject: [PATCH 1/3] chore: replace `conventional-commit-parser` with `@conventional-commits/parser` --- package.json | 5 ++--- pnpm-lock.yaml | 50 ++++++++++++++++++++++++++++++----------- src/getCommitMeaning.ts | 19 +++++++++++----- 3 files changed, 53 insertions(+), 21 deletions(-) diff --git a/package.json b/package.json index 51ae362e..c9157b79 100644 --- a/package.json +++ b/package.json @@ -39,12 +39,11 @@ "*": "prettier --ignore-unknown --write" }, "dependencies": { - "@pkgjs/parseargs": "^0.11.0", - "conventional-commits-parser": "^5.0.0" + "@conventional-commits/parser": "^0.4.1", + "@pkgjs/parseargs": "^0.11.0" }, "devDependencies": { "@release-it/conventional-changelog": "^8.0.0", - "@types/conventional-commits-parser": "^3.0.4", "@types/eslint": "^8.44.3", "@types/pkgjs__parseargs": "^0.10.1", "@typescript-eslint/eslint-plugin": "^6.7.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index acea6a1d..a464d626 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5,20 +5,17 @@ settings: excludeLinksFromLockfile: false dependencies: + '@conventional-commits/parser': + specifier: ^0.4.1 + version: 0.4.1 '@pkgjs/parseargs': specifier: ^0.11.0 version: 0.11.0 - conventional-commits-parser: - specifier: ^5.0.0 - version: 5.0.0 devDependencies: '@release-it/conventional-changelog': specifier: ^8.0.0 version: 8.0.1(release-it@17.0.0) - '@types/conventional-commits-parser': - specifier: ^3.0.4 - version: 3.0.4 '@types/eslint': specifier: ^8.44.3 version: 8.44.3 @@ -258,6 +255,13 @@ packages: resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} dev: true + /@conventional-commits/parser@0.4.1: + resolution: {integrity: sha512-H2ZmUVt6q+KBccXfMBhbBF14NlANeqHTXL4qCL6QGbMzrc4HDXyzWuxPxPNbz71f/5UkR5DrycP5VO9u7crahg==} + dependencies: + unist-util-visit: 2.0.3 + unist-util-visit-parents: 3.1.1 + dev: false + /@cspell/cspell-bundled-dicts@8.0.0: resolution: {integrity: sha512-Phbb1ij1TQQuqxuuvxf5P6fvV9U+EVoATNLmDqFHvRZfUyuhgbJuCMzIPeBx4GfTTDWlPs51FYRvZ/Q8xBHsyA==} engines: {node: '>=18'} @@ -1562,12 +1566,6 @@ packages: resolution: {integrity: sha512-VOVRLM1mBxIRxydiViqPcKn6MIxZytrbMpd6RJLIWKxUNr3zux8no0Oc7kJx0WAPIitgZ0gkrDS+btlqQpubpw==} dev: true - /@types/conventional-commits-parser@3.0.4: - resolution: {integrity: sha512-nO3LTqFyExqXWAAfcsGh63gPLmYZSAqlLZfhqJ57qkgtyd0BA8S8M/mqtWCD/PvegjuaGk1z4UG5Hy7bZq79zA==} - dependencies: - '@types/node': 18.11.18 - dev: true - /@types/eslint@8.44.3: resolution: {integrity: sha512-iM/WfkwAhwmPff3wZuPLYiHX18HI24jU8k1ZSH7P8FHwxTjZ2P6CoX2wnF43oprR+YXJM6UUxATkNvyv/JHd+g==} dependencies: @@ -1619,7 +1617,6 @@ packages: /@types/unist@2.0.6: resolution: {integrity: sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==} - dev: true /@typescript-eslint/eslint-plugin@6.7.3(@typescript-eslint/parser@6.7.3)(eslint@8.50.0)(typescript@5.2.2): resolution: {integrity: sha512-vntq452UHNltxsaaN+L9WyuMch8bMd9CqJ3zhzTPXXidwbf5mqqKCVXEuvRZUqLJSTLeWE65lQwyXsRGnXkCTA==} @@ -1829,6 +1826,7 @@ packages: dependencies: jsonparse: 1.3.1 through: 2.3.8 + dev: true /acorn-jsx@5.3.2(acorn@8.10.0): resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} @@ -2607,6 +2605,7 @@ packages: is-text-path: 2.0.0 meow: 12.1.1 split2: 4.2.0 + dev: true /conventional-recommended-bump@9.0.0: resolution: {integrity: sha512-HR1yD0G5HgYAu6K0wJjLd7QGRK8MQDqqj6Tn1n/ja1dFwBCE6QmV+iSgQ5F7hkx7OUR/8bHpxJqYtXj2f/opPQ==} @@ -4530,6 +4529,7 @@ packages: engines: {node: '>=8'} dependencies: text-extensions: 2.4.0 + dev: true /is-typed-array@1.1.12: resolution: {integrity: sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==} @@ -4730,6 +4730,7 @@ packages: /jsonparse@1.3.1: resolution: {integrity: sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==} engines: {'0': node >= 0.2.0} + dev: true /keyv@4.5.3: resolution: {integrity: sha512-QCiSav9WaX1PgETJ+SpNnx2PRRapJ/oRSXM4VO5OGYGSjrxbKPVFVhB3l2OCbLCk329N8qyAtsJjSjvVBWzEug==} @@ -5140,6 +5141,7 @@ packages: /meow@12.1.1: resolution: {integrity: sha512-BhXM0Au22RwUneMPwSCnyhTOizdWoIEPU9sp0Aqa1PnDMR5Wv2FGXYDjuzJEIX+Eo2Rb8xuYe5jrnm5QowQFkw==} engines: {node: '>=16.10'} + dev: true /meow@9.0.0: resolution: {integrity: sha512-+obSblOQmRhcyBt62furQqRAQpNyWXo8BuQ5bN7dG8wmwQ+vwHKp/rCFD4CrTP8CsDQD1sjoZ94K417XEUk8IQ==} @@ -6539,6 +6541,7 @@ packages: /split2@4.2.0: resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} engines: {node: '>= 10.x'} + dev: true /sprintf-js@1.0.3: resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} @@ -6747,6 +6750,7 @@ packages: /text-extensions@2.4.0: resolution: {integrity: sha512-te/NtwBwfiNRLf9Ijqx3T0nlqZiQ2XrrtBvu+cLL8ZRrGkO0NHTug8MYFKyoSrv/sHTaSKfilUkizV6XhxMJ3g==} engines: {node: '>=8'} + dev: true /text-table@0.2.0: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} @@ -6773,6 +6777,7 @@ packages: /through@2.3.8: resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} + dev: true /tinybench@2.5.1: resolution: {integrity: sha512-65NKvSuAVDP/n4CqH+a9w2kTlLReS9vhsAP06MWx+/89nMinJyB2icyl58RIcqCmIggpojIGeuJGhjU1aGMBSg==} @@ -7075,12 +7080,31 @@ packages: crypto-random-string: 4.0.0 dev: true + /unist-util-is@4.1.0: + resolution: {integrity: sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg==} + dev: false + /unist-util-stringify-position@2.0.3: resolution: {integrity: sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==} dependencies: '@types/unist': 2.0.6 dev: true + /unist-util-visit-parents@3.1.1: + resolution: {integrity: sha512-1KROIZWo6bcMrZEwiH2UrXDyalAa0uqzWCxCJj6lPOvTve2WkfgCytoDTPaMnodXh1WrXOq0haVYHj99ynJlsg==} + dependencies: + '@types/unist': 2.0.6 + unist-util-is: 4.1.0 + dev: false + + /unist-util-visit@2.0.3: + resolution: {integrity: sha512-iJ4/RczbJMkD0712mGktuGpm/U4By4FfDonL7N/9tATGIF4imikjOuagyMY53tnZq3NP6BcmlrHhEKAfGWjh7Q==} + dependencies: + '@types/unist': 2.0.6 + unist-util-is: 4.1.0 + unist-util-visit-parents: 3.1.1 + dev: false + /universal-user-agent@6.0.0: resolution: {integrity: sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==} dev: true diff --git a/src/getCommitMeaning.ts b/src/getCommitMeaning.ts index 3935dbda..10e6812d 100644 --- a/src/getCommitMeaning.ts +++ b/src/getCommitMeaning.ts @@ -1,4 +1,7 @@ -import conventionalCommitsParser from "conventional-commits-parser"; +import { + parser, + toConventionalChangelogFormat, +} from "@conventional-commits/parser"; const alwaysMeaningfulTypes = new Set(["feat", "fix", "perf"]); @@ -8,9 +11,13 @@ const releaseCommitTester = /^(?:chore(?:\(.*\))?:?)?\s*release|v?\d+\.\d+\.\d+/; export function getCommitMeaning(message: string) { - // Some types are always meaningful or ignored, regardless of potentially release-like messages - const { type } = conventionalCommitsParser.sync(message); - if (type) { + let type = undefined; + try { + const messageAst = parser(message); + const commit = toConventionalChangelogFormat(messageAst); + type = commit.type; + + // Some types are always meaningful or ignored, regardless of potentially release-like messages if (alwaysMeaningfulTypes.has(type)) { return "meaningful"; } @@ -18,6 +25,8 @@ export function getCommitMeaning(message: string) { if (alwaysIgnoredTypes.has(type)) { return { type }; } + } catch { + /* empty */ } // If we've hit a release commit, we know we don't need to release @@ -25,5 +34,5 @@ export function getCommitMeaning(message: string) { return "release"; } - return { type: type ?? undefined }; + return { type }; } From 9cbaa651ddfa95566cd7e191d54382cb91802684 Mon Sep 17 00:00:00 2001 From: steveluscher Date: Sat, 2 Dec 2023 23:50:04 +0000 Subject: [PATCH 2/3] feat: breaking changes are now meaningful, by footer or by exclamation point in the type --- src/getCommitMeaning.test.ts | 11 +++++++++++ src/getCommitMeaning.ts | 5 ++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/getCommitMeaning.test.ts b/src/getCommitMeaning.test.ts index 23165883..447514e6 100644 --- a/src/getCommitMeaning.test.ts +++ b/src/getCommitMeaning.test.ts @@ -40,6 +40,17 @@ describe("getCommitMeaning", () => { ["chore(deps): release", "release"], ["chore(deps): release 1.2.3", "release"], ["chore(deps): release v1.2.3", "release"], + // Breaking changes are meaningful no matter the type of the commit. + ["chore!: message", "meaningful"], + ["docs!: message", "meaningful"], + ["style!: message", "meaningful"], + ["chore!: release", "meaningful"], + ["chore: bump\n\nBREAKING CHANGE: breaks things", "meaningful"], + ["chore: bump\n\nBREAKING-CHANGE: breaks things", "meaningful"], + ["docs: bump\n\nBREAKING CHANGE: breaks things", "meaningful"], + ["docs: bump\n\nBREAKING-CHANGE: breaks things", "meaningful"], + ["style: bump\n\nBREAKING CHANGE: breaks things", "meaningful"], + ["style: bump\n\nBREAKING-CHANGE: breaks things", "meaningful"], ])("returns %j for %s", (input, expected) => { expect(getCommitMeaning(input)).toEqual(expected); }); diff --git a/src/getCommitMeaning.ts b/src/getCommitMeaning.ts index 10e6812d..29ad8a8d 100644 --- a/src/getCommitMeaning.ts +++ b/src/getCommitMeaning.ts @@ -18,7 +18,10 @@ export function getCommitMeaning(message: string) { type = commit.type; // Some types are always meaningful or ignored, regardless of potentially release-like messages - if (alwaysMeaningfulTypes.has(type)) { + if ( + alwaysMeaningfulTypes.has(type) || + commit.notes.some(({ title }) => title === "BREAKING CHANGE") + ) { return "meaningful"; } From 765adffd8e353fe4d1ab0a9ac072e96d28b2e37a Mon Sep 17 00:00:00 2001 From: steveluscher Date: Sun, 3 Dec 2023 01:25:55 +0000 Subject: [PATCH 3/3] docs: update README to mention breaking changes --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 51a59309..1459591f 100644 --- a/README.md +++ b/README.md @@ -59,8 +59,9 @@ This is a release commit. Returning false. Based on a commit's conventional commit message type: 1. If the type is `feat` `fix`, or `perf`, it's considered "meaningful" -2. If the type is `docs`, `refactor`, `style`, or `test`, it's ignored -3. If the message looks like `v1.2.3`, `chore: release 1.2.3`, or similar, it's considered a "release" +2. If the commit is marked as being a breaking change, either via a note or via an `!` appended to the type, it's considered "meaningful" +3. If the type is `docs`, `refactor`, `style`, or `test`, it's ignored +4. If the message looks like `v1.2.3`, `chore: release 1.2.3`, or similar, it's considered a "release" See [`getCommitMeaning`](./src/getCommitMeaning.ts) for the exact logic used.