From 8b592edc2498f7f2a2f023f2ea0d5b5a7f750db8 Mon Sep 17 00:00:00 2001 From: Mark Stacey Date: Wed, 21 Apr 2021 12:57:55 -0230 Subject: [PATCH] Add additional validation error types All invalid changelog cases are now described by the `InvalidChangelogError` error type, which has sub-classes to describe each possible scenario. This allows distinguishing invalid changelog errors from all other unexpected errors. The CLI has been updated to take advantage of this; we now print a simpler error message if the changelog is invalid, rather than a stack trace. --- src/cli.js | 6 ++++- src/validateChangelog.js | 49 +++++++++++++++++++++++++++++++++++----- 2 files changed, 48 insertions(+), 7 deletions(-) diff --git a/src/cli.js b/src/cli.js index 19bd7fd..0614b63 100644 --- a/src/cli.js +++ b/src/cli.js @@ -9,8 +9,9 @@ const { hideBin } = require('yargs/helpers'); const { updateChangelog } = require('./updateChangelog'); const { generateDiff } = require('./generateDiff'); const { - validateChangelog, ChangelogFormattingError, + InvalidChangelogError, + validateChangelog, } = require('./validateChangelog'); const { unreleased } = require('./constants'); @@ -79,6 +80,9 @@ async function validate({ const diff = generateDiff(validChangelog, invalidChangelog); console.error(`Changelog not well-formatted.\nDiff:\n${diff}`); process.exit(1); + } else if (error instanceof InvalidChangelogError) { + console.error(`Changelog is invalid: ${error.message}`); + process.exit(1); } throw error; } diff --git a/src/validateChangelog.js b/src/validateChangelog.js index f372d06..37c4eeb 100644 --- a/src/validateChangelog.js +++ b/src/validateChangelog.js @@ -4,10 +4,36 @@ const { parseChangelog } = require('./parseChangelog'); * @typedef {import('./constants.js').Version} Version */ +/** + * Indicates that the changelog is invalid. + */ +class InvalidChangelogError extends Error {} + +/** + * Indicates that unreleased changes are still present in the changelog. + */ +class UnreleasedChangesError extends InvalidChangelogError { + constructor() { + super('Unreleased changes present in the changelog'); + } +} + +/** + * Indicates that the release header for the current version is missing. + */ +class MissingCurrentVersionError extends InvalidChangelogError { + /** + * @param {Version} currentVersion - The current version + */ + constructor(currentVersion) { + super(`Current version missing from changelog: '${currentVersion}'`); + } +} + /** * Represents a formatting error in a changelog. */ -class ChangelogFormattingError extends Error { +class ChangelogFormattingError extends InvalidChangelogError { /** * @param {Object} options * @param {string} options.validChangelog - The string contents of the well- @@ -36,6 +62,13 @@ class ChangelogFormattingError extends Error { * command will also ensure the current version is represented in the * changelog with a release header, and that there are no unreleased changes * present. + * @throws {InvalidChangelogError} Will throw if the changelog is invalid + * @throws {MissingCurrentVersionError} Will throw if `isReleaseCandidate` is + * `true` and the changelog is missing the release header for the current + * version. + * @throws {UnreleasedChangesError} Will throw if `isReleaseCandidate` is + * `true` and the changelog contains unreleased changes. + * @throws {ChangelogFormattingError} Will throw if there is a formatting error. */ function validateChangelog({ changelogContent, @@ -52,14 +85,12 @@ function validateChangelog({ .getReleases() .find((release) => release.version === currentVersion) ) { - throw new Error( - `Current version missing from changelog: '${currentVersion}'`, - ); + throw new MissingCurrentVersionError(currentVersion); } const hasUnreleasedChanges = changelog.getUnreleasedChanges().length !== 0; if (isReleaseCandidate && hasUnreleasedChanges) { - throw new Error('Unreleased changes present in the changelog'); + throw new UnreleasedChangesError(); } const validChangelog = changelog.toString(); @@ -71,4 +102,10 @@ function validateChangelog({ } } -module.exports = { validateChangelog, ChangelogFormattingError }; +module.exports = { + ChangelogFormattingError, + InvalidChangelogError, + MissingCurrentVersionError, + UnreleasedChangesError, + validateChangelog, +};