feat: log with signale and allow to customize stdin and stdout
This commit is contained in:
@@ -27,7 +27,7 @@ test('Get the highest non-prerelease valid tag', async t => {
|
||||
const result = await getLastRelease({cwd, options: {tagFormat: `v\${version}`}, logger: t.context.logger});
|
||||
|
||||
t.deepEqual(result, {gitHead: commits[0].hash, gitTag: 'v2.0.0', version: '2.0.0'});
|
||||
t.deepEqual(t.context.log.args[0], ['Found git tag %s associated with version %s', 'v2.0.0', '2.0.0']);
|
||||
t.deepEqual(t.context.log.args[0], ['Found git tag v2.0.0 associated with version 2.0.0']);
|
||||
});
|
||||
|
||||
test('Get the highest tag in the history of the current branch', async t => {
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
import test from 'ava';
|
||||
import {spy} from 'sinon';
|
||||
import getLogger from '../lib/get-logger';
|
||||
|
||||
test('Expose "error", "success" and "log" functions', t => {
|
||||
const stdout = spy();
|
||||
const stderr = spy();
|
||||
const logger = getLogger({stdout: {write: stdout}, stderr: {write: stderr}});
|
||||
|
||||
logger.log('test log');
|
||||
logger.success('test success');
|
||||
logger.error('test error');
|
||||
|
||||
t.regex(stdout.args[0][0], /.*test log/);
|
||||
t.regex(stdout.args[1][0], /.*test success/);
|
||||
t.regex(stderr.args[0][0], /.*test error/);
|
||||
});
|
||||
+83
-62
@@ -22,9 +22,13 @@ test.beforeEach(t => {
|
||||
// Stub the logger functions
|
||||
t.context.log = spy();
|
||||
t.context.error = spy();
|
||||
t.context.stdout = spy();
|
||||
t.context.stderr = spy();
|
||||
t.context.logger = {log: t.context.log, error: t.context.error, stdout: t.context.stdout, stderr: t.context.stderr};
|
||||
t.context.success = spy();
|
||||
t.context.logger = {
|
||||
log: t.context.log,
|
||||
error: t.context.error,
|
||||
success: t.context.success,
|
||||
scope: () => t.context.logger,
|
||||
};
|
||||
});
|
||||
|
||||
test('Plugins are called with expected values', async t => {
|
||||
@@ -68,10 +72,10 @@ test('Plugins are called with expected values', async t => {
|
||||
};
|
||||
|
||||
const semanticRelease = requireNoCache('..', {
|
||||
'./lib/logger': t.context.logger,
|
||||
'./lib/get-logger': () => t.context.logger,
|
||||
'env-ci': () => ({isCi: true, branch: 'master', isPr: false}),
|
||||
});
|
||||
t.truthy(await semanticRelease(options, {cwd, extendEnv: false, env}));
|
||||
t.truthy(await semanticRelease(options, {cwd, env: {}, stdout: {write: () => {}}, stderr: {write: () => {}}}));
|
||||
|
||||
t.is(verifyConditions1.callCount, 1);
|
||||
t.deepEqual(verifyConditions1.args[0][0], config);
|
||||
@@ -193,10 +197,10 @@ test('Use custom tag format', async t => {
|
||||
};
|
||||
|
||||
const semanticRelease = requireNoCache('..', {
|
||||
'./lib/logger': t.context.logger,
|
||||
'./lib/get-logger': () => t.context.logger,
|
||||
'env-ci': () => ({isCi: true, branch: 'master', isPr: false}),
|
||||
});
|
||||
t.truthy(await semanticRelease(options, {cwd, env: {}}));
|
||||
t.truthy(await semanticRelease(options, {cwd, env: {}, stdout: {write: () => {}}, stderr: {write: () => {}}}));
|
||||
|
||||
// Verify the tag has been created on the local and remote repo and reference the gitHead
|
||||
t.is(await gitTagHead(nextRelease.gitTag, {cwd}), nextRelease.gitHead);
|
||||
@@ -237,11 +241,11 @@ test('Use new gitHead, and recreate release notes if a prepare plugin create a c
|
||||
};
|
||||
|
||||
const semanticRelease = requireNoCache('..', {
|
||||
'./lib/logger': t.context.logger,
|
||||
'./lib/get-logger': () => t.context.logger,
|
||||
'env-ci': () => ({isCi: true, branch: 'master', isPr: false}),
|
||||
});
|
||||
|
||||
t.truthy(await semanticRelease(options, {cwd, env: {}}));
|
||||
t.truthy(await semanticRelease(options, {cwd, env: {}, stdout: {write: () => {}}, stderr: {write: () => {}}}));
|
||||
|
||||
t.is(generateNotes.callCount, 2);
|
||||
t.deepEqual(generateNotes.args[0][1].nextRelease, nextRelease);
|
||||
@@ -295,11 +299,11 @@ test('Call all "success" plugins even if one errors out', async t => {
|
||||
};
|
||||
|
||||
const semanticRelease = requireNoCache('..', {
|
||||
'./lib/logger': t.context.logger,
|
||||
'./lib/get-logger': () => t.context.logger,
|
||||
'env-ci': () => ({isCi: true, branch: 'master', isPr: false}),
|
||||
});
|
||||
|
||||
await t.throws(semanticRelease(options, {cwd, env: {}}));
|
||||
await t.throws(semanticRelease(options, {cwd, env: {}, stdout: {write: () => {}}, stderr: {write: () => {}}}));
|
||||
|
||||
t.is(success1.callCount, 1);
|
||||
t.deepEqual(success1.args[0][1].releases, [{...release, ...nextRelease, notes, pluginName: '[Function: proxy]'}]);
|
||||
@@ -327,15 +331,17 @@ test('Log all "verifyConditions" errors', async t => {
|
||||
};
|
||||
|
||||
const semanticRelease = requireNoCache('..', {
|
||||
'./lib/logger': t.context.logger,
|
||||
'./lib/get-logger': () => t.context.logger,
|
||||
'env-ci': () => ({isCi: true, branch: 'master', isPr: false}),
|
||||
});
|
||||
const errors = [...(await t.throws(semanticRelease(options, {cwd, env: {}})))];
|
||||
const errors = [
|
||||
...(await t.throws(semanticRelease(options, {cwd, env: {}, stdout: {write: () => {}}, stderr: {write: () => {}}}))),
|
||||
];
|
||||
|
||||
t.deepEqual(errors, [error1, error2, error3]);
|
||||
t.deepEqual(t.context.log.args[t.context.log.args.length - 2], ['%s error 2', 'ERR2']);
|
||||
t.deepEqual(t.context.log.args[t.context.log.args.length - 1], ['%s error 3', 'ERR3']);
|
||||
t.deepEqual(t.context.error.args[t.context.error.args.length - 1], [
|
||||
t.deepEqual(t.context.error.args[t.context.error.args.length - 2], ['ERR2 error 2']);
|
||||
t.deepEqual(t.context.error.args[t.context.error.args.length - 1], ['ERR3 error 3']);
|
||||
t.deepEqual(t.context.error.args[t.context.error.args.length - 3], [
|
||||
'An error occurred while running semantic-release: %O',
|
||||
error1,
|
||||
]);
|
||||
@@ -371,14 +377,16 @@ test('Log all "verifyRelease" errors', async t => {
|
||||
};
|
||||
|
||||
const semanticRelease = requireNoCache('..', {
|
||||
'./lib/logger': t.context.logger,
|
||||
'./lib/get-logger': () => t.context.logger,
|
||||
'env-ci': () => ({isCi: true, branch: 'master', isPr: false}),
|
||||
});
|
||||
const errors = [...(await t.throws(semanticRelease(options, {cwd, env: {}})))];
|
||||
const errors = [
|
||||
...(await t.throws(semanticRelease(options, {cwd, env: {}, stdout: {write: () => {}}, stderr: {write: () => {}}}))),
|
||||
];
|
||||
|
||||
t.deepEqual(errors, [error1, error2]);
|
||||
t.deepEqual(t.context.log.args[t.context.log.args.length - 2], ['%s error 1', 'ERR1']);
|
||||
t.deepEqual(t.context.log.args[t.context.log.args.length - 1], ['%s error 2', 'ERR2']);
|
||||
t.deepEqual(t.context.error.args[t.context.error.args.length - 2], ['ERR1 error 1']);
|
||||
t.deepEqual(t.context.error.args[t.context.error.args.length - 1], ['ERR2 error 2']);
|
||||
t.is(fail.callCount, 1);
|
||||
t.deepEqual(fail.args[0][0], config);
|
||||
t.deepEqual(fail.args[0][1].errors, [error1, error2]);
|
||||
@@ -419,10 +427,10 @@ test('Dry-run skips publish and success', async t => {
|
||||
};
|
||||
|
||||
const semanticRelease = requireNoCache('..', {
|
||||
'./lib/logger': t.context.logger,
|
||||
'./lib/get-logger': () => t.context.logger,
|
||||
'env-ci': () => ({isCi: true, branch: 'master', isPr: false}),
|
||||
});
|
||||
t.truthy(await semanticRelease(options, {cwd, env: {}}));
|
||||
t.truthy(await semanticRelease(options, {cwd, env: {}, stdout: {write: () => {}}, stderr: {write: () => {}}}));
|
||||
|
||||
t.not(t.context.log.args[0][0], 'This run was not triggered in a known CI environment, running in dry-run mode.');
|
||||
t.is(verifyConditions.callCount, 1);
|
||||
@@ -457,14 +465,16 @@ test('Dry-run skips fail', async t => {
|
||||
};
|
||||
|
||||
const semanticRelease = requireNoCache('..', {
|
||||
'./lib/logger': t.context.logger,
|
||||
'./lib/get-logger': () => t.context.logger,
|
||||
'env-ci': () => ({isCi: true, branch: 'master', isPr: false}),
|
||||
});
|
||||
const errors = [...(await t.throws(semanticRelease(options, {cwd, env: {}})))];
|
||||
const errors = [
|
||||
...(await t.throws(semanticRelease(options, {cwd, env: {}, stdout: {write: () => {}}, stderr: {write: () => {}}}))),
|
||||
];
|
||||
|
||||
t.deepEqual(errors, [error1, error2]);
|
||||
t.deepEqual(t.context.log.args[t.context.log.args.length - 2], ['%s error 1', 'ERR1']);
|
||||
t.deepEqual(t.context.log.args[t.context.log.args.length - 1], ['%s error 2', 'ERR2']);
|
||||
t.deepEqual(t.context.error.args[t.context.error.args.length - 2], ['ERR1 error 1']);
|
||||
t.deepEqual(t.context.error.args[t.context.error.args.length - 1], ['ERR2 error 2']);
|
||||
t.is(fail.callCount, 0);
|
||||
});
|
||||
|
||||
@@ -504,10 +514,10 @@ test('Force a dry-run if not on a CI and "noCi" is not explicitly set', async t
|
||||
};
|
||||
|
||||
const semanticRelease = requireNoCache('..', {
|
||||
'./lib/logger': t.context.logger,
|
||||
'./lib/get-logger': () => t.context.logger,
|
||||
'env-ci': () => ({isCi: false, branch: 'master'}),
|
||||
});
|
||||
t.truthy(await semanticRelease(options, {cwd, env: {}}));
|
||||
t.truthy(await semanticRelease(options, {cwd, env: {}, stdout: {write: () => {}}, stderr: {write: () => {}}}));
|
||||
|
||||
t.is(t.context.log.args[1][0], 'This run was not triggered in a known CI environment, running in dry-run mode.');
|
||||
t.is(verifyConditions.callCount, 1);
|
||||
@@ -518,7 +528,7 @@ test('Force a dry-run if not on a CI and "noCi" is not explicitly set', async t
|
||||
t.is(success.callCount, 0);
|
||||
});
|
||||
|
||||
test.serial('Dry-run does not print changelog if "generateNotes" return "undefined"', async t => {
|
||||
test('Dry-run does not print changelog if "generateNotes" return "undefined"', async t => {
|
||||
// Create a git repository, set the current working directory at the root of the repo
|
||||
const {cwd, repositoryUrl} = await gitRepo(true);
|
||||
// Add commits to the master branch
|
||||
@@ -547,12 +557,12 @@ test.serial('Dry-run does not print changelog if "generateNotes" return "undefin
|
||||
};
|
||||
|
||||
const semanticRelease = requireNoCache('..', {
|
||||
'./lib/logger': t.context.logger,
|
||||
'./lib/get-logger': () => t.context.logger,
|
||||
'env-ci': () => ({isCi: true, branch: 'master', isPr: false}),
|
||||
});
|
||||
t.truthy(await semanticRelease(options, {cwd, env: {}}));
|
||||
t.truthy(await semanticRelease(options, {cwd, env: {}, stdout: {write: () => {}}, stderr: {write: () => {}}}));
|
||||
|
||||
t.deepEqual(t.context.log.args[t.context.log.args.length - 1], ['Release note for version %s:\n', '2.0.0']);
|
||||
t.deepEqual(t.context.log.args[t.context.log.args.length - 1], ['Release note for version 2.0.0:']);
|
||||
});
|
||||
|
||||
test('Allow local releases with "noCi" option', async t => {
|
||||
@@ -591,10 +601,10 @@ test('Allow local releases with "noCi" option', async t => {
|
||||
};
|
||||
|
||||
const semanticRelease = requireNoCache('..', {
|
||||
'./lib/logger': t.context.logger,
|
||||
'./lib/get-logger': () => t.context.logger,
|
||||
'env-ci': () => ({isCi: false, branch: 'master', isPr: true}),
|
||||
});
|
||||
t.truthy(await semanticRelease(options, {cwd, env: {}}));
|
||||
t.truthy(await semanticRelease(options, {cwd, env: {}, stdout: {write: () => {}}, stderr: {write: () => {}}}));
|
||||
|
||||
t.not(t.context.log.args[0][0], 'This run was not triggered in a known CI environment, running in dry-run mode.');
|
||||
t.not(
|
||||
@@ -643,10 +653,10 @@ test('Accept "undefined" value returned by the "generateNotes" plugins', async t
|
||||
};
|
||||
|
||||
const semanticRelease = requireNoCache('..', {
|
||||
'./lib/logger': t.context.logger,
|
||||
'./lib/get-logger': () => t.context.logger,
|
||||
'env-ci': () => ({isCi: true, branch: 'master', isPr: false}),
|
||||
});
|
||||
t.truthy(await semanticRelease(options, {cwd, env: {}}));
|
||||
t.truthy(await semanticRelease(options, {cwd, env: {}, stdout: {write: () => {}}, stderr: {write: () => {}}}));
|
||||
|
||||
t.is(analyzeCommits.callCount, 1);
|
||||
t.deepEqual(analyzeCommits.args[0][1].lastRelease, lastRelease);
|
||||
@@ -670,11 +680,13 @@ test('Returns falsy value if triggered by a PR', async t => {
|
||||
const {cwd, repositoryUrl} = await gitRepo(true);
|
||||
|
||||
const semanticRelease = requireNoCache('..', {
|
||||
'./lib/logger': t.context.logger,
|
||||
'./lib/get-logger': () => t.context.logger,
|
||||
'env-ci': () => ({isCi: true, branch: 'master', isPr: true}),
|
||||
});
|
||||
|
||||
t.falsy(await semanticRelease({cwd, repositoryUrl}, {cwd, env: {}}));
|
||||
t.falsy(
|
||||
await semanticRelease({cwd, repositoryUrl}, {cwd, env: {}, stdout: {write: () => {}}, stderr: {write: () => {}}})
|
||||
);
|
||||
t.is(
|
||||
t.context.log.args[t.context.log.args.length - 1][0],
|
||||
"This run was triggered by a pull request and therefore a new version won't be published."
|
||||
@@ -694,18 +706,22 @@ test('Returns falsy value if triggered on an outdated clone', async t => {
|
||||
await gitPush(repositoryUrl, 'master', {cwd});
|
||||
|
||||
const semanticRelease = requireNoCache('..', {
|
||||
'./lib/logger': t.context.logger,
|
||||
'./lib/get-logger': () => t.context.logger,
|
||||
'env-ci': () => ({isCi: true, branch: 'master', isPr: false}),
|
||||
});
|
||||
|
||||
t.falsy(await semanticRelease({repositoryUrl}, {cwd: repoDir, env: {}}));
|
||||
t.falsy(
|
||||
await semanticRelease(
|
||||
{repositoryUrl},
|
||||
{cwd: repoDir, env: {}, stdout: {write: () => {}}, stderr: {write: () => {}}}
|
||||
)
|
||||
);
|
||||
t.deepEqual(t.context.log.args[t.context.log.args.length - 1], [
|
||||
"The local branch %s is behind the remote one, therefore a new version won't be published.",
|
||||
'master',
|
||||
"The local branch master is behind the remote one, therefore a new version won't be published.",
|
||||
]);
|
||||
});
|
||||
|
||||
test('Returns falsy value if not running from the configured branch', async t => {
|
||||
test('Returns false if not running from the configured branch', async t => {
|
||||
// Create a git repository, set the current working directory at the root of the repo
|
||||
const {cwd, repositoryUrl} = await gitRepo(true);
|
||||
const options = {
|
||||
@@ -722,11 +738,11 @@ test('Returns falsy value if not running from the configured branch', async t =>
|
||||
};
|
||||
|
||||
const semanticRelease = requireNoCache('..', {
|
||||
'./lib/logger': t.context.logger,
|
||||
'./lib/get-logger': () => t.context.logger,
|
||||
'env-ci': () => ({isCi: true, branch: 'other-branch', isPr: false}),
|
||||
});
|
||||
|
||||
t.falsy(await semanticRelease(options, {cwd, env: {}}));
|
||||
t.falsy(await semanticRelease(options, {cwd, env: {}, stdout: {write: () => {}}, stderr: {write: () => {}}}));
|
||||
t.is(
|
||||
t.context.log.args[1][0],
|
||||
'This test run was triggered on the branch other-branch, while semantic-release is configured to only publish from master, therefore a new version won’t be published.'
|
||||
@@ -759,11 +775,11 @@ test('Returns falsy value if there is no relevant changes', async t => {
|
||||
};
|
||||
|
||||
const semanticRelease = requireNoCache('..', {
|
||||
'./lib/logger': t.context.logger,
|
||||
'./lib/get-logger': () => t.context.logger,
|
||||
'env-ci': () => ({isCi: true, branch: 'master', isPr: false}),
|
||||
});
|
||||
|
||||
t.falsy(await semanticRelease(options, {cwd, env: {}}));
|
||||
t.falsy(await semanticRelease(options, {cwd, env: {}, stdout: {write: () => {}}, stderr: {write: () => {}}}));
|
||||
t.is(analyzeCommits.callCount, 1);
|
||||
t.is(verifyRelease.callCount, 0);
|
||||
t.is(generateNotes.callCount, 0);
|
||||
@@ -807,10 +823,10 @@ test('Exclude commits with [skip release] or [release skip] from analysis', asyn
|
||||
};
|
||||
|
||||
const semanticRelease = requireNoCache('..', {
|
||||
'./lib/logger': t.context.logger,
|
||||
'./lib/get-logger': () => t.context.logger,
|
||||
'env-ci': () => ({isCi: true, branch: 'master', isPr: false}),
|
||||
});
|
||||
await semanticRelease(options, {cwd, env: {}});
|
||||
await semanticRelease(options, {cwd, env: {}, stdout: {write: () => {}}, stderr: {write: () => {}}});
|
||||
|
||||
t.is(analyzeCommits.callCount, 1);
|
||||
t.is(analyzeCommits.args[0][1].commits.length, 2);
|
||||
@@ -830,15 +846,15 @@ test('Log both plugins errors and errors thrown by "fail" plugin', async t => {
|
||||
fail: [stub().rejects(failError1), stub().rejects(failError2)],
|
||||
};
|
||||
const semanticRelease = requireNoCache('..', {
|
||||
'./lib/logger': t.context.logger,
|
||||
'./lib/get-logger': () => t.context.logger,
|
||||
'env-ci': () => ({isCi: true, branch: 'master', isPr: false}),
|
||||
});
|
||||
|
||||
await t.throws(semanticRelease(options, {cwd, env: {}}));
|
||||
await t.throws(semanticRelease(options, {cwd, env: {}, stdout: {write: () => {}}, stderr: {write: () => {}}}));
|
||||
|
||||
t.is(t.context.error.args[t.context.error.args.length - 2][1], failError1);
|
||||
t.is(t.context.error.args[t.context.error.args.length - 1][1], failError2);
|
||||
t.deepEqual(t.context.log.args[t.context.log.args.length - 1], ['%s Plugin error', 'ERR']);
|
||||
t.is(t.context.error.args[t.context.error.args.length - 1][0], 'ERR Plugin error');
|
||||
t.is(t.context.error.args[t.context.error.args.length - 3][1], failError1);
|
||||
t.is(t.context.error.args[t.context.error.args.length - 2][1], failError2);
|
||||
});
|
||||
|
||||
test('Call "fail" only if a plugin returns a SemanticReleaseError', async t => {
|
||||
@@ -853,11 +869,11 @@ test('Call "fail" only if a plugin returns a SemanticReleaseError', async t => {
|
||||
fail,
|
||||
};
|
||||
const semanticRelease = requireNoCache('..', {
|
||||
'./lib/logger': t.context.logger,
|
||||
'./lib/get-logger': () => t.context.logger,
|
||||
'env-ci': () => ({isCi: true, branch: 'master', isPr: false}),
|
||||
});
|
||||
|
||||
await t.throws(semanticRelease(options, {cwd, env: {}}));
|
||||
await t.throws(semanticRelease(options, {cwd, env: {}, stdout: {write: () => {}}, stderr: {write: () => {}}}));
|
||||
|
||||
t.true(fail.notCalled);
|
||||
t.is(t.context.error.args[t.context.error.args.length - 1][1], pluginError);
|
||||
@@ -868,10 +884,12 @@ test('Throw SemanticReleaseError if repositoryUrl is not set and cannot be found
|
||||
const {cwd} = await gitRepo();
|
||||
|
||||
const semanticRelease = requireNoCache('..', {
|
||||
'./lib/logger': t.context.logger,
|
||||
'./lib/get-logger': () => t.context.logger,
|
||||
'env-ci': () => ({isCi: true, branch: 'master', isPr: false}),
|
||||
});
|
||||
const errors = [...(await t.throws(semanticRelease({}, {cwd, env: {}})))];
|
||||
const errors = [
|
||||
...(await t.throws(semanticRelease({}, {cwd, env: {}, stdout: {write: () => {}}, stderr: {write: () => {}}}))),
|
||||
];
|
||||
|
||||
// Verify error code and type
|
||||
t.is(errors[0].code, 'ENOREPOURL');
|
||||
@@ -902,10 +920,13 @@ test('Throw an Error if plugin returns an unexpected value', async t => {
|
||||
};
|
||||
|
||||
const semanticRelease = requireNoCache('..', {
|
||||
'./lib/logger': t.context.logger,
|
||||
'./lib/get-logger': () => t.context.logger,
|
||||
'env-ci': () => ({isCi: true, branch: 'master', isPr: false}),
|
||||
});
|
||||
const error = await t.throws(semanticRelease(options, {cwd, env: {}}), Error);
|
||||
const error = await t.throws(
|
||||
semanticRelease(options, {cwd, env: {}, stdout: {write: () => {}}, stderr: {write: () => {}}}),
|
||||
Error
|
||||
);
|
||||
t.regex(error.details, /string/);
|
||||
});
|
||||
|
||||
@@ -935,10 +956,10 @@ test('Get all commits including the ones not in the shallow clone', async t => {
|
||||
};
|
||||
|
||||
const semanticRelease = requireNoCache('..', {
|
||||
'./lib/logger': t.context.logger,
|
||||
'./lib/get-logger': () => t.context.logger,
|
||||
'env-ci': () => ({isCi: true, branch: 'master', isPr: false}),
|
||||
});
|
||||
t.truthy(await semanticRelease(options, {cwd, env: {}}));
|
||||
t.truthy(await semanticRelease(options, {cwd, env: {}, stdout: {write: () => {}}, stderr: {write: () => {}}}));
|
||||
|
||||
t.is(analyzeCommits.args[0][1].commits.length, 3);
|
||||
});
|
||||
|
||||
@@ -465,6 +465,10 @@ test('Run via JS API', async t => {
|
||||
version: '0.0.0-dev',
|
||||
repository: {url: repositoryUrl},
|
||||
publishConfig: {registry: npmRegistry.url},
|
||||
release: {
|
||||
fail: false,
|
||||
success: false,
|
||||
},
|
||||
});
|
||||
|
||||
/* Initial release */
|
||||
@@ -486,7 +490,7 @@ test('Run via JS API', async t => {
|
||||
t.log('Commit a feature');
|
||||
await gitCommits(['feat: Initial commit'], {cwd});
|
||||
t.log('$ Call semantic-release via API');
|
||||
await semanticRelease({fail: false, success: false}, {cwd, env});
|
||||
await semanticRelease(undefined, {cwd, env, stdout: {write: () => {}}, stderr: {write: () => {}}});
|
||||
|
||||
// Verify package.json and has been updated
|
||||
t.is((await readJson(path.resolve(cwd, 'package.json'))).version, version);
|
||||
@@ -550,9 +554,9 @@ test('Log errors inheriting SemanticReleaseError and exit with 1', async t => {
|
||||
t.log('Commit a feature');
|
||||
await gitCommits(['feat: Initial commit'], {cwd});
|
||||
t.log('$ semantic-release');
|
||||
const {stdout, code} = await execa(cli, [], {env, cwd, reject: false});
|
||||
const {stderr, code} = await execa(cli, [], {env, cwd, reject: false});
|
||||
// Verify the type and message are logged
|
||||
t.regex(stdout, /EINHERITED Inherited error/);
|
||||
t.regex(stderr, /EINHERITED Inherited error/);
|
||||
t.is(code, 1);
|
||||
});
|
||||
|
||||
@@ -568,13 +572,13 @@ test('Exit with 1 if missing permission to push to the remote repository', async
|
||||
await gitCommits(['feat: Initial commit'], {cwd});
|
||||
await gitPush('origin', 'master', {cwd});
|
||||
t.log('$ semantic-release');
|
||||
const {stdout, code} = await execa(
|
||||
const {stderr, code} = await execa(
|
||||
cli,
|
||||
['--repository-url', 'http://user:wrong_pass@localhost:2080/git/unauthorized.git'],
|
||||
{env: {...env, GH_TOKEN: 'user:wrong_pass'}, cwd, reject: false}
|
||||
);
|
||||
// Verify the type and message are logged
|
||||
t.regex(stdout, /EGITNOPERMISSION/);
|
||||
t.regex(stderr, /EGITNOPERMISSION/);
|
||||
t.is(code, 1);
|
||||
});
|
||||
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
import test from 'ava';
|
||||
import {stub} from 'sinon';
|
||||
import logger from '../lib/logger';
|
||||
|
||||
test.beforeEach(t => {
|
||||
t.context.log = stub(console, 'log');
|
||||
t.context.error = stub(console, 'error');
|
||||
});
|
||||
|
||||
test.afterEach.always(t => {
|
||||
t.context.log.restore();
|
||||
t.context.error.restore();
|
||||
});
|
||||
|
||||
test.serial('Basic log', t => {
|
||||
logger.log('test log');
|
||||
logger.error('test error');
|
||||
|
||||
t.regex(t.context.log.args[0][0], /.*test log/);
|
||||
t.regex(t.context.error.args[0][0], /.*test error/);
|
||||
});
|
||||
|
||||
test.serial('Log object', t => {
|
||||
const obj = {a: 1, b: '2'};
|
||||
logger.log(obj);
|
||||
logger.error(obj);
|
||||
|
||||
t.is(t.context.log.args[0][1], obj);
|
||||
t.is(t.context.error.args[0][1], obj);
|
||||
});
|
||||
|
||||
test.serial('Log with string formatting', t => {
|
||||
logger.log('test log %s', 'log value');
|
||||
logger.error('test error %s', 'error value');
|
||||
|
||||
t.regex(t.context.log.args[0][0], /.*test log/);
|
||||
t.regex(t.context.error.args[0][0], /.*test error/);
|
||||
t.is(t.context.log.args[0][1], 'log value');
|
||||
t.is(t.context.error.args[0][1], 'error value');
|
||||
});
|
||||
|
||||
test.serial('Log with error stacktrace and properties', t => {
|
||||
const error = new Error('error message');
|
||||
logger.error(error);
|
||||
const otherError = new Error('other error message');
|
||||
logger.error('test error %O', otherError);
|
||||
|
||||
t.is(t.context.error.args[0][1], error);
|
||||
t.regex(t.context.error.args[1][0], /.*test error/);
|
||||
t.is(t.context.error.args[1][1], otherError);
|
||||
});
|
||||
@@ -8,7 +8,15 @@ const cwd = process.cwd();
|
||||
test.beforeEach(t => {
|
||||
// Stub the logger functions
|
||||
t.context.log = stub();
|
||||
t.context.logger = {log: t.context.log};
|
||||
t.context.error = stub();
|
||||
t.context.success = stub();
|
||||
t.context.stderr = {write: stub()};
|
||||
t.context.logger = {
|
||||
log: t.context.log,
|
||||
error: t.context.error,
|
||||
success: t.context.success,
|
||||
scope: () => t.context.logger,
|
||||
};
|
||||
});
|
||||
|
||||
test('Normalize and load plugin from string', t => {
|
||||
@@ -21,7 +29,7 @@ test('Normalize and load plugin from string', t => {
|
||||
|
||||
t.is(plugin.pluginName, './test/fixtures/plugin-noop');
|
||||
t.is(typeof plugin, 'function');
|
||||
t.deepEqual(t.context.log.args[0], ['Load plugin "%s" from %s', 'verifyConditions', './test/fixtures/plugin-noop']);
|
||||
t.deepEqual(t.context.success.args[0], ['Loaded plugin "verifyConditions" from "./test/fixtures/plugin-noop"']);
|
||||
});
|
||||
|
||||
test('Normalize and load plugin from object', t => {
|
||||
@@ -34,7 +42,7 @@ test('Normalize and load plugin from object', t => {
|
||||
|
||||
t.is(plugin.pluginName, './test/fixtures/plugin-noop');
|
||||
t.is(typeof plugin, 'function');
|
||||
t.deepEqual(t.context.log.args[0], ['Load plugin "%s" from %s', 'publish', './test/fixtures/plugin-noop']);
|
||||
t.deepEqual(t.context.success.args[0], ['Loaded plugin "publish" from "./test/fixtures/plugin-noop"']);
|
||||
});
|
||||
|
||||
test('Normalize and load plugin from a base file path', t => {
|
||||
@@ -44,11 +52,8 @@ test('Normalize and load plugin from a base file path', t => {
|
||||
|
||||
t.is(plugin.pluginName, './plugin-noop');
|
||||
t.is(typeof plugin, 'function');
|
||||
t.deepEqual(t.context.log.args[0], [
|
||||
'Load plugin "%s" from %s in shareable config %s',
|
||||
'verifyConditions',
|
||||
'./plugin-noop',
|
||||
'./test/fixtures',
|
||||
t.deepEqual(t.context.success.args[0], [
|
||||
'Loaded plugin "verifyConditions" from "./plugin-noop" in shareable config "./test/fixtures"',
|
||||
]);
|
||||
});
|
||||
|
||||
@@ -90,12 +95,17 @@ test('Normalize and load plugin that retuns multiple functions', t => {
|
||||
);
|
||||
|
||||
t.is(typeof plugin, 'function');
|
||||
t.deepEqual(t.context.log.args[0], ['Load plugin "%s" from %s', 'verifyConditions', './test/fixtures/multi-plugin']);
|
||||
t.deepEqual(t.context.success.args[0], ['Loaded plugin "verifyConditions" from "./test/fixtures/multi-plugin"']);
|
||||
});
|
||||
|
||||
test('Wrap "analyzeCommits" plugin in a function that validate the output of the plugin', async t => {
|
||||
const analyzeCommits = stub().resolves(2);
|
||||
const plugin = normalize({cwd, options: {}, logger: t.context.logger}, 'analyzeCommits', analyzeCommits, {});
|
||||
const plugin = normalize(
|
||||
{cwd, options: {}, stderr: t.context.stderr, logger: t.context.logger},
|
||||
'analyzeCommits',
|
||||
analyzeCommits,
|
||||
{}
|
||||
);
|
||||
|
||||
const error = await t.throws(plugin());
|
||||
|
||||
@@ -108,7 +118,12 @@ test('Wrap "analyzeCommits" plugin in a function that validate the output of the
|
||||
|
||||
test('Wrap "generateNotes" plugin in a function that validate the output of the plugin', async t => {
|
||||
const generateNotes = stub().resolves(2);
|
||||
const plugin = normalize({cwd, options: {}, logger: t.context.logger}, 'generateNotes', generateNotes, {});
|
||||
const plugin = normalize(
|
||||
{cwd, options: {}, stderr: t.context.stderr, logger: t.context.logger},
|
||||
'generateNotes',
|
||||
generateNotes,
|
||||
{}
|
||||
);
|
||||
|
||||
const error = await t.throws(plugin());
|
||||
|
||||
@@ -120,11 +135,15 @@ test('Wrap "generateNotes" plugin in a function that validate the output of the
|
||||
});
|
||||
|
||||
test('Wrap "publish" plugin in a function that validate the output of the plugin', async t => {
|
||||
const plugin = normalize({cwd, options: {}, logger: t.context.logger}, 'publish', './plugin-identity', {
|
||||
'./plugin-identity': './test/fixtures',
|
||||
});
|
||||
const publish = stub().resolves(2);
|
||||
const plugin = normalize(
|
||||
{cwd, options: {}, stderr: t.context.stderr, logger: t.context.logger},
|
||||
'publish',
|
||||
publish,
|
||||
{}
|
||||
);
|
||||
|
||||
const error = await t.throws(plugin(2));
|
||||
const error = await t.throws(plugin());
|
||||
|
||||
t.is(error.code, 'EPUBLISHOUTPUT');
|
||||
t.is(error.name, 'SemanticReleaseError');
|
||||
@@ -138,9 +157,11 @@ test('Plugin is called with "pluginConfig" (omitting "path", adding global confi
|
||||
const pluginConf = {path: pluginFunction, conf: 'confValue'};
|
||||
const options = {global: 'globalValue'};
|
||||
const plugin = normalize({cwd, options, logger: t.context.logger}, '', pluginConf, {});
|
||||
await plugin('param');
|
||||
await plugin({param: 'param'});
|
||||
|
||||
t.true(pluginFunction.calledWith({conf: 'confValue', global: 'globalValue'}, 'param'));
|
||||
t.true(
|
||||
pluginFunction.calledWith({conf: 'confValue', global: 'globalValue'}, {param: 'param', logger: t.context.logger})
|
||||
);
|
||||
});
|
||||
|
||||
test('Prevent plugins to modify "pluginConfig"', async t => {
|
||||
|
||||
@@ -11,7 +11,8 @@ const cwd = process.cwd();
|
||||
test.beforeEach(t => {
|
||||
// Stub the logger functions
|
||||
t.context.log = stub();
|
||||
t.context.logger = {log: t.context.log};
|
||||
t.context.success = stub();
|
||||
t.context.logger = {log: t.context.log, success: t.context.success, scope: () => t.context.logger};
|
||||
});
|
||||
|
||||
test('Export default plugins', t => {
|
||||
|
||||
Reference in New Issue
Block a user