Skip to content

Commit

Permalink
feat(publish): Add a "from-package" argument
Browse files Browse the repository at this point in the history
Publish un-published releases by reading versions from
the package.json files and publishing any that are not
already available in the registry.

Fixes lerna#1648
  • Loading branch information
chriscasola committed Oct 16, 2018
1 parent 8e86e1e commit 3761321
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 3 deletions.
2 changes: 1 addition & 1 deletion commands/publish/command.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ exports.handler = function handler(argv) {
};

function composeVersionOptions(yargs) {
versionCommand.addBumpPositional(yargs, ["from-git"]);
versionCommand.addBumpPositional(yargs, ["from-git", "from-package"]);
versionCommand.builder(yargs, "publish");

return yargs;
Expand Down
39 changes: 37 additions & 2 deletions commands/publish/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const versionCommand = require("@lerna/version");
const createTempLicenses = require("./lib/create-temp-licenses");
const getCurrentSHA = require("./lib/get-current-sha");
const getCurrentTags = require("./lib/get-current-tags");
const getUnpublishedPackages = require("./lib/get-unpublished-packages");
const getNpmUsername = require("./lib/get-npm-username");
const getTaggedPackages = require("./lib/get-tagged-packages");
const getPackagesWithoutLicense = require("./lib/get-packages-without-license");
Expand Down Expand Up @@ -133,8 +134,9 @@ class PublishCommand extends Command {
: [this.packagesToPublish];

if (result.needsConfirmation) {
// only confirm for --canary or bump === "from-git",
// as VersionCommand has its own confirmation prompt
// only confirm for --canary, bump === "from-git",
// or bump === "from-package", as VersionCommand
// has its own confirmation prompt
return this.confirmPublish();
}

Expand All @@ -155,6 +157,11 @@ class PublishCommand extends Command {
chain = chain.then(() => this.updateCanaryVersions());
}

// TODO need to create git tags
// if (this.options.bump === "from-package") {

// }

chain = chain.then(() => this.resolveLocalDependencyLinks());
chain = chain.then(() => this.annotateGitHead());
chain = chain.then(() => this.packUpdated());
Expand All @@ -181,6 +188,8 @@ class PublishCommand extends Command {

if (this.options.bump === "from-git") {
chain = chain.then(() => this.detectFromGit());
} else if (this.options.bump === "from-package") {
chain = chain.then(() => this.detectFromPackage());
} else if (this.options.canary) {
chain = chain.then(() => this.detectCanaryVersions());
} else {
Expand Down Expand Up @@ -226,6 +235,32 @@ class PublishCommand extends Command {
});
}

detectFromPackage() {
let chain = Promise.resolve();

// attempting to publish a release with local changes is not allowed
chain = chain.then(() => this.verifyWorkingTreeClean());

chain = chain.then(() => getUnpublishedPackages(this.project, this.conf));
chain = chain.then(unpublishedPackages => {
if (!unpublishedPackages.length) {
this.logger.notice("from-package", "No unpublished release found");
}

return unpublishedPackages;
});

return chain.then(updates => {
const updatesVersions = updates.map(({ pkg }) => [pkg.name, pkg.version]);

return {
updates,
updatesVersions,
needsConfirmation: true,
};
});
}

detectCanaryVersions() {
const {
bump = "prepatch",
Expand Down
41 changes: 41 additions & 0 deletions commands/publish/lib/get-unpublished-packages.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
"use strict";

const fetch = require("npm-registry-fetch");
const log = require("npmlog");
const pReduce = require("p-reduce");

module.exports = getUnpublishedPackages;

// Only the abbreviated package metadata is needed to
// determine which versions have been published. This
// saves transfer time for packages with a lot of
// history.
const registryOptions = {
Accept: "application/vnd.npm.install-v1+json",
};

function getUnpublishedPackages(project, opts) {
log.silly("getPackageVersions");

let chain = Promise.resolve();

const mapper = (unpublished, pkg) =>
fetch(`-/${pkg.name}`, Object.assign({}, opts, registryOptions)).then(
packument => {
if (packument.versions[pkg.version] === undefined) {
unpublished.push(pkg);
}

return unpublished;
},
() => {
log.warn("", "Unable to determine published versions, assuming unpublished.");
return unpublished.concat([pkg]);
}
);

chain = chain.then(() => project.getPackages());
chain = chain.then(packages => pReduce(packages, mapper, []));

return chain;
}

0 comments on commit 3761321

Please sign in to comment.