From a902e088b02d06b8a0322de21b1313bb4c90a377 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 | 22 +++++++--------------- 7 files changed, 50 insertions(+), 40 deletions(-) diff --git a/index.js b/index.js index c6fc14c7..20e6b59f 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 a206c6e0..5615daba 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'); -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 65cd6d21..7f604c68 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 d5fa8c2f..9a749613 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 1c1aa917..32d952fe 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 c863ad83..7c20613d 100644 --- a/test/verify.test.js +++ b/test/verify.test.js @@ -4,24 +4,16 @@ const verify = require('../lib/verify'); test('Verify String "changelogFile" and "chagngelogTitle"', 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'); + 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');