Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion source/cli-implementation.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const meow = require('meow');
const updateNotifier = require('update-notifier');
const hasYarn = require('has-yarn');
const config = require('./config');
const git = require('./git');
const {isPackageNameAvailable} = require('./npm/util');
const version = require('./version');
const util = require('./util');
Expand Down Expand Up @@ -127,11 +128,13 @@ updateNotifier({pkg: cli.pkg}).notify();
// Use current (latest) version when 'releaseDraftOnly', otherwise use the first argument.
const version = flags.releaseDraftOnly ? pkg.version : (cli.input.length > 0 ? cli.input[0] : false);

const branch = flags.branch || await git.defaultBranch();
const options = await ui({
...flags,
availability,
version,
runPublish
runPublish,
branch
}, pkg);

if (!options.confirm) {
Expand Down
32 changes: 29 additions & 3 deletions source/git-util.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,9 @@ exports.currentBranch = async () => {
};

exports.verifyCurrentBranchIsReleaseBranch = async releaseBranch => {
const allowedBranches = releaseBranch ? [releaseBranch] : ['main', 'master'];
const currentBranch = await exports.currentBranch();
if (!allowedBranches.includes(currentBranch)) {
throw new Error(`Not on ${allowedBranches.map(branch => `\`${branch}\``).join('/')} branch. Use --any-branch to publish anyway, or set a different release branch using --branch.`);
if (currentBranch !== releaseBranch) {
throw new Error(`Not on \`${releaseBranch}\` branch. Use --any-branch to publish anyway, or set a different release branch using --branch.`);
}
};

Expand Down Expand Up @@ -152,6 +151,33 @@ exports.tagExistsOnRemote = async tagName => {
}
};

async function hasLocalBranch(branch) {
try {
await execa('git', [
'show-ref',
'--verify',
'--quiet',
`refs/heads/${branch}`
]);
return true;
} catch {
return false;
}
}

exports.defaultBranch = async () => {
for (const branch of ['main', 'master', 'gh-pages']) {
// eslint-disable-next-line no-await-in-loop
if (await hasLocalBranch(branch)) {
return branch;
}
}

throw new Error(
'Could not infer the default Git branch. Please specify one with the --branch flag or with a np config.'
);
};

exports.verifyTagDoesNotExistOnRemote = async tagName => {
if (await exports.tagExistsOnRemote(tagName)) {
throw new Error(`Git tag \`${tagName}\` already exists.`);
Expand Down
8 changes: 4 additions & 4 deletions source/ui.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const {prereleaseTags, checkIgnoreStrategy, getRegistryUrl, isExternalRegistry}
const version = require('./version');
const prettyVersionDiff = require('./pretty-version-diff');

const printCommitLog = async (repoUrl, registryUrl, fromLatestTag) => {
const printCommitLog = async (repoUrl, registryUrl, fromLatestTag, releaseBranch) => {
const revision = fromLatestTag ? await git.latestTagOrFirstCommit() : await git.previousTagOrFirstCommit();
if (!revision) {
throw new Error('The package has not been published yet.');
Expand All @@ -28,7 +28,7 @@ const printCommitLog = async (repoUrl, registryUrl, fromLatestTag) => {
}

let hasUnreleasedCommits = false;
let commitRangeText = `${revision}...master`;
let commitRangeText = `${revision}...${releaseBranch}`;

let commits = log.split('\n')
.map(commit => {
Expand Down Expand Up @@ -64,7 +64,6 @@ const printCommitLog = async (repoUrl, registryUrl, fromLatestTag) => {
).join('\n') + `\n\n${repoUrl}/compare/${revision}...${nextTag}`;

const commitRange = util.linkifyCommitRange(repoUrl, commitRangeText);

console.log(`${chalk.bold('Commits:')}\n${history}\n\n${chalk.bold('Commit Range:')}\n${commitRange}\n\n${chalk.bold('Registry:')}\n${registryUrl}\n`);

return {
Expand Down Expand Up @@ -102,6 +101,7 @@ module.exports = async (options, pkg) => {
const repoUrl = pkg.repository && githubUrlFromGit(pkg.repository.url, {extraBaseUrls});
const pkgManager = options.yarn ? 'yarn' : 'npm';
const registryUrl = await getRegistryUrl(pkgManager, pkg);
const releaseBranch = options.branch;

if (options.runPublish) {
checkIgnoreStrategy(pkg);
Expand Down Expand Up @@ -204,7 +204,7 @@ module.exports = async (options, pkg) => {
];

const useLatestTag = !options.releaseDraftOnly;
const {hasCommits, hasUnreleasedCommits, releaseNotes} = await printCommitLog(repoUrl, registryUrl, useLatestTag);
const {hasCommits, hasUnreleasedCommits, releaseNotes} = await printCommitLog(repoUrl, registryUrl, useLatestTag, releaseBranch);

if (hasUnreleasedCommits && options.releaseDraftOnly) {
const answers = await inquirer.prompt([{
Expand Down
12 changes: 6 additions & 6 deletions test/git-tasks.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,16 @@ test.beforeEach(() => {
execaStub.resetStub();
});

test.serial('should fail when release branch is not specified, current branch is not main/master and publishing from any branch not permitted', async t => {
test.serial('should fail when release branch is not specified, current branch is not the release branch, and publishing from any branch not permitted', async t => {
execaStub.createStub([
{
command: 'git symbolic-ref --short HEAD',
exitCode: 0,
stdout: 'feature'
}
]);
await t.throwsAsync(run(testedModule({})),
{message: 'Not on `main`/`master` branch. Use --any-branch to publish anyway, or set a different release branch using --branch.'});
await t.throwsAsync(run(testedModule({branch: 'master'})),
{message: 'Not on `master` branch. Use --any-branch to publish anyway, or set a different release branch using --branch.'});
t.true(SilentRenderer.tasks.some(task => task.title === 'Check current branch' && task.hasFailed()));
});

Expand Down Expand Up @@ -85,7 +85,7 @@ test.serial('should fail when local working tree modified', async t => {
stdout: 'M source/git-tasks.js'
}
]);
await t.throwsAsync(run(testedModule({})), {message: 'Unclean working tree. Commit or stash changes first.'});
await t.throwsAsync(run(testedModule({branch: 'master'})), {message: 'Unclean working tree. Commit or stash changes first.'});
t.true(SilentRenderer.tasks.some(task => task.title === 'Check local working tree' && task.hasFailed()));
});

Expand All @@ -107,7 +107,7 @@ test.serial('should fail when remote history differs', async t => {
stdout: '1'
}
]);
await t.throwsAsync(run(testedModule({})), {message: 'Remote history differs. Please pull changes.'});
await t.throwsAsync(run(testedModule({branch: 'master'})), {message: 'Remote history differs. Please pull changes.'});
t.true(SilentRenderer.tasks.some(task => task.title === 'Check remote history' && task.hasFailed()));
});

Expand All @@ -129,5 +129,5 @@ test.serial('checks should pass when publishing from master, working tree is cle
stdout: ''
}
]);
await t.notThrowsAsync(run(testedModule({})));
await t.notThrowsAsync(run(testedModule({branch: 'master'})));
});