Skip to content

Commit

Permalink
feat: use cwd and env options passed by core
Browse files Browse the repository at this point in the history
feat: use `cwd` and `env` options passed by core

BREAKING CHANGE: require `semantic-release` >= `15.8.0`
  • Loading branch information
pvdlg committed Jul 17, 2018
1 parent a172379 commit 3173a68
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 70 deletions.
7 changes: 4 additions & 3 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ const prepareChangelog = require('./lib/prepare');

let verified;

async function verifyConditions(pluginConfig, {options}) {
async function verifyConditions(pluginConfig, context) {
const {options} = context;
// If the Changelog prepare plugin is used and has `changelogFile` configured, validate them now in order to prevent any release if the configuration is wrong
if (options.prepare) {
const preparePlugin =
Expand All @@ -16,12 +17,12 @@ async function verifyConditions(pluginConfig, {options}) {
verified = true;
}

async function prepare(pluginConfig, {nextRelease: {notes}, logger}) {
async function prepare(pluginConfig, context) {
if (!verified) {
await verifyChangelog(pluginConfig);
verified = true;
}
await prepareChangelog(pluginConfig, notes, logger);
await prepareChangelog(pluginConfig, context);
}

module.exports = {verifyConditions, prepare};
14 changes: 8 additions & 6 deletions lib/prepare.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
const path = require('path');
const {readFile, writeFile, ensureFile} = require('fs-extra');
const resolveConfig = require('./resolve-config');

module.exports = async (pluginConfig, notes, logger) => {
module.exports = async (pluginConfig, {cwd, nextRelease: {notes}, logger}) => {
const {changelogFile, changelogTitle} = resolveConfig(pluginConfig);
const changelogPath = path.resolve(cwd, changelogFile);

if (notes) {
await ensureFile(changelogFile);
const currentFile = (await readFile(changelogFile)).toString().trim();
await ensureFile(changelogPath);
const currentFile = (await readFile(changelogPath)).toString().trim();

if (currentFile) {
logger.log('Update %s', changelogFile);
logger.log('Update %s', changelogPath);
} else {
logger.log('Create %s', changelogFile);
logger.log('Create %s', changelogPath);
}

const currentContent =
Expand All @@ -20,6 +22,6 @@ module.exports = async (pluginConfig, notes, logger) => {
: currentFile;
const content = `${notes.trim()}\n${currentContent ? `\n${currentContent}\n` : ''}`;

await writeFile(changelogFile, changelogTitle ? `${changelogTitle}\n\n${content}` : content);
await writeFile(changelogPath, changelogTitle ? `${changelogTitle}\n\n${content}` : content);
}
};
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@
"all": true
},
"peerDependencies": {
"semantic-release": ">=15.0.0 <16.0.0"
"semantic-release": ">=15.8.0 <16.0.0"
},
"prettier": {
"printWidth": 120,
Expand Down
48 changes: 24 additions & 24 deletions test/integration.test.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
import path from 'path';
import test from 'ava';
import {outputFile, readFile} from 'fs-extra';
import {stub} from 'sinon';
import clearModule from 'clear-module';
import tempy from 'tempy';

// Save the current working diretory
const cwd = process.cwd();

test.beforeEach(t => {
// Change current working directory to a temp directory
process.chdir(tempy.directory());
// Clear npm cache to refresh the module state
clearModule('..');
t.context.m = require('..');
Expand All @@ -18,62 +14,66 @@ test.beforeEach(t => {
t.context.logger = {log: t.context.log};
});

test.afterEach.always(() => {
// Restore the current working directory
process.chdir(cwd);
});

test.serial('Verify "changelogFile"', async t => {
const changelogFile = 'docs/changelog.txt';
const cwd = tempy.directory();
const notes = 'Test release note';
const changelogFile = 'docs/changelog.txt';

await t.notThrows(t.context.m.verifyConditions({changelogFile}, {nextRelease: {notes}, options: {}}));
await t.notThrows(t.context.m.verifyConditions({changelogFile}, {cwd, options: {}, nextRelease: {notes}}));
});

test.serial('Create new CHANGELOG.md', async t => {
const changelogFile = 'docs/changelog.txt';
const cwd = tempy.directory();
const notes = 'Test release note';
const changelogFile = 'docs/changelog.txt';
const changelogPath = path.resolve(cwd, changelogFile);

await t.context.m.prepare({changelogFile}, {nextRelease: {notes}, logger: t.context.logger});
await t.context.m.prepare({changelogFile}, {cwd, options: {}, nextRelease: {notes}, logger: t.context.logger});

// Verify the content of the CHANGELOG.md
t.is((await readFile(changelogFile)).toString(), `${notes}\n`);
t.is((await readFile(changelogPath)).toString(), `${notes}\n`);

t.deepEqual(t.context.log.args[0], ['Create %s', changelogFile]);
t.deepEqual(t.context.log.args[0], ['Create %s', changelogPath]);
});

test.serial('Skip changelog update if the release is empty', async t => {
await outputFile('CHANGELOG.md', 'Initial CHANGELOG');
const cwd = tempy.directory();
const changelogFile = 'CHANGELOG.txt';
const changelogPath = path.resolve(cwd, changelogFile);
await outputFile(changelogPath, 'Initial CHANGELOG');

await t.context.m.prepare({}, {nextRelease: {}, options: {}, logger: t.context.logger});
await t.context.m.prepare({}, {cwd, options: {}, nextRelease: {}, logger: t.context.logger});

// Verify the content of the CHANGELOG.md
t.is((await readFile('CHANGELOG.md')).toString(), 'Initial CHANGELOG');
t.is((await readFile(changelogPath)).toString(), 'Initial CHANGELOG');
});

test.serial('Verify only on the fist call', async t => {
const changelogFile = 'docs/changelog.txt';
const cwd = tempy.directory();
const notes = 'Test release note';
const changelogFile = 'docs/changelog.txt';
const changelogPath = path.resolve(cwd, changelogFile);

await t.context.m.verifyConditions(
{changelogFile},
{nextRelease: {notes}, options: {prepare: ['@semantic-release/git']}}
);
await t.context.m.prepare({changelogFile}, {nextRelease: {notes}, logger: t.context.logger});
await t.context.m.prepare({changelogFile}, {cwd, nextRelease: {notes}, logger: t.context.logger});

// Verify the content of the CHANGELOG.md
t.is((await readFile(changelogFile)).toString(), `${notes}\n`);
t.is((await readFile(changelogPath)).toString(), `${notes}\n`);

t.deepEqual(t.context.log.args[0], ['Create %s', changelogFile]);
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.throws(
t.context.m.verifyConditions(
{},
{options: {prepare: ['@semantic-release/git', {path: '@semantic-release/changelog', changelogFile}]}}
{cwd, options: {prepare: ['@semantic-release/git', {path: '@semantic-release/changelog', changelogFile}]}}
)
)),
];
Expand Down
75 changes: 41 additions & 34 deletions test/prepare.test.js
Original file line number Diff line number Diff line change
@@ -1,85 +1,92 @@
import path from 'path';
import test from 'ava';
import {outputFile, readFile} from 'fs-extra';
import {stub} from 'sinon';
import tempy from 'tempy';
import prepare from '../lib/prepare';

// Save the current working diretory
const cwd = process.cwd();

test.beforeEach(t => {
// Change current working directory to a temp directory
process.chdir(tempy.directory());
// Stub the logger
t.context.log = stub();
t.context.logger = {log: t.context.log};
});

test.afterEach.always(() => {
// Restore the current working directory
process.chdir(cwd);
});

test.serial('Create new CHANGELOG.md', async t => {
test('Create new CHANGELOG.md', async t => {
const cwd = tempy.directory();
const notes = 'Test release note';
const changelogFile = 'CHANGELOG.md';
const changelogPath = path.resolve(cwd, changelogFile);

await prepare({}, notes, t.context.logger);
await prepare({}, {cwd, nextRelease: {notes}, logger: t.context.logger});

// Verify the content of the CHANGELOG.md
t.is((await readFile('CHANGELOG.md')).toString(), `${notes}\n`);
t.is((await readFile(changelogPath)).toString(), `${notes}\n`);

t.deepEqual(t.context.log.args[0], ['Create %s', 'CHANGELOG.md']);
t.deepEqual(t.context.log.args[0], ['Create %s', changelogPath]);
});

test.serial('Create new changelog with custom path', async t => {
test('Create new changelog with custom path', async t => {
const cwd = tempy.directory();
const notes = 'Test release note';
const changelogFile = 'docs/changelog.txt';
const changelogPath = path.resolve(cwd, 'docs/changelog.txt');

await prepare({changelogFile}, notes, t.context.logger);
await prepare({changelogFile}, {cwd, nextRelease: {notes}, logger: t.context.logger});

// Verify the content of the CHANGELOG.md
t.is((await readFile(changelogFile)).toString(), `${notes}\n`);
t.is((await readFile(changelogPath)).toString(), `${notes}\n`);

t.deepEqual(t.context.log.args[0], ['Create %s', changelogFile]);
t.deepEqual(t.context.log.args[0], ['Create %s', changelogPath]);
});

test.serial('Prepend the CHANGELOG.md if there is an existing one', async t => {
test('Prepend the CHANGELOG.md if there is an existing one', async t => {
const cwd = tempy.directory();
const notes = 'Test release note';
await outputFile('CHANGELOG.md', 'Initial CHANGELOG');
const changelogFile = 'CHANGELOG.md';
const changelogPath = path.resolve(cwd, changelogFile);
await outputFile(changelogPath, 'Initial CHANGELOG');

await prepare({}, notes, t.context.logger);
await prepare({}, {cwd, nextRelease: {notes}, logger: t.context.logger});

// Verify the content of the CHANGELOG.md
t.is((await readFile('CHANGELOG.md')).toString(), `${notes}\n\nInitial CHANGELOG\n`);
t.deepEqual(t.context.log.args[0], ['Update %s', 'CHANGELOG.md']);
t.is((await readFile(changelogPath)).toString(), `${notes}\n\nInitial CHANGELOG\n`);
t.deepEqual(t.context.log.args[0], ['Update %s', changelogPath]);
});

test.serial('Prepend title in the CHANGELOG.md if there is none', async t => {
test('Prepend title in the CHANGELOG.md if there is none', async t => {
const cwd = tempy.directory();
const notes = 'Test release note';
await outputFile('CHANGELOG.md', 'Initial CHANGELOG');

const changelogTitle = '# My Changelog Title';
await prepare({changelogTitle}, notes, t.context.logger);
const changelogFile = 'CHANGELOG.md';
const changelogPath = path.resolve(cwd, changelogFile);
await outputFile(changelogPath, 'Initial CHANGELOG');

await prepare({changelogTitle}, {cwd, nextRelease: {notes}, logger: t.context.logger});

t.is((await readFile('CHANGELOG.md')).toString(), `${changelogTitle}\n\n${notes}\n\nInitial CHANGELOG\n`);
t.is((await readFile(changelogPath)).toString(), `${changelogTitle}\n\n${notes}\n\nInitial CHANGELOG\n`);
});

test.serial('Keep the title at the top of the CHANGELOG.md', async t => {
test('Keep the title at the top of the CHANGELOG.md', async t => {
const cwd = tempy.directory();
const notes = 'Test release note';
const changelogTitle = '# My Changelog Title';
await outputFile('CHANGELOG.md', `${changelogTitle}\n\nInitial CHANGELOG`);
const changelogFile = 'CHANGELOG.md';
const changelogPath = path.resolve(cwd, changelogFile);
await outputFile(changelogPath, `${changelogTitle}\n\nInitial CHANGELOG`);

await prepare({changelogTitle}, notes, t.context.logger);
await prepare({changelogTitle}, {cwd, nextRelease: {notes}, logger: t.context.logger});

t.is((await readFile('CHANGELOG.md')).toString(), `${changelogTitle}\n\n${notes}\n\nInitial CHANGELOG\n`);
t.is((await readFile(changelogPath)).toString(), `${changelogTitle}\n\n${notes}\n\nInitial CHANGELOG\n`);
});

test.serial('Create new changelog with title if specified', async t => {
const cwd = tempy.directory();
const notes = 'Test release note';
const changelogTitle = '# My Changelog Title';
const changelogFile = 'HISTORY.md';
const changelogPath = path.resolve(cwd, changelogFile);

await prepare({changelogTitle, changelogFile}, notes, t.context.logger);
await prepare({changelogTitle, changelogFile}, {cwd, nextRelease: {notes}, logger: t.context.logger});

t.is((await readFile(changelogFile)).toString(), `${changelogTitle}\n\n${notes}\n`);
t.is((await readFile(changelogPath)).toString(), `${changelogTitle}\n\n${notes}\n`);
});
4 changes: 2 additions & 2 deletions test/verify.test.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import test from 'ava';
import verify from '../lib/verify';

test.serial('Verify String "changelogFile" and "chagngelogTitle"', t => {
test('Verify String "changelogFile" and "chagngelogTitle"', t => {
const changelogFile = 'docs/changelog.txt';
const changelogTitle = '# My title here';
t.notThrows(() => verify({changelogFile, changelogTitle}));
});

test.serial('Verify undefined "changelogFile" and "chagngelogTitle"', t => {
test('Verify undefined "changelogFile" and "chagngelogTitle"', t => {
t.notThrows(() => verify({}));
});

Expand Down

0 comments on commit 3173a68

Please sign in to comment.