From d1803daf7ca968c8b49c2beb1130f083dce8240f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20Schmitz=20von=20H=C3=BClst?= Date: Thu, 26 Nov 2020 15:05:00 +0100 Subject: [PATCH] feat: add template functionality --- index.js | 4 ++-- lib/prepare.js | 7 +++++-- lib/resolve-config.js | 6 +++--- lib/verify.js | 4 ++-- test/integration.test.js | 34 ++++++++++++++++++---------------- test/prepare.test.js | 13 +++++++++++++ test/verify.test.js | 26 +++++++++----------------- 7 files changed, 52 insertions(+), 42 deletions(-) diff --git a/index.js b/index.js index 1d9efd42..087ddaeb 100644 --- a/index.js +++ b/index.js @@ -16,13 +16,13 @@ async function verifyConditions(pluginConfig, context) { pluginConfig.changelogFile = defaultTo(pluginConfig.changelogFile, preparePlugin.changelogFile); } - await verifyChangelog(pluginConfig); + await verifyChangelog(pluginConfig, context); verified = true; } async function prepare(pluginConfig, context) { if (!verified) { - await verifyChangelog(pluginConfig); + await verifyChangelog(pluginConfig, context); verified = true; } diff --git a/lib/prepare.js b/lib/prepare.js index 7ce101a3..ab953c0f 100644 --- a/lib/prepare.js +++ b/lib/prepare.js @@ -2,9 +2,12 @@ const path = require('path'); const {readFile, writeFile, ensureFile} = require('fs-extra'); const resolveConfig = require('./resolve-config.js'); -module.exports = async (pluginConfig, {cwd, nextRelease: {notes}, logger}) => { - const {changelogFile, changelogTitle} = resolveConfig(pluginConfig); +module.exports = async (pluginConfig, {cwd, stdout, stderr, logger, ...context}) => { + const {changelogFile, changelogTitle} = resolveConfig(pluginConfig, context); const changelogPath = path.resolve(cwd, changelogFile); + const { + nextRelease: {notes}, + } = context; if (notes) { await ensureFile(changelogPath); diff --git a/lib/resolve-config.js b/lib/resolve-config.js index 2ee6c59a..ff6c150e 100644 --- a/lib/resolve-config.js +++ b/lib/resolve-config.js @@ -1,6 +1,6 @@ -const {isNil} = require('lodash'); +const {isNil, template} = require('lodash'); -module.exports = ({changelogFile, changelogTitle}) => ({ - changelogFile: isNil(changelogFile) ? 'CHANGELOG.md' : changelogFile, +module.exports = ({changelogFile, changelogTitle}, context) => ({ + changelogFile: isNil(changelogFile) ? 'CHANGELOG.md' : template(changelogFile)(context), changelogTitle, }); diff --git a/lib/verify.js b/lib/verify.js index f4b93edb..605d441f 100644 --- a/lib/verify.js +++ b/lib/verify.js @@ -10,8 +10,8 @@ const VALIDATORS = { changelogTitle: isNonEmptyString, }; -module.exports = (pluginConfig) => { - const options = resolveConfig(pluginConfig); +module.exports = (pluginConfig, {cwd, stdout, stderr, logger, ...context}) => { + const options = resolveConfig(pluginConfig, context); const errors = Object.entries(options).reduce( (errors, [option, value]) => diff --git a/test/integration.test.js b/test/integration.test.js index ac294a8a..d0885b3e 100644 --- a/test/integration.test.js +++ b/test/integration.test.js @@ -36,6 +36,24 @@ test.serial('Create new CHANGELOG.md', async (t) => { t.deepEqual(t.context.log.args[0], ['Create %s', changelogPath]); }); +test.serial('Create new changelog with template', async (t) => { + const cwd = tempy.directory(); + const notes = 'Test release note'; + const version = '1.2.3-development.0'; + const changelogFile = `docs/CHANGELOG-\${nextRelease.version}.txt`; + const changelogPath = path.resolve(cwd, `docs/CHANGELOG-${version}.txt`); + + await t.context.m.prepare( + {changelogFile}, + {cwd, options: {}, nextRelease: {notes, version}, logger: t.context.logger} + ); + + // Verify the content of the CHANGELOG.md + t.is((await readFile(changelogPath)).toString(), `${notes}\n`); + + t.deepEqual(t.context.log.args[0], ['Create %s', changelogPath]); +}); + test.serial('Skip changelog update if the release is empty', async (t) => { const cwd = tempy.directory(); const changelogFile = 'CHANGELOG.txt'; @@ -65,19 +83,3 @@ test.serial('Verify only on the fist call', async (t) => { t.deepEqual(t.context.log.args[0], ['Create %s', changelogPath]); }); - -test('Throw SemanticReleaseError if prepare "changelogFile" option is not a string', async (t) => { - const cwd = tempy.directory(); - const changelogFile = 42; - const errors = [ - ...(await t.throwsAsync( - t.context.m.verifyConditions( - {}, - {cwd, options: {prepare: ['@semantic-release/git', {path: '@semantic-release/changelog', changelogFile}]}} - ) - )), - ]; - - t.is(errors[0].name, 'SemanticReleaseError'); - t.is(errors[0].code, 'EINVALIDCHANGELOGFILE'); -}); diff --git a/test/prepare.test.js b/test/prepare.test.js index e3037d35..66a39c46 100644 --- a/test/prepare.test.js +++ b/test/prepare.test.js @@ -90,3 +90,16 @@ test.serial('Create new changelog with title if specified', async (t) => { t.is((await readFile(changelogPath)).toString(), `${changelogTitle}\n\n${notes}\n`); }); + +test('Create new changelog with template', async t => { + const cwd = tempy.directory(); + const notes = 'Test release note'; + const version = '1.2.3'; + const changelogTitle = '# My Changelog Title'; + const changelogFile = `HISTORY-\${nextRelease.version}.md`; + const changelogPath = path.resolve(cwd, `HISTORY-${version}.md`); + + await prepare({changelogTitle, changelogFile}, {cwd, nextRelease: {notes, version}, logger: t.context.logger}); + + t.is((await readFile(changelogPath)).toString(), `${changelogTitle}\n\n${notes}\n`); +}); diff --git a/test/verify.test.js b/test/verify.test.js index 57703e64..3a3c1425 100644 --- a/test/verify.test.js +++ b/test/verify.test.js @@ -1,27 +1,19 @@ const test = require('ava'); const verify = require('../lib/verify.js'); -test('Verify String "changelogFile" and "chagngelogTitle"', (t) => { +test('Verify String "changelogFile" and "changelogTitle"', (t) => { const changelogFile = 'docs/changelog.txt'; const changelogTitle = '# My title here'; - t.notThrows(() => verify({changelogFile, changelogTitle})); + t.notThrows(() => verify({changelogFile, changelogTitle}, {})); }); -test('Verify undefined "changelogFile" and "chagngelogTitle"', (t) => { - t.notThrows(() => verify({})); -}); - -test('Throw SemanticReleaseError if "changelogFile" option is not a String', (t) => { - const changelogFile = 42; - const [error] = t.throws(() => verify({changelogFile})); - - t.is(error.name, 'SemanticReleaseError'); - t.is(error.code, 'EINVALIDCHANGELOGFILE'); +test('Verify undefined "changelogFile" and "changelogTitle"', (t) => { + t.notThrows(() => verify({}, {})); }); test('Throw SemanticReleaseError if "changelogFile" option is an empty String', (t) => { const changelogFile = ''; - const [error] = t.throws(() => verify({changelogFile})); + const [error] = t.throws(() => verify({changelogFile}, {})); t.is(error.name, 'SemanticReleaseError'); t.is(error.code, 'EINVALIDCHANGELOGFILE'); @@ -29,7 +21,7 @@ test('Throw SemanticReleaseError if "changelogFile" option is an empty String', test('Throw SemanticReleaseError if "changelogFile" option is a whitespace String', (t) => { const changelogFile = ' \n \r '; - const [error] = t.throws(() => verify({changelogFile})); + const [error] = t.throws(() => verify({changelogFile}, {})); t.is(error.name, 'SemanticReleaseError'); t.is(error.code, 'EINVALIDCHANGELOGFILE'); @@ -37,14 +29,14 @@ test('Throw SemanticReleaseError if "changelogFile" option is a whitespace Strin test('Throw SemanticReleaseError if "changelogTitle" option is not a String', (t) => { const changelogTitle = 42; - const [error] = t.throws(() => verify({changelogTitle})); + const [error] = t.throws(() => verify({changelogTitle}, {})); t.is(error.name, 'SemanticReleaseError'); t.is(error.code, 'EINVALIDCHANGELOGTITLE'); }); test('Throw SemanticReleaseError if "changelogTitle" option is an empty String', (t) => { - const [error] = t.throws(() => verify({changelogTitle: ''})); + const [error] = t.throws(() => verify({changelogTitle: ''}, {})); t.is(error.name, 'SemanticReleaseError'); t.is(error.code, 'EINVALIDCHANGELOGTITLE'); @@ -52,7 +44,7 @@ test('Throw SemanticReleaseError if "changelogTitle" option is an empty String', test('Throw SemanticReleaseError if "changelogTitle" option is a whitespace String', (t) => { const changelogTitle = ' \n \r '; - const [error] = t.throws(() => verify({changelogTitle})); + const [error] = t.throws(() => verify({changelogTitle}, {})); t.is(error.name, 'SemanticReleaseError'); t.is(error.code, 'EINVALIDCHANGELOGTITLE');