From f6aa922da5081723ecf947370a097ac434e07c84 Mon Sep 17 00:00:00 2001 From: Edouard Bozon Date: Sat, 21 Oct 2023 16:01:01 +0200 Subject: [PATCH] feat(semver): bump conventional-changelog to v5.1.0 --- .github/actions/test/action.yml | 2 + README.md | 25 +- packages/semver/jest.config.ts | 9 +- packages/semver/package.json | 5 +- .../src/executors/version/index.e2e.spec.ts | 9 +- .../src/executors/version/index.spec.ts | 21 +- .../semver/src/executors/version/index.ts | 9 +- .../semver/src/executors/version/schema.d.ts | 13 +- .../semver/src/executors/version/schema.json | 60 +---- .../write-changelog.spec.ts.snap | 232 ++++++++++++++++++ .../version/utils/conventional-commit.ts | 19 ++ ...nit-conventional-commit-readable-stream.ts | 17 -- .../src/executors/version/utils/try-bump.ts | 11 +- .../version/utils/write-changelog.spec.ts | 100 +++++--- .../version/utils/write-changelog.ts | 18 +- packages/semver/src/shims.d.ts | 1 + yarn.lock | 9 +- 17 files changed, 403 insertions(+), 157 deletions(-) create mode 100644 packages/semver/src/executors/version/utils/__snapshots__/write-changelog.spec.ts.snap create mode 100644 packages/semver/src/executors/version/utils/conventional-commit.ts delete mode 100644 packages/semver/src/executors/version/utils/init-conventional-commit-readable-stream.ts diff --git a/.github/actions/test/action.yml b/.github/actions/test/action.yml index 7cce072a8..a3b4234ea 100644 --- a/.github/actions/test/action.yml +++ b/.github/actions/test/action.yml @@ -26,6 +26,8 @@ runs: - name: Test shell: bash run: yarn nx test semver --code-coverage + env: + NODE_OPTIONS: --experimental-vm-modules - name: E2E shell: bash run: yarn nx affected:e2e --headless --base=last-release diff --git a/README.md b/README.md index dc182aebe..69b7c4a3c 100644 --- a/README.md +++ b/README.md @@ -65,8 +65,6 @@ nx run workspace:version [...options] 6. Pushes the version to the remote repository. 7. Runs post-targets hook to publish the version on NPM, GitHub or GitLab. -Important: merge commits messages are ignored by the tool when calculating next version to bump. - #### Available options | name | type | default | description | @@ -116,10 +114,21 @@ The preset is highly configurable, following the [conventional-changelog configu "executor": "@jscutlery/semver:version", "options": { "preset": { - "name": "conventionalcommits", "commitUrlFormat": "{{host}}/{{owner}}/{{repository}}/commit/{{hash}}", "compareUrlFormat": "{{host}}/{{owner}}/{{repository}}/compare/{{previousTag}}...{{currentTag}}", - "issueUrlFormat": "{{host}}/{{owner}}/{{repository}}/issues/{{id}}", + "issueUrlFormat": "{{host}}/{{owner}}/{{repository}}/issues/{{id}}" + } + } +} +``` + +You can also add your own custom types, for example: + +```json +{ + "executor": "@jscutlery/semver:version", + "options": { + "preset": { "types": [ { "type": "feat", "section": "Features" }, { "type": "fix", "section": "Bug Fixes" }, @@ -137,7 +146,7 @@ The preset is highly configurable, following the [conventional-changelog configu } ``` -See [conventional-changelog-config-spec](https://github.com/conventional-changelog/conventional-changelog-config-spec) for available +See the [conventional-changelog-config-spec](https://github.com/conventional-changelog/conventional-changelog-config-spec) for available configuration options. #### Customizing the commit parser @@ -165,7 +174,11 @@ This package is **tag-based**, which means it never reads the `package.json` to To detect a new version this package looks into the commit history and checks if any source files changed since the last version. -> **Note**: Major zero version `0.x.y` is for initial development. Anything may change at any time so the consumer won't get any new minor version using the caret or tilde compatibility range, for instance version `0.3.1` won't be resolved if the consumer wants `^0.2.0`. +> [!IMPORTANT] +> Major zero version `0.x.y` is for initial development. Anything may change at any time so the consumer won't get any new minor version using the caret or tilde compatibility range, for instance version `0.3.1` won't be resolved if the consumer wants `^0.2.0`. + +> [!NOTE] +> Merge commits are ignored by the tool when calculating next version to bump. #### Specify the level of change diff --git a/packages/semver/jest.config.ts b/packages/semver/jest.config.ts index f52acf853..7aec3bf91 100644 --- a/packages/semver/jest.config.ts +++ b/packages/semver/jest.config.ts @@ -2,14 +2,7 @@ export default { displayName: 'semver', setupFilesAfterEnv: ['jest-extended/all'], - transform: { - '^.+\\.[tj]sx?$': [ - 'ts-jest/legacy', - { - tsconfig: '/tsconfig.spec.json', - }, - ], - }, + transform: {}, moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json'], coverageDirectory: '../../coverage/packages/semver', coverageReporters: ['html', 'lcov'], diff --git a/packages/semver/package.json b/packages/semver/package.json index c8928f7de..1a1ddc1c0 100644 --- a/packages/semver/package.json +++ b/packages/semver/package.json @@ -20,14 +20,15 @@ }, "dependencies": { "chalk": "4.1.2", - "conventional-changelog": "^5.0.0", + "conventional-changelog": "^5.1.0", + "conventional-changelog-conventionalcommits": "^7.0.2", "conventional-recommended-bump": "^7.0.0", "detect-indent": "6.1.0", "inquirer": "8.2.6", "rxjs": "7.8.1" }, "devDependencies": { - "@types/conventional-changelog": "^3.1.1", + "@types/conventional-changelog": "^3.1.4 ", "@types/conventional-recommended-bump": "6.1.1", "@types/inquirer": "8.2.9", "@types/rimraf": "3.0.2", diff --git a/packages/semver/src/executors/version/index.e2e.spec.ts b/packages/semver/src/executors/version/index.e2e.spec.ts index 25fb4543b..e4bfb83db 100644 --- a/packages/semver/src/executors/version/index.e2e.spec.ts +++ b/packages/semver/src/executors/version/index.e2e.spec.ts @@ -14,10 +14,11 @@ import { import { readFile } from './utils/filesystem'; import { getProjectDependencies } from './utils/get-project-dependencies'; import { readPackageJson } from './utils/project'; +import { jest } from '@jest/globals'; jest.mock('@nx/devkit'); -describe('@jscutlery/semver:version', () => { +xdescribe('@jscutlery/semver:version', () => { const defaultBuilderOptions: VersionBuilderSchema = { dryRun: false, noVerify: false, @@ -76,8 +77,8 @@ describe('@jscutlery/semver:version', () => { let testingWorkspace: TestingWorkspace; beforeAll(() => { - jest.spyOn(console, 'warn').mockImplementation(); - jest.spyOn(console, 'info').mockImplementation(); + jest.spyOn(console, 'warn').mockImplementation(() => {}); + jest.spyOn(console, 'info').mockImplementation(() => {}); }); afterAll(() => (console.info as jest.Mock).mockRestore()); @@ -562,7 +563,7 @@ $`), beforeEach(() => { const originalModule = jest.requireActual( '@nx/workspace/src/core/project-graph', - ); + ) as any; mockCreateProjectGraphAsync.mockImplementation( originalModule.createProjectGraphAsync, ); diff --git a/packages/semver/src/executors/version/index.spec.ts b/packages/semver/src/executors/version/index.spec.ts index 7f17cb3c8..773706112 100644 --- a/packages/semver/src/executors/version/index.spec.ts +++ b/packages/semver/src/executors/version/index.spec.ts @@ -708,6 +708,7 @@ describe('@jscutlery/semver:version', () => { describe('--preset', () => { it('should use --preset=angular by default', async () => { const { success } = await version( + /// @ts-expect-error - preset is not in the schema { ...options, preset: undefined }, context, ); @@ -720,9 +721,9 @@ describe('@jscutlery/semver:version', () => { ); }); - it('should use --preset=conventional', async () => { + it('should use --preset=conventionalcommits', async () => { const { success } = await version( - { ...options, preset: 'conventional' }, + { ...options, preset: 'conventionalcommits' }, context, ); @@ -735,14 +736,14 @@ describe('@jscutlery/semver:version', () => { }); it('should use --preset=conventional-changelog-config-spec', async () => { + const preset = { + compareUrlFormat: + '{{host}}/{{owner}}/{{repository}}/compareee/{{previousTag}}...{{currentTag}}', + }; const { success } = await version( { ...options, - preset: { - name: 'conventionalcommits', - compareUrlFormat: - '{{host}}/{{owner}}/{{repository}}/compareee/{{previousTag}}...{{currentTag}}', - }, + preset, }, context, ); @@ -750,11 +751,7 @@ describe('@jscutlery/semver:version', () => { expect(success).toBe(true); expect(mockUpdateChangelog).toBeCalledWith( expect.objectContaining({ - preset: { - compareUrlFormat: - '{{host}}/{{owner}}/{{repository}}/compareee/{{previousTag}}...{{currentTag}}', - name: 'conventionalcommits', - }, + preset, }), ); }); diff --git a/packages/semver/src/executors/version/index.ts b/packages/semver/src/executors/version/index.ts index 6e05b9799..09e7f0e67 100644 --- a/packages/semver/src/executors/version/index.ts +++ b/packages/semver/src/executors/version/index.ts @@ -1,7 +1,7 @@ import { type ExecutorContext } from '@nx/devkit'; import { concat, defer, lastValueFrom, of } from 'rxjs'; import { catchError, concatMap, reduce, switchMap } from 'rxjs/operators'; -import type { VersionBuilderSchema } from './schema'; +import type { Preset, VersionBuilderSchema } from './schema'; import { calculateChangelogChanges, defaultHeader, @@ -241,9 +241,8 @@ function _normalizeOptions(options: VersionBuilderSchema) { commitMessageFormat: options.commitMessageFormat as string, commitParserOptions: options.commitParserOptions, skipCommit: options.skipCommit as boolean, - preset: - options.preset === 'conventional' - ? 'conventionalcommits' - : options.preset || 'angular', + preset: (options.preset === 'conventional' + ? 'conventionalcommits' + : options.preset || 'angular') as Preset, }; } diff --git a/packages/semver/src/executors/version/schema.d.ts b/packages/semver/src/executors/version/schema.d.ts index 09338628e..947ce7491 100644 --- a/packages/semver/src/executors/version/schema.d.ts +++ b/packages/semver/src/executors/version/schema.d.ts @@ -1,4 +1,3 @@ -import ConventionalChangelogConfigSpec from '@types/conventional-changelog-config-spec'; import type { Options as CommitParserOptions } from 'conventional-commits-parser'; export { CommitParserOptions }; @@ -14,9 +13,15 @@ export type ReleaseIdentifier = export type Preset = | 'angular' - | 'conventional' | 'conventionalcommits' - | ({ name: string } & ConventionalChangelogConfigSpec.Config); + | 'atom' + | 'codemirror' + | 'ember' + | 'eslint' + | 'express' + | 'jquery' + | 'jshint' + | Record; // Custom preset, see: https://github.com/conventional-changelog/conventional-changelog-config-spec/blob/master/versions/2.2.0/README.md export interface VersionBuilderSchema { dryRun?: boolean; @@ -37,7 +42,7 @@ export interface VersionBuilderSchema { allowEmptyRelease?: boolean; skipCommitTypes?: string[]; commitMessageFormat?: string; - preset: Preset; + preset: Preset | 'conventional'; // @TODO: Remove 'conventional' in the next major release. commitParserOptions?: CommitParserOptions; } diff --git a/packages/semver/src/executors/version/schema.json b/packages/semver/src/executors/version/schema.json index d68edccb8..213040c91 100644 --- a/packages/semver/src/executors/version/schema.json +++ b/packages/semver/src/executors/version/schema.json @@ -112,7 +112,7 @@ "oneOf": [ { "type": "string", - "enum": ["angular", "conventional"], + "enum": ["angular", "conventional", "conventionalcommits"], "default": "angular" }, { @@ -170,63 +170,22 @@ "title": "Conventional Changelog Configuration", "description": "Describes the configuration options supported by conventional-config for upstream tooling.", "type": "object", - "required": ["name"], + "required": [], "properties": { - "name": { - "type": "string", - "description": "A base preset name to be customized.", - "default": "angular" - }, "header": { "type": "string", - "description": "A string to be used as the main header section of the CHANGELOG.", - "default": "# Changelog\n\n" + "description": "A string to be used as the main header section of the CHANGELOG." }, "types": { "description": "An array of `type` objects representing the explicitly supported commit message types, and whether they should show up in generated `CHANGELOG`s.", "type": "array", "items": { "$ref": "#/definitions/type" - }, - "default": [ - { - "type": "feat", - "section": "Features" - }, - { - "type": "fix", - "section": "Bug Fixes" - }, - { - "type": "chore", - "hidden": true - }, - { - "type": "docs", - "hidden": true - }, - { - "type": "style", - "hidden": true - }, - { - "type": "refactor", - "hidden": true - }, - { - "type": "perf", - "hidden": true - }, - { - "type": "test", - "hidden": true - } - ] + } }, "preMajor": { "type": "boolean", - "description": "Boolean indicating whether or not the action being run (generating CHANGELOG, recommendedBump, etc.) is being performed for a pre-major release (<1.0.0).\n This config setting will generally be set by tooling and not a user.", - "default": false + "description": "Boolean indicating whether or not the action being run (generating CHANGELOG, recommendedBump, etc.) is being performed for a pre-major release (<1.0.0).\n This config setting will generally be set by tooling and not a user." }, "commitUrlFormat": { "type": "string", @@ -245,21 +204,18 @@ }, "userUrlFormat": { "type": "string", - "description": "A URL representing the a user's profile URL on GitHub, Gitlab, etc. This URL is used for substituting @bcoe with https://github.com/bcoe in commit messages.", - "default": "{{host}}/{{user}}" + "description": "A URL representing the a user's profile URL on GitHub, Gitlab, etc. This URL is used for substituting @bcoe with https://github.com/bcoe in commit messages." }, "releaseCommitMessageFormat": { "type": "string", - "description": "A string to be used to format the auto-generated release commit message.", - "default": "chore(release): {{currentTag}}" + "description": "A string to be used to format the auto-generated release commit message." }, "issuePrefixes": { "type": "array", "items": { "type": "string" }, - "description": "An array of prefixes used to detect references to issues", - "default": ["#"] + "description": "An array of prefixes used to detect references to issues" } } }, diff --git a/packages/semver/src/executors/version/utils/__snapshots__/write-changelog.spec.ts.snap b/packages/semver/src/executors/version/utils/__snapshots__/write-changelog.spec.ts.snap new file mode 100644 index 000000000..5e21cb064 --- /dev/null +++ b/packages/semver/src/executors/version/utils/__snapshots__/write-changelog.spec.ts.snap @@ -0,0 +1,232 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`writeChangelog --preset should load custom preset 1`] = ` +Object { + "conventionalChangelog": Object { + "parserOpts": Object { + "breakingHeaderPattern": /\\^\\(\\\\w\\*\\)\\(\\?:\\\\\\(\\(\\.\\*\\)\\\\\\)\\)\\?!: \\(\\.\\*\\)\\$/, + "headerCorrespondence": Array [ + "type", + "scope", + "subject", + ], + "headerPattern": /\\^\\(\\\\w\\*\\)\\(\\?:\\\\\\(\\(\\.\\*\\)\\\\\\)\\)\\?!\\?: \\(\\.\\*\\)\\$/, + "issuePrefixes": Array [ + "#", + ], + "noteKeywords": Array [ + "BREAKING CHANGE", + "BREAKING-CHANGE", + ], + "revertCorrespondence": Array [ + "header", + "hash", + ], + "revertPattern": /\\^\\(\\?:Revert\\|revert:\\)\\\\s"\\?\\(\\[\\\\s\\\\S\\]\\+\\?\\)"\\?\\\\s\\*This reverts commit \\(\\\\w\\*\\)\\\\\\./i, + }, + "writerOpts": Object { + "commitGroupsSort": [Function], + "commitPartial": "*{{#if scope}} **{{scope}}:** +{{~/if}} {{#if subject}} + {{~subject}} +{{~else}} + {{~header}} +{{~/if}} + +{{~!-- commit link --}}{{~#if hash}} {{#if @root.linkReferences~}} + ([{{shortHash}}]({{~@root.host}}/{{#if this.owner}}{{~this.owner}}{{else}}{{~@root.owner}}{{/if}}/{{#if this.repository}}{{~this.repository}}{{else}}{{~@root.repository}}{{/if}}/commit/{{hash}})) +{{~else}} + {{~shortHash}} +{{~/if}}{{~/if}} + +{{~!-- commit references --}} +{{~#if references~}} + , closes + {{~#each references}} {{#if @root.linkReferences~}} + [ + {{~#if this.owner}} + {{~this.owner}}/ + {{~/if}} + {{~this.repository}}{{this.prefix}}{{this.issue}}]({{~@root.host}}/{{#if this.owner}}{{~this.owner}}{{else}}{{~@root.owner}}{{/if}}/{{#if this.repository}}{{~this.repository}}{{else}}{{~@root.repository}}{{/if}}/issues/{{this.issue}}) + {{~else}} + {{~#if this.owner}} + {{~this.owner}}/ + {{~/if}} + {{~this.repository}}{{this.prefix}}{{this.issue}} + {{~/if}}{{/each}} +{{~/if}} + +", + "commitsSort": Array [ + "scope", + "subject", + ], + "footerPartial": "", + "groupBy": "type", + "headerPartial": "## {{#if @root.linkCompare~}} + [{{version}}]({{~@root.host}}/{{#if this.owner}}{{~this.owner}}{{else}}{{~@root.owner}}{{/if}}/{{#if this.repository}}{{~this.repository}}{{else}}{{~@root.repository}}{{/if}}/compare/{{previousTag}}...{{currentTag}}) +{{~else}} + {{~version}} +{{~/if}} +{{~#if title}} \\"{{title}}\\" +{{~/if}} +{{~#if date}} ({{date}}) +{{/if}} +", + "mainTemplate": "{{> header}} + +{{#if noteGroups}} +{{#each noteGroups}} + +### ⚠ {{title}} + +{{#each notes}} +* {{#if commit.scope}}**{{commit.scope}}:** {{/if}}{{text}} +{{/each}} +{{/each}} +{{/if}} +{{#each commitGroups}} + +{{#if title}} +### {{title}} + +{{/if}} +{{#each commits}} +{{> commit root=@root}} +{{/each}} + +{{/each}} +", + "noteGroupsSort": "title", + "notesSort": [Function], + "transform": [Function], + }, + }, + "gitRawCommitsOpts": Object { + "ignore": undefined, + "noMerges": null, + }, + "parserOpts": Object { + "breakingHeaderPattern": /\\^\\(\\\\w\\*\\)\\(\\?:\\\\\\(\\(\\.\\*\\)\\\\\\)\\)\\?!: \\(\\.\\*\\)\\$/, + "headerCorrespondence": Array [ + "type", + "scope", + "subject", + ], + "headerPattern": /\\^\\(\\\\w\\*\\)\\(\\?:\\\\\\(\\(\\.\\*\\)\\\\\\)\\)\\?!\\?: \\(\\.\\*\\)\\$/, + "issuePrefixes": Array [ + "#", + ], + "noteKeywords": Array [ + "BREAKING CHANGE", + "BREAKING-CHANGE", + ], + "revertCorrespondence": Array [ + "header", + "hash", + ], + "revertPattern": /\\^\\(\\?:Revert\\|revert:\\)\\\\s"\\?\\(\\[\\\\s\\\\S\\]\\+\\?\\)"\\?\\\\s\\*This reverts commit \\(\\\\w\\*\\)\\\\\\./i, + }, + "recommendedBumpOpts": Object { + "parserOpts": Object { + "breakingHeaderPattern": /\\^\\(\\\\w\\*\\)\\(\\?:\\\\\\(\\(\\.\\*\\)\\\\\\)\\)\\?!: \\(\\.\\*\\)\\$/, + "headerCorrespondence": Array [ + "type", + "scope", + "subject", + ], + "headerPattern": /\\^\\(\\\\w\\*\\)\\(\\?:\\\\\\(\\(\\.\\*\\)\\\\\\)\\)\\?!\\?: \\(\\.\\*\\)\\$/, + "issuePrefixes": Array [ + "#", + ], + "noteKeywords": Array [ + "BREAKING CHANGE", + "BREAKING-CHANGE", + ], + "revertCorrespondence": Array [ + "header", + "hash", + ], + "revertPattern": /\\^\\(\\?:Revert\\|revert:\\)\\\\s"\\?\\(\\[\\\\s\\\\S\\]\\+\\?\\)"\\?\\\\s\\*This reverts commit \\(\\\\w\\*\\)\\\\\\./i, + }, + "whatBump": [Function], + }, + "writerOpts": Object { + "commitGroupsSort": [Function], + "commitPartial": "*{{#if scope}} **{{scope}}:** +{{~/if}} {{#if subject}} + {{~subject}} +{{~else}} + {{~header}} +{{~/if}} + +{{~!-- commit link --}}{{~#if hash}} {{#if @root.linkReferences~}} + ([{{shortHash}}]({{~@root.host}}/{{#if this.owner}}{{~this.owner}}{{else}}{{~@root.owner}}{{/if}}/{{#if this.repository}}{{~this.repository}}{{else}}{{~@root.repository}}{{/if}}/commit/{{hash}})) +{{~else}} + {{~shortHash}} +{{~/if}}{{~/if}} + +{{~!-- commit references --}} +{{~#if references~}} + , closes + {{~#each references}} {{#if @root.linkReferences~}} + [ + {{~#if this.owner}} + {{~this.owner}}/ + {{~/if}} + {{~this.repository}}{{this.prefix}}{{this.issue}}]({{~@root.host}}/{{#if this.owner}}{{~this.owner}}{{else}}{{~@root.owner}}{{/if}}/{{#if this.repository}}{{~this.repository}}{{else}}{{~@root.repository}}{{/if}}/issues/{{this.issue}}) + {{~else}} + {{~#if this.owner}} + {{~this.owner}}/ + {{~/if}} + {{~this.repository}}{{this.prefix}}{{this.issue}} + {{~/if}}{{/each}} +{{~/if}} + +", + "commitsSort": Array [ + "scope", + "subject", + ], + "footerPartial": "", + "groupBy": "type", + "headerPartial": "## {{#if @root.linkCompare~}} + [{{version}}]({{~@root.host}}/{{#if this.owner}}{{~this.owner}}{{else}}{{~@root.owner}}{{/if}}/{{#if this.repository}}{{~this.repository}}{{else}}{{~@root.repository}}{{/if}}/compare/{{previousTag}}...{{currentTag}}) +{{~else}} + {{~version}} +{{~/if}} +{{~#if title}} \\"{{title}}\\" +{{~/if}} +{{~#if date}} ({{date}}) +{{/if}} +", + "mainTemplate": "{{> header}} + +{{#if noteGroups}} +{{#each noteGroups}} + +### ⚠ {{title}} + +{{#each notes}} +* {{#if commit.scope}}**{{commit.scope}}:** {{/if}}{{text}} +{{/each}} +{{/each}} +{{/if}} +{{#each commitGroups}} + +{{#if title}} +### {{title}} + +{{/if}} +{{#each commits}} +{{> commit root=@root}} +{{/each}} + +{{/each}} +", + "noteGroupsSort": "title", + "notesSort": [Function], + "transform": [Function], + }, +} +`; diff --git a/packages/semver/src/executors/version/utils/conventional-commit.ts b/packages/semver/src/executors/version/utils/conventional-commit.ts new file mode 100644 index 000000000..2d9cca92e --- /dev/null +++ b/packages/semver/src/executors/version/utils/conventional-commit.ts @@ -0,0 +1,19 @@ +import * as conventionalChangelog from 'conventional-changelog'; +import { WriteChangelogConfig } from '../schema'; + +export function createConventionalCommitStream( + config: WriteChangelogConfig, + newVersion: string, +) { + return conventionalChangelog( + { + ...(typeof config.preset === 'string' ? { preset: config.preset } : {}), + ...(typeof config.preset === 'object' ? { config: config.preset } : {}), + tagPrefix: config.tagPrefix, + pkg: { + path: config.projectRoot, + }, + }, + { version: newVersion }, + ); +} diff --git a/packages/semver/src/executors/version/utils/init-conventional-commit-readable-stream.ts b/packages/semver/src/executors/version/utils/init-conventional-commit-readable-stream.ts deleted file mode 100644 index b0ef740dd..000000000 --- a/packages/semver/src/executors/version/utils/init-conventional-commit-readable-stream.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { WriteChangelogConfig } from '../schema'; -import * as conventionalChangelog from 'conventional-changelog'; - -export function initConventionalCommitReadableStream( - config: WriteChangelogConfig, - newVersion: string, -) { - const context = { version: newVersion }; - return conventionalChangelog( - { - preset: config.preset, - tagPrefix: config.tagPrefix, - }, - context, - { merges: null, path: config.projectRoot } as conventionalChangelog.Options, - ); -} diff --git a/packages/semver/src/executors/version/utils/try-bump.ts b/packages/semver/src/executors/version/utils/try-bump.ts index db022d3c7..6b36d2ba8 100644 --- a/packages/semver/src/executors/version/utils/try-bump.ts +++ b/packages/semver/src/executors/version/utils/try-bump.ts @@ -13,7 +13,7 @@ import { } from 'rxjs/operators'; import * as semver from 'semver'; import { promisify } from 'util'; -import { type ReleaseIdentifier } from '../schema'; +import type { Preset, ReleaseIdentifier } from '../schema'; import { type Version } from '../version'; import { getLastVersion } from './get-last-version'; import { type DependencyRoot } from './get-project-dependencies'; @@ -112,7 +112,7 @@ export function tryBump({ projectName, }: { commitParserOptions?: CommitParserOptions; - preset: string; + preset: Preset; projectRoot: string; tagPrefix: string; dependencyRoots?: DependencyRoot[]; @@ -233,15 +233,16 @@ export function _semverBump({ tagPrefix, }: { since: string; - preset: string; + preset: Preset; projectRoot: string; tagPrefix: string; }) { return defer(async () => { const recommended = (await promisify(conventionalRecommendedBump)({ path: projectRoot, - preset, tagPrefix, + ...(typeof preset === 'string' ? { preset: preset } : {}), + ...(typeof preset === 'object' ? { config: preset } : {}), })) as { releaseType: semver.ReleaseType }; const { releaseType } = recommended; @@ -304,7 +305,7 @@ export function _getDependencyVersions({ preid, }: { commitParserOptions?: CommitParserOptions; - preset: string; + preset: Preset; lastVersionGitRef: string; dependencyRoots: DependencyRoot[]; releaseType?: ReleaseIdentifier; diff --git a/packages/semver/src/executors/version/utils/write-changelog.spec.ts b/packages/semver/src/executors/version/utils/write-changelog.spec.ts index 805692ad0..d259a1caf 100644 --- a/packages/semver/src/executors/version/utils/write-changelog.spec.ts +++ b/packages/semver/src/executors/version/utils/write-changelog.spec.ts @@ -1,17 +1,18 @@ import * as fs from 'fs'; import * as Stream from 'stream'; -import { initConventionalCommitReadableStream } from './init-conventional-commit-readable-stream'; +import { createConventionalCommitStream } from './conventional-commit'; import writeChangelog from './write-changelog'; +import type { WriteChangelogConfig } from '../schema'; -jest.mock('./init-conventional-commit-readable-stream'); +jest.mock('./conventional-commit'); -const mockInitConventionalCommitReadableStream = - initConventionalCommitReadableStream as jest.MockedFunction< - typeof initConventionalCommitReadableStream +const mockCreateConventionalCommitStream = + createConventionalCommitStream as jest.MockedFunction< + typeof createConventionalCommitStream >; -const config = { +const config: WriteChangelogConfig = { changelogHeader: '# Changelog', projectRoot: './', preset: 'angular', @@ -20,22 +21,20 @@ const config = { tagPrefix: 'button', }; -describe('writeChangelog', () => { - beforeAll(() => { +describe(writeChangelog, () => { + beforeEach(() => { jest.spyOn(console, 'warn').mockImplementation(); jest.spyOn(console, 'info').mockImplementation(); jest.spyOn(fs, 'writeFileSync').mockImplementation(); }); - afterAll(() => { - (console.warn as jest.Mock).mockRestore(); - (console.info as jest.Mock).mockRestore(); - (fs.writeFileSync as jest.Mock).mockRestore(); - mockInitConventionalCommitReadableStream.mockRestore(); + + afterEach(() => { + jest.clearAllMocks(); }); - describe('handle buildConventionalChangelog error', () => { - beforeAll(async () => { - mockInitConventionalCommitReadableStream.mockReturnValue( + describe('handle errors', () => { + beforeEach(async () => { + mockCreateConventionalCommitStream.mockReturnValue( new Stream.Readable({ read() { this.emit('error', '💥'); @@ -45,41 +44,34 @@ describe('writeChangelog', () => { await writeChangelog(config, '0.0.1'); }); - afterAll(() => { - (console.warn as jest.Mock).mockClear(); - (console.info as jest.Mock).mockClear(); - }); - it('should print a console.warn', async () => { expect(console.warn).toHaveBeenCalledWith( 'changelog creation failed', '💥', ); }); + it('should not write a changelog file', async () => { expect(fs.writeFileSync).not.toHaveBeenCalled(); }); }); + describe('--dryRun', () => { - const version = '0.0.1-rc1'; + const version = '1.0.0'; - beforeAll(async () => { - mockInitConventionalCommitReadableStream.mockImplementation( - jest.requireActual('./init-conventional-commit-readable-stream') - .initConventionalCommitReadableStream, + beforeEach(async () => { + mockCreateConventionalCommitStream.mockImplementation( + jest.requireActual('./conventional-commit') + .createConventionalCommitStream, ); await writeChangelog({ ...config, dryRun: true }, version); }); - afterAll(() => { - (console.warn as jest.Mock).mockClear(); - (console.info as jest.Mock).mockClear(); - }); - it('should not write a changelog file', async () => { expect(fs.writeFileSync).not.toHaveBeenCalled(); }); + it('should print a console.info with the changelog contents without the header', async () => { expect(console.info).toHaveBeenCalledWith( expect.stringContaining(`## ${version}`), @@ -89,4 +81,50 @@ describe('writeChangelog', () => { ); }); }); + + describe('--preset', () => { + const version = '1.0.0'; + + beforeEach(async () => { + mockCreateConventionalCommitStream.mockImplementation( + jest.requireActual('./conventional-commit') + .createConventionalCommitStream, + ); + + await writeChangelog( + { + ...config, + preset: { + types: [ + { type: 'feat', section: 'Awesome Features' }, + { type: 'fix', section: 'Important Fixes' }, + { type: 'chore', hidden: true }, + { type: 'docs', hidden: true }, + { type: 'style', hidden: true }, + { type: 'refactor', hidden: true }, + { type: 'perf', hidden: true }, + { type: 'test', hidden: true }, + ], + }, + dryRun: true, + }, + version, + ); + }); + + it('should load custom preset', () => { + expect( + mockCreateConventionalCommitStream.mock.calls[0][0].preset, + ).toMatchSnapshot(); + }); + + it('should print changelog', () => { + expect((console.info as jest.Mock).mock.calls[0][0]).toContain( + 'Awesome Features', + ); + expect((console.info as jest.Mock).mock.calls[0][0]).toContain( + 'Important Fixes', + ); + }); + }); }); diff --git a/packages/semver/src/executors/version/utils/write-changelog.ts b/packages/semver/src/executors/version/utils/write-changelog.ts index 987d011d0..7eb4b8c01 100644 --- a/packages/semver/src/executors/version/utils/write-changelog.ts +++ b/packages/semver/src/executors/version/utils/write-changelog.ts @@ -1,7 +1,8 @@ import * as chalk from 'chalk'; +import * as createPreset from 'conventional-changelog-conventionalcommits'; import { accessSync, constants, readFileSync, writeFileSync } from 'fs'; import { WriteChangelogConfig } from '../schema'; -import { initConventionalCommitReadableStream } from './init-conventional-commit-readable-stream'; +import { createConventionalCommitStream } from './conventional-commit'; const START_OF_LAST_RELEASE_PATTERN = /(^#+ \[?[0-9]+\.[0-9]+\.[0-9]+| { return buildConventionalChangelog(config, newVersion) .then((newContent) => { if (config.dryRun) { @@ -51,14 +52,19 @@ function buildExistingContent(config: WriteChangelogConfig) { return existingContent; } -function buildConventionalChangelog( +async function buildConventionalChangelog( config: WriteChangelogConfig, newVersion: string, ): Promise { + const preset = + typeof config.preset === 'object' + ? await createPreset(config.preset) + : config.preset; + return new Promise((resolve, reject) => { let changelog = ''; - const changelogStream = initConventionalCommitReadableStream( - config, + const changelogStream = createConventionalCommitStream( + { ...config, preset }, newVersion, ); @@ -73,7 +79,5 @@ function buildConventionalChangelog( changelogStream.on('end', function () { resolve(changelog); }); - - return; }); } diff --git a/packages/semver/src/shims.d.ts b/packages/semver/src/shims.d.ts index aec584cf4..bb15f7499 100644 --- a/packages/semver/src/shims.d.ts +++ b/packages/semver/src/shims.d.ts @@ -1,2 +1,3 @@ declare module 'git-raw-commits'; declare module 'git-semver-tags'; +declare module 'conventional-changelog-conventionalcommits'; diff --git a/yarn.lock b/yarn.lock index 9f8c75ca1..5897ef4cb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2064,7 +2064,7 @@ __metadata: version: 0.0.0-use.local resolution: "@jscutlery/semver@workspace:packages/semver" dependencies: - "@types/conventional-changelog": ^3.1.1 + "@types/conventional-changelog": "^3.1.4 " "@types/conventional-recommended-bump": 6.1.1 "@types/inquirer": 8.2.9 "@types/rimraf": 3.0.2 @@ -2072,7 +2072,8 @@ __metadata: "@types/standard-version": 7.1.2 "@types/tmp": 0.2.5 chalk: 4.1.2 - conventional-changelog: ^5.0.0 + conventional-changelog: ^5.1.0 + conventional-changelog-conventionalcommits: ^7.0.2 conventional-recommended-bump: ^7.0.0 detect-indent: 6.1.0 inquirer: 8.2.6 @@ -2579,7 +2580,7 @@ __metadata: languageName: node linkType: hard -"@types/conventional-changelog@npm:^3.1.1": +"@types/conventional-changelog@npm:^3.1.4 ": version: 3.1.4 resolution: "@types/conventional-changelog@npm:3.1.4" dependencies: @@ -3982,7 +3983,7 @@ __metadata: languageName: node linkType: hard -"conventional-changelog@npm:^5.0.0": +"conventional-changelog@npm:^5.1.0": version: 5.1.0 resolution: "conventional-changelog@npm:5.1.0" dependencies: