diff --git a/source/cli-implementation.js b/source/cli-implementation.js index 9177095e..2e541542 100755 --- a/source/cli-implementation.js +++ b/source/cli-implementation.js @@ -98,7 +98,7 @@ const cli = meow(` updateNotifier({pkg: cli.pkg}).notify(); (async () => { - const pkg = util.readPkg(); + const {pkg, pkgPath} = util.readPkg(); const defaultFlags = { cleanup: true, @@ -139,7 +139,7 @@ updateNotifier({pkg: cli.pkg}).notify(); version, runPublish, branch - }, pkg); + }, {pkg, pkgPath}); if (!options.confirm) { process.exit(0); diff --git a/source/git-util.js b/source/git-util.js index f9f28d1f..693c88dd 100644 --- a/source/git-util.js +++ b/source/git-util.js @@ -1,4 +1,5 @@ 'use strict'; +const path = require('path'); const execa = require('execa'); const escapeStringRegexp = require('escape-string-regexp'); const ignoreWalker = require('ignore-walk'); @@ -10,6 +11,11 @@ exports.latestTag = async () => { return stdout; }; +exports.root = async () => { + const {stdout} = await execa('git', ['rev-parse', '--show-toplevel']); + return stdout; +}; + exports.newFilesSinceLastRelease = async () => { try { const {stdout} = await execa('git', ['diff', '--name-only', '--diff-filter=A', await this.latestTag(), 'HEAD']); @@ -28,6 +34,12 @@ exports.newFilesSinceLastRelease = async () => { } }; +exports.readFileFromLastRelease = async file => { + const filePathFromRoot = path.relative(await exports.root(), file); + const {stdout: oldFile} = await execa('git', ['show', `${await this.latestTag()}:${filePathFromRoot}`]); + return oldFile; +}; + const firstCommit = async () => { const {stdout} = await execa('git', ['rev-list', '--max-parents=0', 'HEAD']); return stdout; diff --git a/source/index.js b/source/index.js index b20dec43..7d25820c 100644 --- a/source/index.js +++ b/source/index.js @@ -47,7 +47,7 @@ module.exports = async (input = 'patch', options) => { options.cleanup = false; } - const pkg = util.readPkg(options.contents); + const {pkg} = util.readPkg(options.contents); const runTests = options.tests && !options.yolo; const runCleanup = options.cleanup && !options.yolo; const pkgManager = options.yarn === true ? 'yarn' : 'npm'; @@ -75,7 +75,7 @@ module.exports = async (input = 'patch', options) => { const versionInLatestTag = latestTag.slice(tagVersionPrefix.length); try { - if (versionInLatestTag === util.readPkg().version && + if (versionInLatestTag === util.readPkg().pkg.version && versionInLatestTag !== pkg.version) { // Verify that the package's version has been bumped before deleting the last tag and commit. await git.deleteTag(latestTag); await git.removeLastCommit(); diff --git a/source/ui.js b/source/ui.js index b1d0a9c1..247cbd39 100644 --- a/source/ui.js +++ b/source/ui.js @@ -79,19 +79,31 @@ const printCommitLog = async (repoUrl, registryUrl, fromLatestTag, releaseBranch }; }; -const checkNewFiles = async pkg => { +const checkNewFilesAndDependencies = async (pkg, pkgPath) => { const newFiles = await util.getNewFiles(pkg); - if ((!newFiles.unpublished || newFiles.unpublished.length === 0) && (!newFiles.firstTime || newFiles.firstTime.length === 0)) { + const newDependencies = await util.getNewDependencies(pkg, pkgPath); + + const noNewUnpublishedFiles = !newFiles.unpublished || newFiles.unpublished.length === 0; + const noNewFirstTimeFiles = !newFiles.firstTime || newFiles.firstTime.length === 0; + const noNewFiles = noNewUnpublishedFiles && noNewFirstTimeFiles; + + const noNewDependencies = !newDependencies || newDependencies.length === 0; + + if (noNewFiles && noNewDependencies) { return true; } const messages = []; if (newFiles.unpublished.length > 0) { - messages.push(`The following new files will not be part of your published package:\n${chalk.reset(newFiles.unpublished.map(path => `- ${path}`).join('\n'))}`); + messages.push(`The following new files will not be part of your published package:\n${util.joinList(newFiles.unpublished)}`); } if (newFiles.firstTime.length > 0) { - messages.push(`The following new files will be published for the first time:\n${chalk.reset(newFiles.firstTime.map(path => `- ${path}`).join('\n'))}`); + messages.push(`The following new files will be published for the first time:\n${util.joinList(newFiles.firstTime)}`); + } + + if (newDependencies.length > 0) { + messages.push(`The following new dependencies will be part of your published package:\n${util.joinList(newDependencies)}`); } if (!isInteractive()) { @@ -109,7 +121,7 @@ const checkNewFiles = async pkg => { return answers.confirm; }; -module.exports = async (options, pkg) => { +module.exports = async (options, {pkg, pkgPath}) => { const oldVersion = pkg.version; const extraBaseUrls = ['gitlab.com']; const repoUrl = pkg.repository && githubUrlFromGit(pkg.repository.url, {extraBaseUrls}); @@ -120,7 +132,7 @@ module.exports = async (options, pkg) => { if (options.runPublish) { checkIgnoreStrategy(pkg); - const answerIgnoredFiles = await checkNewFiles(pkg); + const answerIgnoredFiles = await checkNewFilesAndDependencies(pkg, pkgPath); if (!answerIgnoredFiles) { return { ...options, diff --git a/source/util.js b/source/util.js index 79d329c9..0b683fc6 100644 --- a/source/util.js +++ b/source/util.js @@ -6,6 +6,7 @@ const execa = require('execa'); const pMemoize = require('p-memoize'); const {default: ow} = require('ow'); const pkgDir = require('pkg-dir'); +const chalk = require('chalk'); const gitUtil = require('./git-util'); const npmUtil = require('./npm/util'); @@ -16,11 +17,11 @@ exports.readPkg = packagePath => { throw new Error('No `package.json` found. Make sure the current directory is a valid package.'); } - const {packageJson} = readPkgUp.sync({ + const {packageJson, path} = readPkgUp.sync({ cwd: packagePath }); - return packageJson; + return {pkg: packageJson, pkgPath: path}; }; exports.linkifyIssues = (url, message) => { @@ -71,11 +72,28 @@ exports.getTagVersionPrefix = pMemoize(async options => { } }); +exports.joinList = list => chalk.reset(list.map(item => `- ${item}`).join('\n')); + exports.getNewFiles = async pkg => { const listNewFiles = await gitUtil.newFilesSinceLastRelease(); return {unpublished: await npmUtil.getNewAndUnpublishedFiles(pkg, listNewFiles), firstTime: await npmUtil.getFirstTimePublishedFiles(pkg, listNewFiles)}; }; +exports.getNewDependencies = async (newPkg, pkgPath) => { + let oldPkg = await gitUtil.readFileFromLastRelease(pkgPath); + oldPkg = JSON.parse(oldPkg); + + const newDependencies = []; + + for (const dependency of Object.keys(newPkg.dependencies)) { + if (!oldPkg.dependencies[dependency]) { + newDependencies.push(dependency); + } + } + + return newDependencies; +}; + exports.getPreReleasePrefix = pMemoize(async options => { ow(options, ow.object.hasKeys('yarn'));