From ff1fe413e47e9956b7a710267749f1a8d2815f65 Mon Sep 17 00:00:00 2001 From: Andrew Ross Date: Thu, 23 Feb 2023 16:52:32 -0800 Subject: [PATCH] Use imperative mood in changelog entry (#131) * Use imperative mood in changelog entry The imperative mood is generally recommended for git commit messages. Git uses it for things like "Revert ..." or "Merge ..." and dependabot uses it in the [commit message][1]. This changes the changelog helper to use the imperative mood for consistency. [1]: https://github.com/dangoslen/dependabot-changelog-helper/commit/11616d35c16f6141349e2417035d9440c3218b36 --------- Signed-off-by: Andrew Ross Co-authored-by: dangoslen --- CHANGELOG.md | 5 +- __tests__/changelog-updater.test.ts | 159 +++++++++++++++++++--------- action.yml | 5 + dist/index.js | 2 +- src/changelog-updater.ts | 41 ++++--- src/dependabot-helper.ts | 4 +- 6 files changed, 151 insertions(+), 65 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b20caf9..04ea186 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,9 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) ## [UNRELEASED] +### Changed +- Use imperative mood in changelog entry by default + ### Dependencies - Bumps `typescript` from 4.9.4 to 4.9.5 - Bumps `eslint` from 8.32.0 to 8.34.0 @@ -82,4 +85,4 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) ### Dependencies - Bumps `eslint` from 7.17.0 to 7.21.0 - Bumps `@types/node` from 14.14.30 to 14.14.31 -- Bumps `eslint-plugin-jest` from 24.1.3 to 24.1.5 \ No newline at end of file +- Bumps `eslint-plugin-jest` from 24.1.3 to 24.1.5 diff --git a/__tests__/changelog-updater.test.ts b/__tests__/changelog-updater.test.ts index c22a384..f800bb1 100644 --- a/__tests__/changelog-updater.test.ts +++ b/__tests__/changelog-updater.test.ts @@ -18,38 +18,38 @@ const CHANGELOG_WITH_PROPER_SECTIONS_AND_ENTRIES = `# Changelog ## [v1.0.0] ### Dependencies -- Bumps \`different-package\` from v1 to v2` +- Bump \`different-package\` from v1 to v2` test('adds an entry to the changelog when section already exists with entry', async () => { mockReadStream(CHANGELOG_WITH_PROPER_SECTIONS_AND_ENTRIES) - await updateChangelog(PACKAGE_ENTRY, 'v1.0.0', './CHANGELOG.md') + await updateChangelog(PACKAGE_ENTRY, 'v1.0.0', './CHANGELOG.md', 'Bump') expectWrittenChangelogToBe(`# Changelog ## [v1.0.0] ### Dependencies -- Bumps \`different-package\` from v1 to v2 -- Bumps \`package\` from v1 to v2`) +- Bump \`different-package\` from v1 to v2 +- Bump \`package\` from v1 to v2`) }) const CHANGELOG_WITH_PROPER_SECTIONS_AND_ENTRIES_UNRELEASED = `# Changelog ## [UNRELEASED] ### Dependencies -- Bumps \`different-package\` from v1 to v2` +- Bump \`different-package\` from v1 to v2` test('adds an entry to the changelog when section exists under default unreleased version', async () => { mockReadStream(CHANGELOG_WITH_PROPER_SECTIONS_AND_ENTRIES_UNRELEASED) - await updateChangelog(PACKAGE_ENTRY, 'nope', './CHANGELOG.md') + await updateChangelog(PACKAGE_ENTRY, 'nope', './CHANGELOG.md', 'Bump') expectWrittenChangelogToBe(`# Changelog ## [UNRELEASED] ### Dependencies -- Bumps \`different-package\` from v1 to v2 -- Bumps \`package\` from v1 to v2`) +- Bump \`different-package\` from v1 to v2 +- Bump \`package\` from v1 to v2`) }) const CHANGELOG_WITH_PROPER_SECTIONS_UNRELEASED = `# Changelog @@ -60,13 +60,13 @@ const CHANGELOG_WITH_PROPER_SECTIONS_UNRELEASED = `# Changelog test('adds an entry to the changelog when section already exists, but no entry', async () => { mockReadStream(CHANGELOG_WITH_PROPER_SECTIONS_UNRELEASED) - await updateChangelog(PACKAGE_ENTRY, 'v1.0.0', './CHANGELOG.md') + await updateChangelog(PACKAGE_ENTRY, 'v1.0.0', './CHANGELOG.md', 'Bump') expectWrittenChangelogToBe(`# Changelog ## [UNRELEASED] ### Dependencies -- Bumps \`package\` from v1 to v2`) +- Bump \`package\` from v1 to v2`) }) const CHANGELOG_MISSING_DEPENDECIES = `# Changelog @@ -78,41 +78,41 @@ test('adds an entry to the changelog when version exists but section does not', fs.createReadStream.mockReturnValue(readable) fs.readFileSync.mockReturnValue(CHANGELOG_MISSING_DEPENDECIES) - await updateChangelog(PACKAGE_ENTRY, 'UNRELEASED', './CHANGELOG.md') + await updateChangelog(PACKAGE_ENTRY, 'UNRELEASED', './CHANGELOG.md', 'Bump') expectWrittenChangelogToBe(`# Changelog ## [UNRELEASED] ### Dependencies -- Bumps \`package\` from v1 to v2`) +- Bump \`package\` from v1 to v2`) }) const CHANGELOG_WITH_MULTIPLE_VERSIONS = `# Changelog ## [UNRELEASED] ### Dependencies -- Bumps \`different-package\` from v1 to v2 +- Bump \`different-package\` from v1 to v2 ## [v1.0.0] ### Dependencies -- Bumps \`foo\` from bar to foo-bar +- Bump \`foo\` from bar to foo-bar ` test('adds an entry to the changelog - multiple versions', async () => { mockReadStream(CHANGELOG_WITH_MULTIPLE_VERSIONS) - await updateChangelog(PACKAGE_ENTRY, 'UNRELEASED', './CHANGELOG.md') + await updateChangelog(PACKAGE_ENTRY, 'UNRELEASED', './CHANGELOG.md', 'Bump') expectWrittenChangelogToBe(`# Changelog ## [UNRELEASED] ### Dependencies -- Bumps \`different-package\` from v1 to v2 -- Bumps \`package\` from v1 to v2 +- Bump \`different-package\` from v1 to v2 +- Bump \`package\` from v1 to v2 ## [v1.0.0] ### Dependencies -- Bumps \`foo\` from bar to foo-bar`) +- Bump \`foo\` from bar to foo-bar`) }) const CHANGELOG_WITH_NO_VERSION = `# Changelog @@ -122,7 +122,7 @@ test('errors when there is no version section', async () => { mockReadStream(CHANGELOG_WITH_NO_VERSION) try { - await updateChangelog(PACKAGE_ENTRY, 'v1.0.0', './CHANGELOG.md') + await updateChangelog(PACKAGE_ENTRY, 'v1.0.0', './CHANGELOG.md', 'Bump') } catch (err) { expect(err).not.toBeNull() expect(fs.writeFileSync).toBeCalledTimes(0) @@ -133,12 +133,12 @@ const CHANGELOG_WITH_DUPLICATE_ENTRY = `# Changelog ## [v1.0.0] ### Dependencies -- Bumps \`package\` from v1 to v2` +- Bump \`package\` from v1 to v2` test('does not update the changelog on duplicate entry', async () => { mockReadStream(CHANGELOG_WITH_DUPLICATE_ENTRY) - await updateChangelog(PACKAGE_ENTRY, 'v1.0.0', './CHANGELOG.md') + await updateChangelog(PACKAGE_ENTRY, 'v1.0.0', './CHANGELOG.md', 'Bump') expect(fs.writeFileSync).toBeCalledTimes(0) }) @@ -147,7 +147,7 @@ const CHANGELOG_WITH_DUPLICATE_ENTRY_NOT_LAST_LINE = `# Changelog ## [v1.0.0] ### Dependencies -- Bumps \`package\` from v1 to v2 +- Bump \`package\` from v1 to v2 ## [v0.9.0] ### Added @@ -156,7 +156,7 @@ const CHANGELOG_WITH_DUPLICATE_ENTRY_NOT_LAST_LINE = `# Changelog test('does not update the changelog on duplicate entry when not the last item', async () => { mockReadStream(CHANGELOG_WITH_DUPLICATE_ENTRY_NOT_LAST_LINE) - await updateChangelog(PACKAGE_ENTRY, 'v1.0.0', './CHANGELOG.md') + await updateChangelog(PACKAGE_ENTRY, 'v1.0.0', './CHANGELOG.md', 'Bump') expect(fs.writeFileSync).toBeCalledTimes(0) }) @@ -165,19 +165,19 @@ const CHANGELOG_WITH_ENTRY_TO_UPDATE = `# Changelog ## [v1.0.0] ### Dependencies -- Bumps \`package\` from v1 to v1.1` +- Bump \`package\` from v1 to v1.1` test('updates an entry for an existing package in the same version', async () => { mockReadStream(CHANGELOG_WITH_ENTRY_TO_UPDATE) - await updateChangelog(PACKAGE_ENTRY, 'v1.0.0', './CHANGELOG.md') + await updateChangelog(PACKAGE_ENTRY, 'v1.0.0', './CHANGELOG.md', 'Bump') expectWrittenChangelogToBe( `# Changelog ## [v1.0.0] ### Dependencies -- Bumps \`package\` from v1 to v2` +- Bump \`package\` from v1 to v2` ) }) @@ -190,7 +190,7 @@ const CHANGELOG_WITH_VERSION_MISSING_DEP_SECTION_BUT_HAS_OTHERS = `# Changelog test('updates version with new section and entry', async () => { mockReadStream(CHANGELOG_WITH_VERSION_MISSING_DEP_SECTION_BUT_HAS_OTHERS) - await updateChangelog(PACKAGE_ENTRY, 'v1.0.0', './CHANGELOG.md') + await updateChangelog(PACKAGE_ENTRY, 'v1.0.0', './CHANGELOG.md', 'Bump') expectWrittenChangelogToBe( `# Changelog @@ -199,7 +199,7 @@ test('updates version with new section and entry', async () => { ### Added ### Removed ### Dependencies -- Bumps \`package\` from v1 to v2` +- Bump \`package\` from v1 to v2` ) }) @@ -207,27 +207,27 @@ const CHANGELOG_WITH_MULTI_VERSION_PACKAGE_UPDATES = `# Changelog ## [v1.0.0] ### Dependencies -- Bumps \`package\` from v1 to v1.1 +- Bump \`package\` from v1 to v1.1 ## [v0.9.0] ### Dependencies -- Bumps \`package\` from alpha to v1` +- Bump \`package\` from alpha to v1` test('Does not update lines additional times', async () => { mockReadStream(CHANGELOG_WITH_MULTI_VERSION_PACKAGE_UPDATES) - await updateChangelog(PACKAGE_ENTRY, 'v1.0.0', './CHANGELOG.md') + await updateChangelog(PACKAGE_ENTRY, 'v1.0.0', './CHANGELOG.md', 'Bump') expectWrittenChangelogToBe( `# Changelog ## [v1.0.0] ### Dependencies -- Bumps \`package\` from v1 to v2 +- Bump \`package\` from v1 to v2 ## [v0.9.0] ### Dependencies -- Bumps \`package\` from alpha to v1` +- Bump \`package\` from alpha to v1` ) }) @@ -239,17 +239,17 @@ const CHANGELOG_WITH_EXISTING_SECTION_AND_SEPARATED_SECTIONS = `# Changelog - Added a new feature ### Dependencies -- Bumps \`other-package\` from v2 to v3 +- Bump \`other-package\` from v2 to v3 ## [v0.9.0] ### Dependencies -- Bumps \`package\` from alpha to v1` +- Bump \`package\` from alpha to v1` test('Updates existing section when sections separated by blank lines', async () => { mockReadStream(CHANGELOG_WITH_EXISTING_SECTION_AND_SEPARATED_SECTIONS) - await updateChangelog(PACKAGE_ENTRY, 'v1.0.0', './CHANGELOG.md') + await updateChangelog(PACKAGE_ENTRY, 'v1.0.0', './CHANGELOG.md', 'Bump') expectWrittenChangelogToBe( `# Changelog @@ -260,13 +260,13 @@ test('Updates existing section when sections separated by blank lines', async () - Added a new feature ### Dependencies -- Bumps \`other-package\` from v2 to v3 -- Bumps \`package\` from v1 to v2 +- Bump \`other-package\` from v2 to v3 +- Bump \`package\` from v1 to v2 ## [v0.9.0] ### Dependencies -- Bumps \`package\` from alpha to v1` +- Bump \`package\` from alpha to v1` ) }) @@ -283,12 +283,12 @@ const CHANGELOG_WITHOUT_EXISTING_SECTION_AND_SEPARATED_SECTIONS = `# Changelog ## [v0.9.0] ### Dependencies -- Bumps \`package\` from alpha to v1` +- Bump \`package\` from alpha to v1` test('Adds section when sections separated by blank lines', async () => { mockReadStream(CHANGELOG_WITHOUT_EXISTING_SECTION_AND_SEPARATED_SECTIONS) - await updateChangelog(PACKAGE_ENTRY, 'v1.0.0', './CHANGELOG.md') + await updateChangelog(PACKAGE_ENTRY, 'v1.0.0', './CHANGELOG.md', 'Bump') expectWrittenChangelogToBe( `# Changelog @@ -301,12 +301,12 @@ test('Adds section when sections separated by blank lines', async () => { ### Removed - Removed a feature ### Dependencies -- Bumps \`package\` from v1 to v2 +- Bump \`package\` from v1 to v2 ## [v0.9.0] ### Dependencies -- Bumps \`package\` from alpha to v1` +- Bump \`package\` from alpha to v1` ) }) @@ -318,7 +318,7 @@ const CHANGELOG_WITH_EXISTING_SECTION_BETWEEN_OTHERS = `# Changelog - Added a new feature ### Dependencies -- Bumps \`other-package\` from v2 to v3 +- Bump \`other-package\` from v2 to v3 ### Removed - Removed a feature @@ -326,12 +326,12 @@ const CHANGELOG_WITH_EXISTING_SECTION_BETWEEN_OTHERS = `# Changelog ## [v0.9.0] ### Dependencies -- Bumps \`package\` from alpha to v1` +- Bump \`package\` from alpha to v1` test('Updates existing section when between other sections', async () => { mockReadStream(CHANGELOG_WITH_EXISTING_SECTION_BETWEEN_OTHERS) - await updateChangelog(PACKAGE_ENTRY, 'v1.0.0', './CHANGELOG.md') + await updateChangelog(PACKAGE_ENTRY, 'v1.0.0', './CHANGELOG.md', 'Bump') expectWrittenChangelogToBe( `# Changelog @@ -342,8 +342,8 @@ test('Updates existing section when between other sections', async () => { - Added a new feature ### Dependencies -- Bumps \`other-package\` from v2 to v3 -- Bumps \`package\` from v1 to v2 +- Bump \`other-package\` from v2 to v3 +- Bump \`package\` from v1 to v2 ### Removed - Removed a feature @@ -351,10 +351,71 @@ test('Updates existing section when between other sections', async () => { ## [v0.9.0] ### Dependencies -- Bumps \`package\` from alpha to v1` +- Bump \`package\` from alpha to v1` ) }) +const CHANGELOG_WITH_PROPER_SECTIONS_AND_ENTRIES_DIFFERENT_PREFIX = `# Changelog + +## [v1.0.0] +### Dependencies +- Bump \`different-package\` from v1 to v2` + +test('adds an entry with a different prefix to the changelog when section already exists with entry', async () => { + mockReadStream(CHANGELOG_WITH_PROPER_SECTIONS_AND_ENTRIES) + + await updateChangelog(PACKAGE_ENTRY, 'v1.0.0', './CHANGELOG.md', 'Update') + + const params = fs.writeFileSync.mock.calls[0] + expect(params[0]).toStrictEqual('./CHANGELOG.md') + expect(params[1]).toStrictEqual(`# Changelog + +## [v1.0.0] +### Dependencies +- Bump \`different-package\` from v1 to v2 +- Update \`package\` from v1 to v2`) +}) + +const CHANGELOG_WITH_DUPLICATE_ENTRY_DIFFERENT_PREFIX = `# Changelog + +## [v1.0.0] +### Dependencies +- Bump \`package\` from v1 to v2` + +test('keeps prefix on entry with a different prefix but is otherwise a duplicate', async () => { + mockReadStream(CHANGELOG_WITH_DUPLICATE_ENTRY_DIFFERENT_PREFIX) + + await updateChangelog(PACKAGE_ENTRY, 'v1.0.0', './CHANGELOG.md', 'Update') + + const params = fs.writeFileSync.mock.calls[0] + expect(params[0]).toStrictEqual('./CHANGELOG.md') + expect(params[1]).toStrictEqual(`# Changelog + +## [v1.0.0] +### Dependencies +- Bump \`package\` from v1 to v2`) +}) + +const CHANGELOG_WITH_EXISTING_ENTRY_DIFFERENT_PREFIX = `# Changelog + +## [v1.0.0] +### Dependencies +- Bump \`package\` from v1 to v1.1` + +test('keeps prefix on entry with a different prefix', async () => { + mockReadStream(CHANGELOG_WITH_DUPLICATE_ENTRY_DIFFERENT_PREFIX) + + await updateChangelog(PACKAGE_ENTRY, 'v1.0.0', './CHANGELOG.md', 'Update') + + const params = fs.writeFileSync.mock.calls[0] + expect(params[0]).toStrictEqual('./CHANGELOG.md') + expect(params[1]).toStrictEqual(`# Changelog + +## [v1.0.0] +### Dependencies +- Bump \`package\` from v1 to v2`) +}) + function mockReadStream(changelog: string) { fs.createReadStream.mockImplementation((_: PathLike) => { return Readable.from([changelog]) diff --git a/action.yml b/action.yml index 23c8634..2becbfd 100644 --- a/action.yml +++ b/action.yml @@ -18,6 +18,11 @@ inputs: "The label to indicate that the action should run" required: true default: 'dependabot' + entryPrefix: + description: | + "The prefix word (after the hyphen) of the changelog entry, for example: '- [entryPrefix] `dependency` from v1.0 to v2.0'" + required: true + default: 'Bump' runs: using: 'node16' main: 'dist/index.js' diff --git a/dist/index.js b/dist/index.js index 88f9e4f..de08df4 100644 --- a/dist/index.js +++ b/dist/index.js @@ -68,7 +68,7 @@ function buildEntryLine(entry) { return `${buildEntryLineStart(entry)} ${entry.oldVersion} to ${entry.newVersion}`; } function buildEntryLineStart(entry) { - return `- Bumps \`${entry.package}\` from`; + return `- Bump \`${entry.package}\` from`; } function addNewEntry(entry, changelogPath, result) { // We build the entry string "backwards" so that we can only do one write, and base it on if the correct diff --git a/src/changelog-updater.ts b/src/changelog-updater.ts index 471013d..fe3eb33 100644 --- a/src/changelog-updater.ts +++ b/src/changelog-updater.ts @@ -21,13 +21,19 @@ const EMPTY_LINE_REGEX = new RegExp(/^\s*$/) export async function updateChangelog( entry: DependabotEntry, version: string, - changelogPath: fs.PathLike + changelogPath: fs.PathLike, + entryPrefix: string ): Promise { const versionRegex: RegExp = buildVersionRegex(version) const regexs: RegExp[] = [versionRegex, UNRELEASED_REGEX] for (const regex of regexs) { - const found = await searchAndUpdateVersion(regex, entry, changelogPath) + const found = await searchAndUpdateVersion( + regex, + entry, + changelogPath, + entryPrefix + ) // If we found the version, we have updated the changelog or we had a duplicate if (found) { @@ -41,10 +47,12 @@ export async function updateChangelog( async function searchAndUpdateVersion( versionRegex: RegExp, entry: DependabotEntry, - changelogPath: fs.PathLike + changelogPath: fs.PathLike, + entryPrefix: string ): Promise { const result = await parseChangelogForEntry( versionRegex, + entryPrefix, entry, changelogPath ) @@ -56,30 +64,38 @@ async function searchAndUpdateVersion( if (result.foundEntryToUpdate) { updateEntry(entry, changelogPath, result) } else if (!result.foundDuplicateEntry) { - addNewEntry(entry, changelogPath, result) + addNewEntry(entryPrefix, entry, changelogPath, result) } return true } -function buildEntryLine(entry: DependabotEntry): string { - return `${buildEntryLineStart(entry)} ${entry.oldVersion} to ${ +function buildEntryLine(entryPrefix: string, entry: DependabotEntry): string { + return `${buildEntryLineStart(entryPrefix, entry)} ${entry.oldVersion} to ${ entry.newVersion }` } -function buildEntryLineStart(entry: DependabotEntry): string { - return `- Bumps \`${entry.package}\` from` +function buildEntryLineStart( + entryPrefix: string, + entry: DependabotEntry +): string { + return `- ${entryPrefix} \`${entry.package}\` from` +} + +function buildEntryLineStartRegex(entry: DependabotEntry): RegExp { + return new RegExp(`- \\w+ \`${entry.package}\` from `) } function addNewEntry( + prefix: string, entry: DependabotEntry, changelogPath: fs.PathLike, result: ParsedResult ): void { // We build the entry string "backwards" so that we can only do one write, and base it on if the correct // sections exist - let changelogEntry = buildEntryLine(entry) + let changelogEntry = buildEntryLine(prefix, entry) const lineNumber = result.changelogLineNumber if (!result.dependencySectionFound) { changelogEntry = `### Dependencies${EOL}${changelogEntry}` @@ -129,6 +145,7 @@ function buildVersionRegex(version: string): RegExp { async function parseChangelogForEntry( versionRegex: RegExp, + entryPrefix: string, entry: DependabotEntry, changelogPath: fs.PathLike ): Promise { @@ -145,8 +162,8 @@ async function parseChangelogForEntry( let foundDuplicateEntry = false let foundEntryToUpdate = false - const entryLine = buildEntryLine(entry) - const entryLineStart = buildEntryLineStart(entry) + const entryLine = buildEntryLine(entryPrefix, entry) + const entryLineStartRegex = buildEntryLineStartRegex(entry) const contents = [] @@ -176,7 +193,7 @@ async function parseChangelogForEntry( } else if (line.startsWith('- ')) { if (line.startsWith(entryLine)) { foundDuplicateEntry = true - } else if (line.startsWith(entryLineStart)) { + } else if (entryLineStartRegex.test(line)) { foundEntryToUpdate = true changelogLineNumber = lineNumber } else { diff --git a/src/dependabot-helper.ts b/src/dependabot-helper.ts index 33f5fcc..e314205 100644 --- a/src/dependabot-helper.ts +++ b/src/dependabot-helper.ts @@ -8,12 +8,12 @@ async function run(): Promise { try { const version: string = core.getInput('version') const label: string = core.getInput('activationLabel') - const changelogPath: PathLike = core.getInput('changelogPath') + const entryPrefix: string = core.getInput('entryPrefix') if (label !== '' && pullRequestHasLabel(label)) { const entry: DependabotEntry = getDependabotEntry(github.context.payload) - await updateChangelog(entry, version, changelogPath) + await updateChangelog(entry, version, changelogPath, entryPrefix) } } catch (err) { if (err instanceof Error) {